Avoid segfaults when some display vector is an empty string
[emacs.git] / lisp / textmodes / reftex-parse.el
blobaf2810d72e84b28f7b30b51bb6406262053fa0cd
1 ;;; reftex-parse.el --- parser functions for RefTeX
3 ;; Copyright (C) 1997-2017 Free Software Foundation, Inc.
5 ;; Author: Carsten Dominik <dominik@science.uva.nl>
6 ;; Maintainer: auctex-devel@gnu.org
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation, either version 3 of the License, or
13 ;; (at your option) any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
23 ;;; Commentary:
25 ;;; Code:
27 (eval-when-compile (require 'cl-lib))
29 (require 'reftex)
31 (defmacro reftex-with-special-syntax (&rest body)
32 `(let ((saved-syntax (syntax-table)))
33 (unwind-protect
34 (progn
35 (set-syntax-table reftex-syntax-table)
36 (let ((case-fold-search nil))
37 ,@body))
38 (set-syntax-table saved-syntax))))
40 ;;;###autoload
41 (defun reftex-parse-one ()
42 "Re-parse this file."
43 (interactive)
44 (let ((reftex-enable-partial-scans t))
45 (reftex-access-scan-info '(4))))
47 ;;;###autoload
48 (defun reftex-parse-all ()
49 "Re-parse entire document."
50 (interactive)
51 (reftex-access-scan-info '(16)))
53 (defvar reftex--index-tags)
55 ;;;###autoload
56 (defun reftex-do-parse (rescan &optional file)
57 "Do a document rescan.
58 When allowed, do only a partial scan from FILE."
60 ;; Normalize the rescan argument
61 (setq rescan (cond ((eq rescan t) t)
62 ((eq rescan 1) 1)
63 ((equal rescan '(4)) t)
64 ((equal rescan '(16)) 1)
65 (t 1)))
67 ;; Partial scans only when allowed
68 (unless reftex-enable-partial-scans
69 (setq rescan 1))
71 ;; Do the scanning.
73 (let* ((old-list (symbol-value reftex-docstruct-symbol))
74 (master (reftex-TeX-master-file))
75 (true-master (file-truename master))
76 (master-dir (file-name-as-directory (file-name-directory master)))
77 (file (or file (buffer-file-name)))
78 (true-file (file-truename file))
79 (bibview-cache (assq 'bibview-cache old-list))
80 (reftex--index-tags (cdr (assq 'index-tags old-list)))
81 from-file appendix docstruct tmp)
83 ;; Make sure replacement is really an option here
84 (when (and (eq rescan t)
85 (not (and (member (list 'bof file) old-list)
86 (member (list 'eof file) old-list))))
87 ;; Scan whole document because no such file section exists
88 (setq rescan 1))
89 (when (string= true-file true-master)
90 ;; Scan whole document because this file is the master
91 (setq rescan 1))
93 ;; From which file do we start?
94 (setq from-file
95 (cond ((eq rescan t) (or file master))
96 ((eq rescan 1) master)
97 (t (error "This should not happen (reftex-do-parse)"))))
99 ;; Reset index-tags if we scan everything
100 (if (equal rescan 1) (setq reftex--index-tags nil))
102 ;; Find active toc entry and initialize section-numbers
103 (setq reftex-active-toc (reftex-last-assoc-before-elt
104 'toc (list 'bof from-file) old-list)
105 appendix (reftex-last-assoc-before-elt
106 'appendix (list 'bof from-file) old-list))
108 (reftex-init-section-numbers reftex-active-toc appendix)
110 (if (eq rescan 1)
111 (message "Scanning entire document...")
112 (message "Scanning document from %s..." from-file))
114 (reftex-with-special-syntax
115 (save-window-excursion
116 (save-excursion
117 (unwind-protect
118 (setq docstruct
119 (reftex-parse-from-file
120 from-file docstruct master-dir))
121 (reftex-kill-temporary-buffers)))))
123 (message "Scanning document... done")
125 ;; Turn the list around.
126 (setq docstruct (nreverse docstruct))
128 ;; Set or insert
129 (setq docstruct (reftex-replace-label-list-segment
130 old-list docstruct (eq rescan 1)))
132 ;; Add all missing information
133 (unless (assq 'label-numbers docstruct)
134 (push (cons 'label-numbers nil) docstruct))
135 (unless (assq 'master-dir docstruct)
136 (push (cons 'master-dir master-dir) docstruct))
137 (unless (assq 'bibview-cache docstruct)
138 (push (cons 'bibview-cache (cdr bibview-cache)) docstruct))
139 (let* ((bof1 (memq (assq 'bof docstruct) docstruct))
140 (bof2 (assq 'bof (cdr bof1)))
141 (is-multi (not (not (and bof1 bof2))))
142 (entry (or (assq 'is-multi docstruct)
143 (car (push (list 'is-multi is-multi) docstruct)))))
144 (setcdr entry (cons is-multi nil)))
145 (and reftex--index-tags
146 (setq reftex--index-tags (sort reftex--index-tags 'string<)))
147 (let ((index-tag-cell (assq 'index-tags docstruct)))
148 (if index-tag-cell
149 (setcdr index-tag-cell reftex--index-tags)
150 (push (cons 'index-tags reftex--index-tags) docstruct)))
151 (unless (assq 'xr docstruct)
152 (let* ((allxr (reftex-all-assq 'xr-doc docstruct))
153 (alist (mapcar
154 (lambda (x)
155 (if (setq tmp (reftex-locate-file (nth 2 x) "tex"
156 master-dir))
157 (cons (nth 1 x) tmp)
158 (message "Can't find external document %s"
159 (nth 2 x))
160 nil))
161 allxr))
162 (alist (delq nil alist))
163 (allprefix (delq nil (mapcar 'car alist)))
164 (regexp (if allprefix
165 (concat "\\`\\("
166 (mapconcat 'identity allprefix "\\|")
167 "\\)")
168 "\\\\\\\\\\\\"))) ; this will never match
169 (push (list 'xr alist regexp) docstruct)))
171 (set reftex-docstruct-symbol docstruct)
172 (put reftex-docstruct-symbol 'modified t)))
174 ;;;###autoload
175 (defun reftex-everything-regexp ()
176 (if reftex-support-index
177 reftex-everything-regexp
178 reftex-everything-regexp-no-index))
180 ;; NB this is a global autoload - see reftex.el.
181 ;;;###autoload
182 (defun reftex-all-document-files (&optional relative)
183 "Return a list of all files belonging to the current document.
184 When RELATIVE is non-nil, give file names relative to directory
185 of master file."
186 (let* ((all (symbol-value reftex-docstruct-symbol))
187 (master-dir (file-name-directory (reftex-TeX-master-file)))
188 (re (concat "\\`" (regexp-quote master-dir)))
189 file-list tmp file)
190 (while (setq tmp (assoc 'bof all))
191 (setq file (nth 1 tmp)
192 all (cdr (memq tmp all)))
193 (and relative
194 (string-match re file)
195 (setq file (substring file (match-end 0))))
196 (push file file-list))
197 (nreverse file-list)))
199 ;; Bound in the caller, reftex-do-parse.
200 (defun reftex-parse-from-file (file docstruct master-dir)
201 "Scan the buffer for labels and save them in a list."
202 (let ((regexp (reftex-everything-regexp))
203 (bound 0)
204 file-found tmp include-file
205 (level 1)
206 (highest-level 100)
207 toc-entry index-entry next-buf buf)
209 (catch 'exit
210 (setq file-found (reftex-locate-file file "tex" master-dir))
211 (if (and (not file-found)
212 (setq buf (reftex-get-buffer-visiting file)))
213 (setq file-found (buffer-file-name buf)))
215 (unless file-found
216 (push (list 'file-error file) docstruct)
217 (throw 'exit nil))
219 (save-excursion
221 (message "Scanning file %s" file)
222 (set-buffer
223 (setq next-buf
224 (reftex-get-file-buffer-force
225 file-found
226 (not (eq t reftex-keep-temporary-buffers)))))
228 ;; Begin of file mark
229 (setq file (buffer-file-name))
230 (push (list 'bof file) docstruct)
232 (reftex-with-special-syntax
233 (save-excursion
234 (save-restriction
235 (widen)
236 (goto-char 1)
238 (while (re-search-forward regexp nil t)
240 (cond
242 ((match-end 1)
243 ;; It is a label
244 (when (or (null reftex-label-ignored-macros-and-environments)
245 ;; \label{} defs should always be honored,
246 ;; just no keyval style [label=foo] defs.
247 (string-equal "\\label{" (substring (reftex-match-string 0) 0 7))
248 (if (and (fboundp 'TeX-current-macro)
249 (fboundp 'LaTeX-current-environment))
250 (not (or (member (save-match-data (TeX-current-macro))
251 reftex-label-ignored-macros-and-environments)
252 (member (save-match-data (LaTeX-current-environment))
253 reftex-label-ignored-macros-and-environments)))
255 (push (reftex-label-info (reftex-match-string 1) file bound)
256 docstruct)))
258 ((match-end 3)
259 ;; It is a section
261 ;; Use the beginning as bound and not the end
262 ;; (i.e. (point)) because the section command might
263 ;; be the start of the current environment to be
264 ;; found by `reftex-label-info'.
265 (setq bound (match-beginning 0))
266 ;; The section regexp matches a character at the end
267 ;; we are not interested in. Especially if it is the
268 ;; backslash of a following macro we want to find in
269 ;; the next parsing iteration.
270 (when (eq (char-before) ?\\) (backward-char))
271 ;; Insert in List
272 (setq toc-entry (funcall reftex-section-info-function file))
273 (when (and toc-entry
274 (eq ;; Either both are t or both are nil.
275 (= (char-after bound) ?%)
276 (string-suffix-p ".dtx" file)))
277 ;; It can happen that section info returns nil
278 (setq level (nth 5 toc-entry))
279 (setq highest-level (min highest-level level))
280 (if (= level highest-level)
281 (message
282 "Scanning %s %s ..."
283 (car (rassoc level reftex-section-levels-all))
284 (nth 6 toc-entry)))
286 (push toc-entry docstruct)
287 (setq reftex-active-toc toc-entry)))
289 ((match-end 7)
290 ;; It's an include or input
291 (setq include-file (reftex-match-string 7))
292 ;; Test if this file should be ignored
293 (unless (delq nil (mapcar
294 (lambda (x) (string-match x include-file))
295 reftex-no-include-regexps))
296 ;; Parse it
297 (setq docstruct
298 (reftex-parse-from-file
299 include-file
300 docstruct master-dir))))
302 ((match-end 9)
303 ;; Appendix starts here
304 (reftex-init-section-numbers nil t)
305 (push (cons 'appendix t) docstruct))
307 ((match-end 10)
308 ;; Index entry
309 (when reftex-support-index
310 (setq index-entry (reftex-index-info file))
311 (when index-entry
312 (cl-pushnew (nth 1 index-entry) reftex--index-tags :test #'equal)
313 (push index-entry docstruct))))
315 ((match-end 11)
316 ;; A macro with label
317 (save-excursion
318 (let* ((mac (reftex-match-string 11))
319 (label (progn (goto-char (match-end 11))
320 (save-match-data
321 (reftex-no-props
322 (reftex-nth-arg-wrapper
323 mac)))))
324 (typekey (nth 1 (assoc mac reftex-env-or-mac-alist)))
325 (entry (progn (if typekey
326 ;; A typing macro
327 (goto-char (match-end 0))
328 ;; A neutral macro
329 (goto-char (match-end 11))
330 (reftex-move-over-touching-args))
331 (reftex-label-info
332 label file bound nil nil))))
333 (push entry docstruct))))
334 (t (error "This should not happen (reftex-parse-from-file)")))
337 ;; Find bibliography statement
338 (when (setq tmp (reftex-locate-bibliography-files master-dir))
339 (push (cons 'bib tmp) docstruct))
341 (goto-char 1)
342 (when (re-search-forward
343 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\begin{thebibliography}" nil t)
344 (push (cons 'thebib file) docstruct))
346 ;; Find external document specifications
347 (goto-char 1)
348 (while (re-search-forward "[\n\r][ \t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t)
349 (push (list 'xr-doc (reftex-match-string 2)
350 (reftex-match-string 3))
351 docstruct))
353 ;; End of file mark
354 (push (list 'eof file) docstruct)))))
356 ;; Kill the scanned buffer
357 (reftex-kill-temporary-buffers next-buf))
359 ;; Return the list
360 docstruct))
362 (defun reftex-using-biblatex-p ()
363 "Return non-nil if we are using biblatex rather than bibtex."
364 (if (boundp 'TeX-active-styles)
365 ;; the sophisticated AUCTeX way
366 (member "biblatex" TeX-active-styles)
367 ;; poor-man's check...
368 (save-excursion
369 (re-search-forward "^[^%\n]*?\\\\usepackage.*{biblatex}" nil t))))
371 ;;;###autoload
372 (defun reftex-locate-bibliography-files (master-dir &optional files)
373 "Scan buffer for bibliography macros and return file list."
374 (unless files
375 (save-excursion
376 (goto-char (point-min))
377 ;; when biblatex is used, multiple \bibliography or
378 ;; \addbibresource macros are allowed. With plain bibtex, only
379 ;; the first is used.
380 (let ((using-biblatex (reftex-using-biblatex-p))
381 (again t))
382 (while (and again
383 (re-search-forward
384 (concat
385 ;; "\\(\\`\\|[\n\r]\\)[^%]*\\\\\\("
386 "\\(^\\)[^%\n\r]*\\\\\\("
387 (mapconcat 'identity reftex-bibliography-commands "\\|")
388 "\\)\\(\\[.+?\\]\\)?{[ \t]*\\([^}]+\\)") nil t))
389 (setq files
390 (append files
391 (split-string (reftex-match-string 4)
392 "[ \t\n\r]*,[ \t\n\r]*")))
393 (unless using-biblatex
394 (setq again nil))))))
395 (when files
396 (setq files
397 (mapcar
398 (lambda (x)
399 (if (or (member x reftex-bibfile-ignore-list)
400 (delq nil (mapcar (lambda (re) (string-match re x))
401 reftex-bibfile-ignore-regexps)))
402 ;; excluded file
404 ;; find the file
405 (reftex-locate-file x "bib" master-dir)))
406 files))
407 (delq nil files)))
409 (defun reftex-replace-label-list-segment (old insert &optional entirely)
410 "Replace the segment in OLD which corresponds to INSERT.
411 Works with side effects, directly changes old.
412 If ENTIRELY is t, just return INSERT.
413 This function also makes sure the old toc markers do not point anywhere."
415 (cond
416 (entirely
417 (reftex-silence-toc-markers old (length old))
418 insert)
419 (t (let* ((new old)
420 (file (nth 1 (car insert)))
421 (eof-list (member (list 'eof file) old))
422 (bof-list (member (list 'bof file) old))
424 (if (not (and bof-list eof-list))
425 (error "Cannot splice")
426 ;; Splice
427 (reftex-silence-toc-markers bof-list (- (length bof-list)
428 (length eof-list)))
429 (setq n (- (length old) (length bof-list)))
430 (setcdr (nthcdr n new) (cdr insert))
431 (setcdr (nthcdr (1- (length new)) new) (cdr eof-list)))
432 new))))
434 ;;;###autoload
435 (defun reftex-section-info (file)
436 "Return a section entry for the current match.
437 Careful: This function expects the match-data to be still in place!"
438 (let* ((marker (set-marker (make-marker) (1- (match-beginning 3))))
439 (macro (reftex-match-string 3))
440 (prefix (save-match-data
441 (if (string-match "begin{\\([^}]+\\)}" macro)
442 (match-string 1 macro))))
443 (level-exp (cdr (assoc macro reftex-section-levels-all)))
444 (level (if (symbolp level-exp)
445 (save-match-data (funcall level-exp))
446 level-exp))
447 (star (= ?* (char-after (match-end 3))))
448 (unnumbered (or star (< level 0)))
449 (level (abs level))
450 (section-number (reftex-section-number level unnumbered))
451 (text1 (save-match-data
452 (save-excursion
453 (reftex-context-substring prefix))))
454 (literal (buffer-substring-no-properties
455 (1- (match-beginning 3))
456 (min (point-max) (+ (match-end 0) (length text1) 1))))
457 ;; Literal can be too short since text1 too short. No big problem.
458 (text (reftex-nicify-text text1)))
460 ;; Add section number and indentation
461 (setq text
462 (concat
463 (make-string (* reftex-level-indent level) ?\ )
464 (if (nth 1 reftex-label-menu-flags) ; section number flag
465 (concat section-number " "))
466 (if prefix (concat (capitalize prefix) ": ") "")
467 text))
468 (list 'toc "toc" text file marker level section-number
469 literal (marker-position marker))))
471 ;;;###autoload
472 (defun reftex-ensure-index-support (&optional abort)
473 "When index support is turned off, ask to turn it on and
474 set the current prefix argument so that `reftex-access-scan-info'
475 will rescan the entire document."
476 (cond
477 (reftex-support-index t)
478 ((y-or-n-p "Turn on index support and rescan entire document? ")
479 (setq reftex-support-index 'demanded
480 current-prefix-arg '(16)))
481 (t (if abort
482 (error "No index support")
483 (message "No index support")
484 (ding)
485 (sit-for 1)))))
487 ;;;###autoload
488 (defun reftex-index-info-safe (file)
489 (reftex-with-special-syntax
490 (reftex-index-info file)))
492 (defvar test-dummy)
493 ;;;###autoload
494 (defun reftex-index-info (file)
495 "Return an index entry for the current match.
496 Careful: This function expects the match-data to be still in place!"
497 (catch 'exit
498 (let* ((macro (reftex-match-string 10))
499 (bom (match-beginning 10))
500 (boa (match-end 10))
501 (entry (or (assoc macro reftex-index-macro-alist)
502 (throw 'exit nil)))
503 (exclude (nth 3 entry))
504 ;; The following is a test if this match should be excluded
505 (test-dummy (and (fboundp exclude)
506 (funcall exclude)
507 (throw 'exit nil)))
508 (itag (nth 1 entry))
509 (prefix (nth 2 entry))
510 (index-tag
511 (cond ((stringp itag) itag)
512 ((integerp itag)
513 (progn (goto-char boa)
514 (or (reftex-nth-arg itag (nth 6 entry)) "idx")))
515 (t "idx")))
516 (arg (or (progn (goto-char boa)
517 (reftex-nth-arg (nth 5 entry) (nth 6 entry)))
518 ""))
519 (end-of-args (progn (goto-char boa)
520 (reftex-move-over-touching-args)
521 (point)))
522 (end-of-context (progn (skip-chars-forward "^ \t\n\r") (point)))
523 (begin-of-context
524 (progn (goto-char bom)
525 (skip-chars-backward "^ \t\r\n")
526 (point)))
527 (context (buffer-substring-no-properties
528 begin-of-context end-of-context))
529 (key-end (if (string-match reftex-index-key-end-re arg)
530 (1+ (match-beginning 0))))
531 (rawkey (substring arg 0 key-end))
533 (key (if prefix (concat prefix rawkey) rawkey))
534 (sortkey (downcase key))
535 (showkey (mapconcat 'identity
536 (split-string key reftex-index-level-re)
537 " ! ")))
538 (goto-char end-of-args)
539 ;; 0 1 2 3 4 5 6 7 8 9
540 (list 'index index-tag context file bom arg key showkey sortkey key-end))))
542 ;;;###autoload
543 (defun reftex-short-context (env parse &optional bound derive)
544 "Get about one line of useful context for the label definition at point."
546 (if (consp parse)
547 (setq parse (if derive (cdr parse) (car parse))))
549 (reftex-nicify-text
551 (cond
553 ((null parse)
554 (save-excursion
555 (reftex-context-substring)))
557 ((eq parse t)
558 (if (string= env "section")
559 ;; special treatment for section labels
560 (save-excursion
561 (if (and (re-search-backward reftex-section-or-include-regexp
562 (point-min) t)
563 (match-end 2))
564 (progn
565 (goto-char (match-end 0))
566 (reftex-context-substring))
567 (if reftex-active-toc
568 (progn
569 (string-match "{\\([^}]*\\)" (nth 7 reftex-active-toc))
570 (match-string 1 (nth 7 reftex-active-toc)))
571 "SECTION HEADING NOT FOUND")))
572 (save-excursion
573 (goto-char reftex-default-context-position)
574 (unless (eq (string-to-char env) ?\\)
575 (reftex-move-over-touching-args))
576 (reftex-context-substring))))
578 ((stringp parse)
579 (save-excursion
580 (if (re-search-backward parse bound t)
581 (progn
582 (goto-char (match-end 0))
583 (reftex-context-substring))
584 "NO MATCH FOR CONTEXT REGEXP")))
586 ((integerp parse)
587 (or (save-excursion
588 (goto-char reftex-default-context-position)
589 (reftex-nth-arg
590 parse
591 (nth 6 (assoc env reftex-env-or-mac-alist))))
592 ""))
594 ((fboundp parse)
595 ;; A hook function. Call it.
596 (save-excursion
597 (condition-case error-var
598 (funcall parse env)
599 (error (format "HOOK ERROR: %s" (cdr error-var))))))
601 "INVALID VALUE OF PARSE"))))
603 ;;;###autoload
604 (defun reftex-where-am-I ()
605 "Return the docstruct entry above point.
606 Actually returns a cons cell in which the cdr is a flag indicating
607 if the information is exact (t) or approximate (nil)."
609 (let ((docstruct (symbol-value reftex-docstruct-symbol))
610 (cnt 0) rtn rtn-if-no-other
611 found)
612 (save-excursion
613 (while (not rtn)
614 (cl-incf cnt)
615 (setq found (re-search-backward (reftex-everything-regexp) nil t))
616 (setq rtn
617 (cond
618 ((not found)
619 ;; no match
621 (car (member (list 'bof (buffer-file-name)) docstruct))
622 (not (setq cnt 2))
623 (assq 'bof docstruct) ;; for safety reasons
624 'corrupted))
625 ((match-end 1)
626 ;; Label
627 (assoc (reftex-match-string 1)
628 (symbol-value reftex-docstruct-symbol)))
629 ((match-end 3)
630 ;; Section
631 (goto-char (1- (match-beginning 3)))
632 (let* ((list (member (list 'bof (buffer-file-name))
633 docstruct))
634 (endelt (car (member (list 'eof (buffer-file-name))
635 list)))
636 rtn1)
637 (while (and list (not (eq endelt (car list))))
638 (if (and (eq (car (car list)) 'toc)
639 (string= (buffer-file-name)
640 (nth 3 (car list))))
641 (cond
642 ((equal (point)
643 (or (and (markerp (nth 4 (car list)))
644 (marker-position (nth 4 (car list))))
645 (nth 8 (car list))))
646 ;; Fits with marker position or recorded position
647 (setq rtn1 (car list) list nil))
648 ((looking-at (reftex-make-regexp-allow-for-ctrl-m
649 (nth 7 (car list))))
650 ;; Same title: remember, but keep looking
651 (setq rtn-if-no-other (car list)))))
652 (pop list))
653 rtn1))
654 ((match-end 7)
655 ;; Input or include...
656 (car
657 (member (list 'eof (reftex-locate-file
658 (reftex-match-string 7) "tex"
659 (cdr (assq 'master-dir docstruct))))
660 docstruct)))
661 ((match-end 9)
662 (assq 'appendix (symbol-value reftex-docstruct-symbol)))
663 ((match-end 10)
664 ;; Index entry
665 (when reftex-support-index
666 (let* ((index-info (save-excursion
667 (reftex-index-info-safe nil)))
668 (list (member (list 'bof (buffer-file-name))
669 docstruct))
670 (endelt (car (member (list 'eof (buffer-file-name))
671 list)))
672 dist last-dist last (n 0))
673 ;; Check all index entries with equal text
674 (while (and list (not (eq endelt (car list))))
675 (when (and (eq (car (car list)) 'index)
676 (string= (nth 2 index-info)
677 (nth 2 (car list))))
678 (cl-incf n)
679 (setq dist (abs (- (point) (nth 4 (car list)))))
680 (if (or (not last-dist) (< dist last-dist))
681 (setq last-dist dist last (car list))))
682 (setq list (cdr list)))
683 ;; We are sure if we have only one, or a zero distance
684 (cond ((or (= n 1) (equal dist 0)) last)
685 ((> n 1) (setq cnt 2) last)
686 (t nil)))))
687 ((match-end 11)
688 (save-excursion
689 (goto-char (match-end 11))
690 (assoc (reftex-no-props
691 (reftex-nth-arg-wrapper
692 (reftex-match-string 11)))
693 (symbol-value reftex-docstruct-symbol))))
695 (error "This should not happen (reftex-where-am-I)"))))))
696 ;; Check if there was only a by-name match for the section.
697 (when (and (not rtn) rtn-if-no-other)
698 (setq rtn rtn-if-no-other
699 cnt 2))
700 (cons rtn (eq cnt 1))))
702 ;;;###autoload
703 (defun reftex-notice-new (&optional n force)
704 "Hook to handshake with RefTeX after something new has been inserted."
705 ;; Add a new entry to the docstruct list. If it is a section, renumber
706 ;; the following sections.
707 ;; FIXME: Put in a WHAT parameter and search backward until one is found.
708 ;; When N is given, go back that many matches of reftex-everything-regexp
709 ;; When FORCE is non-nil, also insert if `reftex-where-am-I' was uncertain.
710 (condition-case nil
711 (catch 'exit
712 (unless reftex-mode (throw 'exit nil))
713 (reftex-access-scan-info)
714 (let* ((docstruct (symbol-value reftex-docstruct-symbol))
715 here-I-am appendix tail entry star level
716 section-number context)
718 (save-excursion
719 (when (re-search-backward (reftex-everything-regexp) nil t (or n 1))
721 ;; Find where we are
722 (setq here-I-am (reftex-where-am-I))
723 (or here-I-am (throw 'exit nil))
724 (unless (or force (cdr here-I-am)) (throw 'exit nil))
725 (setq tail (memq (car here-I-am) docstruct))
726 (or tail (throw 'exit nil))
727 (setq reftex-active-toc (reftex-last-assoc-before-elt
728 'toc (car here-I-am) docstruct)
729 appendix (reftex-last-assoc-before-elt
730 'appendix (car here-I-am) docstruct))
732 ;; Initialize section numbers
733 (if (eq (car (car here-I-am)) 'appendix)
734 (reftex-init-section-numbers nil t)
735 (reftex-init-section-numbers reftex-active-toc appendix))
737 ;; Match the section command
738 (when (re-search-forward (reftex-everything-regexp) nil t)
739 (cond
740 ((match-end 1)
741 (push (reftex-label-info (reftex-match-string 1) buffer-file-name)
742 (cdr tail)))
744 ((match-end 3)
745 (setq star (= ?* (char-after (match-end 3)))
746 entry (reftex-section-info (buffer-file-name))
747 level (nth 5 entry))
748 ;; Insert the section info
749 (push entry (cdr tail))
751 ;; We are done unless we use section numbers
752 (unless (nth 1 reftex-label-menu-flags) (throw 'exit nil))
754 ;; Update the remaining toc items
755 (setq tail (cdr tail))
756 (while (and (setq tail (memq (assq 'toc (cdr tail)) tail))
757 (setq entry (car tail))
758 (>= (nth 5 entry) level))
759 (setq star (string-match "\\*" (nth 6 entry))
760 context (nth 2 entry)
761 section-number
762 (reftex-section-number (nth 5 entry) star))
763 (when (string-match "\\`\\([ \t]*\\)\\([.0-9A-Z]+\\)\\(.*\\)"
764 context)
765 (when (and (not appendix)
766 (>= (string-to-char (match-string 2)) ?A))
767 ;; Just entered the appendix. Get out.
768 (throw 'exit nil))
770 ;; Change the section number.
771 (setf (nth 2 entry)
772 (concat (match-string 1 context)
773 section-number
774 (match-string 3 context))))))
775 ((match-end 10)
776 ;; Index entry
777 (and reftex-support-index
778 (setq entry (reftex-index-info-safe buffer-file-name))
779 ;; FIXME: (add-to-list 'reftex--index-tags (nth 1 index-entry))
780 (push entry (cdr tail))))))))))
782 (error nil))
785 (defsubst reftex-move-to-previous-arg (&optional bound)
786 "Assuming that we are in front of a macro argument,
787 move backward to the closing parenthesis of the previous argument.
788 This function understands the splitting of macros over several lines
789 in TeX."
790 (cond
791 ;; Just to be quick:
792 ((memq (preceding-char) '(?\] ?\})))
793 ;; Do a search
794 ((and reftex-allow-detached-macro-args
795 (re-search-backward
796 "[]}][ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*\\=" bound t))
797 (goto-char (1+ (match-beginning 0)))
799 (t nil)))
801 ;;;###autoload
802 (defun reftex-what-macro-safe (which &optional bound)
803 "Call `reftex-what-macro' with special syntax table."
804 (reftex-with-special-syntax
805 (reftex-what-macro which bound)))
807 ;;;###autoload
808 (defun reftex-what-macro (which &optional bound)
809 "Find out if point is within the arguments of any TeX-macro.
810 The return value is either (\"\\macro\" . (point)) or a list of them.
812 If WHICH is nil, immediately return nil.
813 If WHICH is 1, return innermost enclosing macro.
814 If WHICH is t, return list of all macros enclosing point.
815 If WHICH is a list of macros, look only for those macros and return the
816 name of the first macro in this list found to enclose point.
817 If the optional BOUND is an integer, bound backwards directed
818 searches to this point. If it is nil, limit to nearest \\section -
819 like statement.
821 This function is pretty stable, but can be fooled if the text contains
822 things like \\macro{aa}{bb} where \\macro is defined to take only one
823 argument. As RefTeX cannot know this, the string \"bb\" would still be
824 considered an argument of macro \\macro."
825 (unless reftex-section-regexp (reftex-compile-variables))
826 (catch 'exit
827 (if (null which) (throw 'exit nil))
828 (let ((bound (or bound (save-excursion (re-search-backward
829 reftex-section-regexp nil 1)
830 (point))))
831 pos cmd-list cmd cnt cnt-opt entry)
832 (save-restriction
833 (save-excursion
834 (narrow-to-region (max (point-min) bound) (point-max))
835 ;; move back out of the current parenthesis
836 (while (condition-case nil
837 (let ((forward-sexp-function nil))
838 (up-list -1) t)
839 (error nil))
840 (setq cnt 1 cnt-opt 0)
841 ;; move back over any touching sexps
842 (while (and (reftex-move-to-previous-arg bound)
843 (condition-case nil
844 (let ((forward-sexp-function nil))
845 (backward-sexp) t)
846 (error nil)))
847 (if (eq (following-char) ?\[) (cl-incf cnt-opt))
848 (cl-incf cnt))
849 (setq pos (point))
850 (when (and (or (= (following-char) ?\[)
851 (= (following-char) ?\{))
852 (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t))
853 (setq cmd (reftex-match-string 0))
854 (when (looking-at "\\\\begin{[^}]*}")
855 (setq cmd (reftex-match-string 0)
856 cnt (1- cnt)))
857 ;; This does ignore optional arguments. Very hard to fix.
858 (when (setq entry (assoc cmd reftex-env-or-mac-alist))
859 (if (> cnt (or (nth 4 entry) 100))
860 (setq cmd nil)))
861 (cond
862 ((null cmd))
863 ((eq t which)
864 (push (cons cmd (point)) cmd-list))
865 ((or (eq 1 which) (member cmd which))
866 (throw 'exit (cons cmd (point))))))
867 (goto-char pos)))
868 (nreverse cmd-list)))))
870 ;;;###autoload
871 (defun reftex-what-environment (which &optional bound)
872 "Find out if point is inside a LaTeX environment.
873 The return value is (e.g.) either (\"equation\" . (point)) or a list of
874 them.
876 If WHICH is nil, immediately return nil.
877 If WHICH is 1, return innermost enclosing environment.
878 If WHICH is t, return list of all environments enclosing point.
879 If WHICH is a list of environments, look only for those environments and
880 return the name of the first environment in this list found to enclose
881 point.
883 If the optional BOUND is an integer, bound backwards directed searches to
884 this point. If it is nil, limit to nearest \\section - like statement."
885 (unless reftex-section-regexp (reftex-compile-variables))
886 (catch 'exit
887 (save-excursion
888 (if (null which) (throw 'exit nil))
889 (let ((bound (or bound (save-excursion (re-search-backward
890 reftex-section-regexp nil 1)
891 (point))))
892 env-list end-list env)
893 (while (re-search-backward "\\\\\\(begin\\|end\\){\\([^}]+\\)}"
894 bound t)
895 (setq env (buffer-substring-no-properties
896 (match-beginning 2) (match-end 2)))
897 (cond
898 ((string= (match-string 1) "end")
899 (push env end-list))
900 ((equal env (car end-list))
901 (setq end-list (cdr end-list)))
902 ((eq t which)
903 (push (cons env (point)) env-list))
904 ((or (eq 1 which) (member env which))
905 (throw 'exit (cons env (point))))))
906 (nreverse env-list)))))
908 ;;;###autoload
909 (defun reftex-what-special-env (which &optional bound)
910 "Run the special environment parsers and return the matches.
912 The return value is (e.g.) either (\"my-parser-function\" . (point))
913 or a list of them.
915 If WHICH is nil, immediately return nil.
916 If WHICH is 1, return innermost enclosing environment.
917 If WHICH is t, return list of all environments enclosing point.
918 If WHICH is a list of environments, look only for those environments and
919 return the name of the first environment in this list found to enclose
920 point."
921 (unless reftex-section-regexp (reftex-compile-variables))
922 (catch 'exit
923 (save-excursion
924 (if (null reftex-special-env-parsers) (throw 'exit nil))
925 (if (null which) (throw 'exit nil))
926 (let ((bound (or bound (save-excursion (re-search-backward
927 reftex-section-regexp nil 1)
928 (point))))
929 (fun-list (if (listp which)
930 (mapcar (lambda (x) (if (memq x which) x nil))
931 reftex-special-env-parsers)
932 reftex-special-env-parsers))
933 specials rtn)
934 ;; Call all functions
935 (setq specials (mapcar
936 (lambda (fun)
937 (save-excursion
938 (setq rtn (and fun (funcall fun bound)))
939 (if rtn (cons (symbol-name fun) rtn) nil)))
940 fun-list))
941 ;; Delete the non-matches
942 (setq specials (delq nil specials))
943 ;; Sort
944 (setq specials (sort specials (lambda (a b) (> (cdr a) (cdr b)))))
945 (if (eq which t)
946 specials
947 (car specials))))))
949 (defsubst reftex-move-to-next-arg (&optional _ignore)
950 "Assuming that we are at the end of a macro name or a macro argument,
951 move forward to the opening parenthesis of the next argument.
952 This function understands the splitting of macros over several lines
953 in TeX."
954 (cond
955 ;; Just to be quick:
956 ((memq (following-char) '(?\[ ?\{)))
957 ;; Do a search
958 ((and reftex-allow-detached-macro-args
959 (looking-at "[ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*[[{]"))
960 (goto-char (1- (match-end 0)))
962 (t nil)))
964 (defun reftex-nth-arg-wrapper (key)
965 (let ((entry (assoc key reftex-env-or-mac-alist)))
966 (reftex-nth-arg (nth 5 entry) (nth 6 entry))))
968 ;;;###autoload
969 (defun reftex-nth-arg (n &optional opt-args)
970 "Return the Nth following {} or [] parentheses content.
971 OPT-ARGS is a list of argument numbers which are optional."
973 ;; If we are sitting at a macro start, skip to end of macro name.
974 (and (eq (following-char) ?\\) (skip-chars-forward "a-zA-Z*\\\\"))
976 (if (= n 1000)
977 ;; Special case: Skip all touching arguments
978 (progn
979 (reftex-move-over-touching-args)
980 (reftex-context-substring))
982 ;; Do the real thing.
983 (let ((cnt 1))
985 (when (reftex-move-to-next-arg)
987 (while (< cnt n)
988 (while (and (member cnt opt-args)
989 (eq (following-char) ?\{))
990 (cl-incf cnt))
991 (when (< cnt n)
992 (unless (and (condition-case nil
993 (or (forward-list 1) t)
994 (error nil))
995 (reftex-move-to-next-arg)
996 (cl-incf cnt))
997 (setq cnt 1000))))
999 (while (and (memq cnt opt-args)
1000 (eq (following-char) ?\{))
1001 (cl-incf cnt)))
1002 (if (and (= n cnt)
1003 (> (skip-chars-forward "{\\[") 0))
1004 (reftex-context-substring)
1005 nil))))
1007 ;;;###autoload
1008 (defun reftex-move-over-touching-args ()
1009 (condition-case nil
1010 (while (memq (following-char) '(?\[ ?\{))
1011 (forward-list 1))
1012 (error nil)))
1014 (defun reftex-context-substring (&optional to-end)
1015 "Return up to 150 chars from point.
1016 When point is just after a { or [, limit string to matching parenthesis"
1017 (cond
1018 (to-end
1019 ;; Environment - find next \end
1020 (buffer-substring-no-properties
1021 (point)
1022 (min (+ (point) 150)
1023 (save-match-data
1024 ;; FIXME: This is not perfect
1025 (if (re-search-forward "\\\\end{" nil t)
1026 (match-beginning 0)
1027 (point-max))))))
1028 ((memq (preceding-char) '(?\{ ?\[))
1029 ;; Inside a list - get only the list.
1030 (buffer-substring-no-properties
1031 (point)
1032 (min (+ (point) 150)
1033 (point-max)
1034 (condition-case nil
1035 (let ((forward-sexp-function nil)) ;Unneeded fanciness.
1036 (up-list 1)
1037 (1- (point)))
1038 (error (point-max))))))
1040 ;; no list - just grab 150 characters
1041 (buffer-substring-no-properties (point)
1042 (min (+ (point) 150) (point-max))))))
1044 ;; Variable holding the vector with section numbers
1045 (defvar reftex-section-numbers (make-vector reftex-max-section-depth 0))
1047 ;;;###autoload
1048 (defun reftex-init-section-numbers (&optional toc-entry appendix)
1049 "Initialize the section numbers with zeros or with what is found in the TOC-ENTRY."
1050 (let* ((level (or (nth 5 toc-entry) -1))
1051 (numbers (nreverse (split-string (or (nth 6 toc-entry) "") "\\.")))
1052 (depth (1- (length reftex-section-numbers)))
1053 (i depth) number-string)
1054 (while (>= i 0)
1055 (if (> i level)
1056 (aset reftex-section-numbers i 0)
1057 (setq number-string (or (car numbers) "0"))
1058 (if (string-match "\\`[A-Z]\\'" number-string)
1059 (aset reftex-section-numbers i
1060 (- (string-to-char number-string) ?A -1))
1061 (aset reftex-section-numbers i (string-to-number number-string)))
1062 (pop numbers))
1063 (cl-decf i)))
1064 (put 'reftex-section-numbers 'appendix appendix))
1066 ;;;###autoload
1067 (defun reftex-section-number (&optional level star)
1068 "Return a string with the current section number.
1069 When LEVEL is non-nil, increase section numbers on that level."
1070 (let* ((depth (1- (length reftex-section-numbers))) idx n (string "")
1071 (appendix (get 'reftex-section-numbers 'appendix))
1072 (partspecial (and (not reftex-part-resets-chapter)
1073 (equal level 0))))
1074 ;; partspecial means, this is a part statement.
1075 ;; Parts do not reset the chapter counter, and the part number is
1076 ;; not included in the numbering of other sectioning levels.
1077 (when level
1078 (when (and (> level -1) (not star))
1079 (aset reftex-section-numbers
1080 level (1+ (aref reftex-section-numbers level))))
1081 (setq idx (1+ level))
1082 (when (not star)
1083 (while (<= idx depth)
1084 (if (or (not partspecial)
1085 (not (= idx 1)))
1086 (aset reftex-section-numbers idx 0))
1087 (cl-incf idx))))
1088 (if partspecial
1089 (setq string (concat "Part " (reftex-roman-number
1090 (aref reftex-section-numbers 0))))
1091 (setq idx (if reftex-part-resets-chapter 0 1))
1092 (while (<= idx depth)
1093 (setq n (aref reftex-section-numbers idx))
1094 (if (not (and partspecial (not (equal string ""))))
1095 (setq string (concat string (if (not (string= string "")) "." "")
1096 (int-to-string n))))
1097 (cl-incf idx))
1098 (save-match-data
1099 (if (string-match "\\`\\([@0]\\.\\)+" string)
1100 (setq string (replace-match "" nil nil string)))
1101 (if (string-match "\\(\\.0\\)+\\'" string)
1102 (setq string (replace-match "" nil nil string)))
1103 (if (and appendix
1104 (string-match "\\`[0-9]+" string))
1105 (setq string
1106 (concat
1107 (char-to-string
1108 (1- (+ ?A (string-to-number (match-string 0 string)))))
1109 (substring string (match-end 0))))))
1110 (if star
1111 (concat (make-string (1- (length string)) ?\ ) "*")
1112 string))))
1114 (defun reftex-roman-number (n)
1115 "Return as a string the roman number equal to N."
1116 (let ((nrest n)
1117 (string "")
1118 (list '((1000 . "M") ( 900 . "CM") ( 500 . "D") ( 400 . "CD")
1119 ( 100 . "C") ( 90 . "XC") ( 50 . "L") ( 40 . "XL")
1120 ( 10 . "X") ( 9 . "IX") ( 5 . "V") ( 4 . "IV")
1121 ( 1 . "I")))
1122 listel i s)
1123 (while (>= nrest 1)
1124 (setq listel (pop list)
1125 i (car listel)
1126 s (cdr listel))
1127 (while (>= nrest i)
1128 (setq string (concat string s)
1129 nrest (- nrest i))))
1130 string))
1132 (provide 'reftex-parse)
1134 ;;; reftex-parse.el ends here
1136 ;; Local Variables:
1137 ;; generated-autoload-file: "reftex-loaddefs.el"
1138 ;; End: