1 ;;; reftex-parse.el --- parser functions for RefTeX
3 ;; Copyright (C) 1997-2013 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/>.
27 (eval-when-compile (require 'cl))
31 (defmacro reftex-with-special-syntax (&rest body)
32 `(let ((saved-syntax (syntax-table)))
35 (set-syntax-table reftex-syntax-table)
36 (let ((case-fold-search nil))
38 (set-syntax-table saved-syntax))))
40 (defun reftex-parse-one ()
43 (let ((reftex-enable-partial-scans t))
44 (reftex-access-scan-info '(4))))
46 (defun reftex-parse-all ()
47 "Re-parse entire document."
49 (reftex-access-scan-info '(16)))
51 (defun reftex-do-parse (rescan &optional file)
52 "Do a document rescan. When allowed, do only a partial scan from FILE."
54 ;; Normalize the rescan argument
55 (setq rescan (cond ((eq rescan t) t)
57 ((equal rescan '(4)) t)
58 ((equal rescan '(16)) 1)
61 ;; Partial scans only when allowed
62 (unless reftex-enable-partial-scans
67 (let* ((old-list (symbol-value reftex-docstruct-symbol))
68 (master (reftex-TeX-master-file))
69 (true-master (file-truename master))
70 (master-dir (file-name-as-directory (file-name-directory master)))
71 (file (or file (buffer-file-name)))
72 (true-file (file-truename file))
73 (bibview-cache (assq 'bibview-cache old-list))
74 (index-tags (cdr (assq 'index-tags old-list)))
75 from-file appendix docstruct tmp)
77 ;; Make sure replacement is really an option here
78 (when (and (eq rescan t)
79 (not (and (member (list 'bof file) old-list)
80 (member (list 'eof file) old-list))))
81 ;; Scan whole document because no such file section exists
83 (when (string= true-file true-master)
84 ;; Scan whole document because this file is the master
87 ;; From which file do we start?
89 (cond ((eq rescan t) (or file master))
90 ((eq rescan 1) master)
91 (t (error "This should not happen (reftex-do-parse)"))))
93 ;; Reset index-tags if we scan everything
94 (if (equal rescan 1) (setq index-tags nil))
96 ;; Find active toc entry and initialize section-numbers
97 (setq reftex-active-toc (reftex-last-assoc-before-elt
98 'toc (list 'bof from-file) old-list)
99 appendix (reftex-last-assoc-before-elt
100 'appendix (list 'bof from-file) old-list))
102 (reftex-init-section-numbers reftex-active-toc appendix)
105 (message "Scanning entire document...")
106 (message "Scanning document from %s..." from-file))
108 (reftex-with-special-syntax
109 (save-window-excursion
113 (reftex-parse-from-file
114 from-file docstruct master-dir))
115 (reftex-kill-temporary-buffers)))))
117 (message "Scanning document... done")
119 ;; Turn the list around.
120 (setq docstruct (nreverse docstruct))
123 (setq docstruct (reftex-replace-label-list-segment
124 old-list docstruct (eq rescan 1)))
126 ;; Add all missing information
127 (unless (assq 'label-numbers docstruct)
128 (push (cons 'label-numbers nil) docstruct))
129 (unless (assq 'master-dir docstruct)
130 (push (cons 'master-dir master-dir) docstruct))
131 (unless (assq 'bibview-cache docstruct)
132 (push (cons 'bibview-cache (cdr bibview-cache)) docstruct))
133 (let* ((bof1 (memq (assq 'bof docstruct) docstruct))
134 (bof2 (assq 'bof (cdr bof1)))
135 (is-multi (not (not (and bof1 bof2))))
136 (entry (or (assq 'is-multi docstruct)
137 (car (push (list 'is-multi is-multi) docstruct)))))
138 (setcdr entry (cons is-multi nil)))
139 (and index-tags (setq index-tags (sort index-tags 'string<)))
140 (let ((index-tag-cell (assq 'index-tags docstruct)))
142 (setcdr index-tag-cell index-tags)
143 (push (cons 'index-tags index-tags) docstruct)))
144 (unless (assq 'xr docstruct)
145 (let* ((allxr (reftex-all-assq 'xr-doc docstruct))
148 (if (setq tmp (reftex-locate-file (nth 2 x) "tex"
151 (message "Can't find external document %s"
155 (alist (delq nil alist))
156 (allprefix (delq nil (mapcar 'car alist)))
157 (regexp (if allprefix
159 (mapconcat 'identity allprefix "\\|")
161 "\\\\\\\\\\\\"))) ; this will never match
162 (push (list 'xr alist regexp) docstruct)))
164 (set reftex-docstruct-symbol docstruct)
165 (put reftex-docstruct-symbol 'modified t)))
167 (defun reftex-everything-regexp ()
168 (if reftex-support-index
169 reftex-everything-regexp
170 reftex-everything-regexp-no-index))
173 (defun reftex-all-document-files (&optional relative)
174 "Return a list of all files belonging to the current document.
175 When RELATIVE is non-nil, give file names relative to directory
177 (let* ((all (symbol-value reftex-docstruct-symbol))
178 (master-dir (file-name-directory (reftex-TeX-master-file)))
179 (re (concat "\\`" (regexp-quote master-dir)))
181 (while (setq tmp (assoc 'bof all))
182 (setq file (nth 1 tmp)
183 all (cdr (memq tmp all)))
185 (string-match re file)
186 (setq file (substring file (match-end 0))))
187 (push file file-list))
188 (nreverse file-list)))
190 ;; Bound in the caller, reftex-do-parse.
193 (defun reftex-parse-from-file (file docstruct master-dir)
194 ;; Scan the buffer for labels and save them in a list.
195 (let ((regexp (reftex-everything-regexp))
197 file-found tmp include-file
200 toc-entry index-entry next-buf buf)
203 (setq file-found (reftex-locate-file file "tex" master-dir))
204 (if (and (not file-found)
205 (setq buf (reftex-get-buffer-visiting file)))
206 (setq file-found (buffer-file-name buf)))
209 (push (list 'file-error file) docstruct)
214 (message "Scanning file %s" file)
217 (reftex-get-file-buffer-force
219 (not (eq t reftex-keep-temporary-buffers)))))
221 ;; Begin of file mark
222 (setq file (buffer-file-name))
223 (push (list 'bof file) docstruct)
225 (reftex-with-special-syntax
231 (while (re-search-forward regexp nil t)
237 (push (reftex-label-info (reftex-match-string 1) file bound)
243 ;; Use the beginning as bound and not the end
244 ;; (i.e. (point)) because the section command might
245 ;; be the start of the current environment to be
246 ;; found by `reftex-label-info'.
247 (setq bound (match-beginning 0))
248 ;; The section regexp matches a character at the end
249 ;; we are not interested in. Especially if it is the
250 ;; backslash of a following macro we want to find in
251 ;; the next parsing iteration.
252 (when (eq (char-before) ?\\) (backward-char))
254 (setq toc-entry (funcall reftex-section-info-function file))
256 ;; It can happen that section info returns nil
257 (setq level (nth 5 toc-entry))
258 (setq highest-level (min highest-level level))
259 (if (= level highest-level)
262 (car (rassoc level reftex-section-levels-all))
265 (push toc-entry docstruct)
266 (setq reftex-active-toc toc-entry)))
269 ;; It's an include or input
270 (setq include-file (reftex-match-string 7))
271 ;; Test if this file should be ignored
272 (unless (delq nil (mapcar
273 (lambda (x) (string-match x include-file))
274 reftex-no-include-regexps))
277 (reftex-parse-from-file
279 docstruct master-dir))))
282 ;; Appendix starts here
283 (reftex-init-section-numbers nil t)
284 (push (cons 'appendix t) docstruct))
288 (when reftex-support-index
289 (setq index-entry (reftex-index-info file))
291 (add-to-list 'index-tags (nth 1 index-entry))
292 (push index-entry docstruct))))
295 ;; A macro with label
297 (let* ((mac (reftex-match-string 11))
298 (label (progn (goto-char (match-end 11))
301 (reftex-nth-arg-wrapper
303 (typekey (nth 1 (assoc mac reftex-env-or-mac-alist)))
304 (entry (progn (if typekey
306 (goto-char (match-end 0))
308 (goto-char (match-end 11))
309 (reftex-move-over-touching-args))
311 label file bound nil nil))))
312 (push entry docstruct))))
313 (t (error "This should not happen (reftex-parse-from-file)")))
316 ;; Find bibliography statement
317 (when (setq tmp (reftex-locate-bibliography-files master-dir))
318 (push (cons 'bib tmp) docstruct))
321 (when (re-search-forward
322 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\begin{thebibliography}" nil t)
323 (push (cons 'thebib file) docstruct))
325 ;; Find external document specifications
327 (while (re-search-forward "[\n\r][ \t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t)
328 (push (list 'xr-doc (reftex-match-string 2)
329 (reftex-match-string 3))
333 (push (list 'eof file) docstruct)))))
335 ;; Kill the scanned buffer
336 (reftex-kill-temporary-buffers next-buf))
341 (defun reftex-locate-bibliography-files (master-dir &optional files)
342 ;; Scan buffer for bibliography macro and return file list.
346 (goto-char (point-min))
347 (if (re-search-forward
349 ; "\\(\\`\\|[\n\r]\\)[^%]*\\\\\\("
350 "\\(^\\)[^%\n\r]*\\\\\\("
351 (mapconcat 'identity reftex-bibliography-commands "\\|")
352 "\\){[ \t]*\\([^}]+\\)") nil t)
354 (split-string (reftex-match-string 3)
355 "[ \t\n\r]*,[ \t\n\r]*")))))
360 (if (or (member x reftex-bibfile-ignore-list)
361 (delq nil (mapcar (lambda (re) (string-match re x))
362 reftex-bibfile-ignore-regexps)))
366 (reftex-locate-file x "bib" master-dir)))
370 (defun reftex-replace-label-list-segment (old insert &optional entirely)
371 ;; Replace the segment in OLD which corresponds to INSERT.
372 ;; Works with side effects, directly changes old.
373 ;; If entirely is t, just return INSERT.
374 ;; This function also makes sure the old toc markers do not point anywhere.
378 (reftex-silence-toc-markers old (length old))
381 (file (nth 1 (car insert)))
382 (eof-list (member (list 'eof file) old))
383 (bof-list (member (list 'bof file) old))
385 (if (not (and bof-list eof-list))
386 (error "Cannot splice")
388 (reftex-silence-toc-markers bof-list (- (length bof-list)
390 (setq n (- (length old) (length bof-list)))
391 (setcdr (nthcdr n new) (cdr insert))
392 (setcdr (nthcdr (1- (length new)) new) (cdr eof-list)))
395 (defun reftex-section-info (file)
396 ;; Return a section entry for the current match.
397 ;; Careful: This function expects the match-data to be still in place!
398 (let* ((marker (set-marker (make-marker) (1- (match-beginning 3))))
399 (macro (reftex-match-string 3))
400 (prefix (save-match-data
401 (if (string-match "begin{\\([^}]+\\)}" macro)
402 (match-string 1 macro))))
403 (level-exp (cdr (assoc macro reftex-section-levels-all)))
404 (level (if (symbolp level-exp)
405 (save-match-data (funcall level-exp))
407 (star (= ?* (char-after (match-end 3))))
408 (unnumbered (or star (< level 0)))
410 (section-number (reftex-section-number level unnumbered))
411 (text1 (save-match-data
413 (reftex-context-substring prefix))))
414 (literal (buffer-substring-no-properties
415 (1- (match-beginning 3))
416 (min (point-max) (+ (match-end 0) (length text1) 1))))
417 ;; Literal can be too short since text1 too short. No big problem.
418 (text (reftex-nicify-text text1)))
420 ;; Add section number and indentation
423 (make-string (* reftex-level-indent level) ?\ )
424 (if (nth 1 reftex-label-menu-flags) ; section number flag
425 (concat section-number " "))
426 (if prefix (concat (capitalize prefix) ": ") "")
428 (list 'toc "toc" text file marker level section-number
429 literal (marker-position marker))))
431 (defun reftex-ensure-index-support (&optional abort)
432 ;; When index support is turned off, ask to turn it on and
433 ;; set the current prefix argument so that `reftex-access-scan-info'
434 ;; will rescan the entire document.
436 (reftex-support-index t)
437 ((y-or-n-p "Turn on index support and rescan entire document? ")
438 (setq reftex-support-index 'demanded
439 current-prefix-arg '(16)))
441 (error "No index support")
442 (message "No index support")
446 (defun reftex-index-info-safe (file)
447 (reftex-with-special-syntax
448 (reftex-index-info file)))
451 (defun reftex-index-info (file)
452 ;; Return an index entry for the current match.
453 ;; Careful: This function expects the match-data to be still in place!
455 (let* ((macro (reftex-match-string 10))
456 (bom (match-beginning 10))
458 (entry (or (assoc macro reftex-index-macro-alist)
460 (exclude (nth 3 entry))
461 ;; The following is a test if this match should be excluded
462 (test-dummy (and (fboundp exclude)
466 (prefix (nth 2 entry))
468 (cond ((stringp itag) itag)
470 (progn (goto-char boa)
471 (or (reftex-nth-arg itag (nth 6 entry)) "idx")))
473 (arg (or (progn (goto-char boa)
474 (reftex-nth-arg (nth 5 entry) (nth 6 entry)))
476 (end-of-args (progn (goto-char boa)
477 (reftex-move-over-touching-args)
479 (end-of-context (progn (skip-chars-forward "^ \t\n\r") (point)))
481 (progn (goto-char bom)
482 (skip-chars-backward "^ \t\r\n")
484 (context (buffer-substring-no-properties
485 begin-of-context end-of-context))
486 (key-end (if (string-match reftex-index-key-end-re arg)
487 (1+ (match-beginning 0))))
488 (rawkey (substring arg 0 key-end))
490 (key (if prefix (concat prefix rawkey) rawkey))
491 (sortkey (downcase key))
492 (showkey (mapconcat 'identity
493 (split-string key reftex-index-level-re)
495 (goto-char end-of-args)
496 ;; 0 1 2 3 4 5 6 7 8 9
497 (list 'index index-tag context file bom arg key showkey sortkey key-end))))
499 (defun reftex-short-context (env parse &optional bound derive)
500 ;; Get about one line of useful context for the label definition at point.
503 (setq parse (if derive (cdr parse) (car parse))))
511 (reftex-context-substring)))
514 (if (string= env "section")
515 ;; special treatment for section labels
517 (if (and (re-search-backward reftex-section-or-include-regexp
521 (goto-char (match-end 0))
522 (reftex-context-substring))
523 (if reftex-active-toc
525 (string-match "{\\([^}]*\\)" (nth 7 reftex-active-toc))
526 (match-string 1 (nth 7 reftex-active-toc)))
527 "SECTION HEADING NOT FOUND")))
529 (goto-char reftex-default-context-position)
530 (unless (eq (string-to-char env) ?\\)
531 (reftex-move-over-touching-args))
532 (reftex-context-substring))))
536 (if (re-search-backward parse bound t)
538 (goto-char (match-end 0))
539 (reftex-context-substring))
540 "NO MATCH FOR CONTEXT REGEXP")))
544 (goto-char reftex-default-context-position)
547 (nth 6 (assoc env reftex-env-or-mac-alist))))
551 ;; A hook function. Call it.
553 (condition-case error-var
555 (error (format "HOOK ERROR: %s" (cdr error-var))))))
557 "INVALID VALUE OF PARSE"))))
559 (defun reftex-where-am-I ()
560 ;; Return the docstruct entry above point. Actually returns a cons
561 ;; cell in which the cdr is a flag indicating if the information is
562 ;; exact (t) or approximate (nil).
564 (let ((docstruct (symbol-value reftex-docstruct-symbol))
565 (cnt 0) rtn rtn-if-no-other
570 (setq found (re-search-backward (reftex-everything-regexp) nil t))
576 (car (member (list 'bof (buffer-file-name)) docstruct))
578 (assq 'bof docstruct) ;; for safety reasons
582 (assoc (reftex-match-string 1)
583 (symbol-value reftex-docstruct-symbol)))
586 (goto-char (1- (match-beginning 3)))
587 (let* ((list (member (list 'bof (buffer-file-name))
589 (endelt (car (member (list 'eof (buffer-file-name))
592 (while (and list (not (eq endelt (car list))))
593 (if (and (eq (car (car list)) 'toc)
594 (string= (buffer-file-name)
598 (or (and (markerp (nth 4 (car list)))
599 (marker-position (nth 4 (car list))))
601 ;; Fits with marker position or recorded position
602 (setq rtn1 (car list) list nil))
603 ((looking-at (reftex-make-regexp-allow-for-ctrl-m
605 ;; Same title: remember, but keep looking
606 (setq rtn-if-no-other (car list)))))
610 ;; Input or include...
612 (member (list 'eof (reftex-locate-file
613 (reftex-match-string 7) "tex"
614 (cdr (assq 'master-dir docstruct))))
617 (assq 'appendix (symbol-value reftex-docstruct-symbol)))
620 (when reftex-support-index
621 (let* ((index-info (save-excursion
622 (reftex-index-info-safe nil)))
623 (list (member (list 'bof (buffer-file-name))
625 (endelt (car (member (list 'eof (buffer-file-name))
627 dist last-dist last (n 0))
628 ;; Check all index entries with equal text
629 (while (and list (not (eq endelt (car list))))
630 (when (and (eq (car (car list)) 'index)
631 (string= (nth 2 index-info)
634 (setq dist (abs (- (point) (nth 4 (car list)))))
635 (if (or (not last-dist) (< dist last-dist))
636 (setq last-dist dist last (car list))))
637 (setq list (cdr list)))
638 ;; We are sure if we have only one, or a zero distance
639 (cond ((or (= n 1) (equal dist 0)) last)
640 ((> n 1) (setq cnt 2) last)
644 (goto-char (match-end 11))
645 (assoc (reftex-no-props
646 (reftex-nth-arg-wrapper
647 (reftex-match-string 11)))
648 (symbol-value reftex-docstruct-symbol))))
650 (error "This should not happen (reftex-where-am-I)"))))))
651 ;; Check if there was only a by-name match for the section.
652 (when (and (not rtn) rtn-if-no-other)
653 (setq rtn rtn-if-no-other
655 (cons rtn (eq cnt 1))))
657 (defun reftex-notice-new (&optional n force)
658 "Hook to handshake with RefTeX after something new has been inserted."
659 ;; Add a new entry to the docstruct list. If it is a section, renumber
660 ;; the following sections.
661 ;; FIXME: Put in a WHAT parameter and search backward until one is found.
662 ;; When N is given, go back that many matches of reftex-everything-regexp
663 ;; When FORCE is non-nil, also insert if `reftex-where-am-I' was uncertain.
666 (unless reftex-mode (throw 'exit nil))
667 (reftex-access-scan-info)
668 (let* ((docstruct (symbol-value reftex-docstruct-symbol))
669 here-I-am appendix tail entry star level
670 section-number context)
673 (when (re-search-backward (reftex-everything-regexp) nil t (or n 1))
676 (setq here-I-am (reftex-where-am-I))
677 (or here-I-am (throw 'exit nil))
678 (unless (or force (cdr here-I-am)) (throw 'exit nil))
679 (setq tail (memq (car here-I-am) docstruct))
680 (or tail (throw 'exit nil))
681 (setq reftex-active-toc (reftex-last-assoc-before-elt
682 'toc (car here-I-am) docstruct)
683 appendix (reftex-last-assoc-before-elt
684 'appendix (car here-I-am) docstruct))
686 ;; Initialize section numbers
687 (if (eq (car (car here-I-am)) 'appendix)
688 (reftex-init-section-numbers nil t)
689 (reftex-init-section-numbers reftex-active-toc appendix))
691 ;; Match the section command
692 (when (re-search-forward (reftex-everything-regexp) nil t)
695 (push (reftex-label-info (reftex-match-string 1) buffer-file-name)
699 (setq star (= ?* (char-after (match-end 3)))
700 entry (reftex-section-info (buffer-file-name))
702 ;; Insert the section info
703 (push entry (cdr tail))
705 ;; We are done unless we use section numbers
706 (unless (nth 1 reftex-label-menu-flags) (throw 'exit nil))
708 ;; Update the remaining toc items
709 (setq tail (cdr tail))
710 (while (and (setq tail (memq (assq 'toc (cdr tail)) tail))
711 (setq entry (car tail))
712 (>= (nth 5 entry) level))
713 (setq star (string-match "\\*" (nth 6 entry))
714 context (nth 2 entry)
716 (reftex-section-number (nth 5 entry) star))
717 (when (string-match "\\`\\([ \t]*\\)\\([.0-9A-Z]+\\)\\(.*\\)"
719 (when (and (not appendix)
720 (>= (string-to-char (match-string 2)) ?A))
721 ;; Just entered the appendix. Get out.
724 ;; Change the section number.
726 (concat (match-string 1 context)
728 (match-string 3 context))))))
731 (and reftex-support-index
732 (setq entry (reftex-index-info-safe buffer-file-name))
733 ;; FIXME: (add-to-list 'index-tags (nth 1 index-entry))
734 (push entry (cdr tail))))))))))
739 (defsubst reftex-move-to-previous-arg (&optional bound)
740 ;; Assuming that we are in front of a macro argument,
741 ;; move backward to the closing parenthesis of the previous argument.
742 ;; This function understands the splitting of macros over several lines
746 ((memq (preceding-char) '(?\] ?\})))
748 ((and reftex-allow-detached-macro-args
750 "[]}][ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*\\=" bound t))
751 (goto-char (1+ (match-beginning 0)))
755 (defun reftex-what-macro-safe (which &optional bound)
756 ;; reftex-what-macro with special syntax table.
757 (reftex-with-special-syntax
758 (reftex-what-macro which bound)))
760 (defun reftex-what-macro (which &optional bound)
761 ;; Find out if point is within the arguments of any TeX-macro.
762 ;; The return value is either ("\\macro" . (point)) or a list of them.
764 ;; If WHICH is nil, immediately return nil.
765 ;; If WHICH is 1, return innermost enclosing macro.
766 ;; If WHICH is t, return list of all macros enclosing point.
767 ;; If WHICH is a list of macros, look only for those macros and return the
768 ;; name of the first macro in this list found to enclose point.
769 ;; If the optional BOUND is an integer, bound backwards directed
770 ;; searches to this point. If it is nil, limit to nearest \section -
773 ;; This function is pretty stable, but can be fooled if the text contains
774 ;; things like \macro{aa}{bb} where \macro is defined to take only one
775 ;; argument. As RefTeX cannot know this, the string "bb" would still be
776 ;; considered an argument of macro \macro.
778 (unless reftex-section-regexp (reftex-compile-variables))
780 (if (null which) (throw 'exit nil))
781 (let ((bound (or bound (save-excursion (re-search-backward
782 reftex-section-regexp nil 1)
784 pos cmd-list cmd cnt cnt-opt entry)
787 (narrow-to-region (max (point-min) bound) (point-max))
788 ;; move back out of the current parenthesis
789 (while (condition-case nil
790 (let ((forward-sexp-function nil))
793 (setq cnt 1 cnt-opt 0)
794 ;; move back over any touching sexps
795 (while (and (reftex-move-to-previous-arg bound)
797 (let ((forward-sexp-function nil))
800 (if (eq (following-char) ?\[) (incf cnt-opt))
803 (when (and (or (= (following-char) ?\[)
804 (= (following-char) ?\{))
805 (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t))
806 (setq cmd (reftex-match-string 0))
807 (when (looking-at "\\\\begin{[^}]*}")
808 (setq cmd (reftex-match-string 0)
810 ;; This does ignore optional arguments. Very hard to fix.
811 (when (setq entry (assoc cmd reftex-env-or-mac-alist))
812 (if (> cnt (or (nth 4 entry) 100))
817 (push (cons cmd (point)) cmd-list))
818 ((or (eq 1 which) (member cmd which))
819 (throw 'exit (cons cmd (point))))))
821 (nreverse cmd-list)))))
823 (defun reftex-what-environment (which &optional bound)
824 ;; Find out if point is inside a LaTeX environment.
825 ;; The return value is (e.g.) either ("equation" . (point)) or a list of
828 ;; If WHICH is nil, immediately return nil.
829 ;; If WHICH is 1, return innermost enclosing environment.
830 ;; If WHICH is t, return list of all environments enclosing point.
831 ;; If WHICH is a list of environments, look only for those environments and
832 ;; return the name of the first environment in this list found to enclose
835 ;; If the optional BOUND is an integer, bound backwards directed searches to
836 ;; this point. If it is nil, limit to nearest \section - like statement.
838 (unless reftex-section-regexp (reftex-compile-variables))
841 (if (null which) (throw 'exit nil))
842 (let ((bound (or bound (save-excursion (re-search-backward
843 reftex-section-regexp nil 1)
845 env-list end-list env)
846 (while (re-search-backward "\\\\\\(begin\\|end\\){\\([^}]+\\)}"
848 (setq env (buffer-substring-no-properties
849 (match-beginning 2) (match-end 2)))
851 ((string= (match-string 1) "end")
853 ((equal env (car end-list))
854 (setq end-list (cdr end-list)))
856 (push (cons env (point)) env-list))
857 ((or (eq 1 which) (member env which))
858 (throw 'exit (cons env (point))))))
859 (nreverse env-list)))))
861 (defun reftex-what-special-env (which &optional bound)
862 ;; Run the special environment parsers and return the matches.
864 ;; The return value is (e.g.) either ("my-parser-function" . (point))
865 ;; or a list of them.
867 ;; If WHICH is nil, immediately return nil.
868 ;; If WHICH is 1, return innermost enclosing environment.
869 ;; If WHICH is t, return list of all environments enclosing point.
870 ;; If WHICH is a list of environments, look only for those environments and
871 ;; return the name of the first environment in this list found to enclose
874 (unless reftex-section-regexp (reftex-compile-variables))
877 (if (null reftex-special-env-parsers) (throw 'exit nil))
878 (if (null which) (throw 'exit nil))
879 (let ((bound (or bound (save-excursion (re-search-backward
880 reftex-section-regexp nil 1)
882 (fun-list (if (listp which)
883 (mapcar (lambda (x) (if (memq x which) x nil))
884 reftex-special-env-parsers)
885 reftex-special-env-parsers))
887 ;; Call all functions
888 (setq specials (mapcar
891 (setq rtn (and fun (funcall fun bound)))
892 (if rtn (cons (symbol-name fun) rtn) nil)))
894 ;; Delete the non-matches
895 (setq specials (delq nil specials))
897 (setq specials (sort specials (lambda (a b) (> (cdr a) (cdr b)))))
902 (defsubst reftex-move-to-next-arg (&optional ignore)
903 ;; Assuming that we are at the end of a macro name or a macro argument,
904 ;; move forward to the opening parenthesis of the next argument.
905 ;; This function understands the splitting of macros over several lines
909 ((memq (following-char) '(?\[ ?\{)))
911 ((and reftex-allow-detached-macro-args
912 (looking-at "[ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*[[{]"))
913 (goto-char (1- (match-end 0)))
917 (defun reftex-nth-arg-wrapper (key)
918 (let ((entry (assoc key reftex-env-or-mac-alist)))
919 (reftex-nth-arg (nth 5 entry) (nth 6 entry))))
921 (defun reftex-nth-arg (n &optional opt-args)
922 ;; Return the nth following {} or [] parentheses content.
923 ;; OPT-ARGS is a list of argument numbers which are optional.
925 ;; If we are sitting at a macro start, skip to end of macro name.
926 (and (eq (following-char) ?\\) (skip-chars-forward "a-zA-Z*\\\\"))
929 ;; Special case: Skip all touching arguments
931 (reftex-move-over-touching-args)
932 (reftex-context-substring))
934 ;; Do the real thing.
937 (when (reftex-move-to-next-arg)
940 (while (and (member cnt opt-args)
941 (eq (following-char) ?\{))
944 (unless (and (condition-case nil
945 (or (forward-list 1) t)
947 (reftex-move-to-next-arg)
951 (while (and (memq cnt opt-args)
952 (eq (following-char) ?\{))
955 (> (skip-chars-forward "{\\[") 0))
956 (reftex-context-substring)
959 (defun reftex-move-over-touching-args ()
961 (while (memq (following-char) '(?\[ ?\{))
965 (defun reftex-context-substring (&optional to-end)
966 ;; Return up to 150 chars from point
967 ;; When point is just after a { or [, limit string to matching parenthesis
970 ;; Environment - find next \end
971 (buffer-substring-no-properties
975 ;; FIXME: This is not perfect
976 (if (re-search-forward "\\\\end{" nil t)
979 ((memq (preceding-char) '(?\{ ?\[))
980 ;; Inside a list - get only the list.
981 (buffer-substring-no-properties
986 (let ((forward-sexp-function nil)) ;Unneeded fanciness.
989 (error (point-max))))))
991 ;; no list - just grab 150 characters
992 (buffer-substring-no-properties (point)
993 (min (+ (point) 150) (point-max))))))
995 ;; Variable holding the vector with section numbers
996 (defvar reftex-section-numbers (make-vector reftex-max-section-depth 0))
998 (defun reftex-init-section-numbers (&optional toc-entry appendix)
999 ;; Initialize the section numbers with zeros or with what is found
1000 ;; in the toc entry.
1001 (let* ((level (or (nth 5 toc-entry) -1))
1002 (numbers (nreverse (split-string (or (nth 6 toc-entry) "") "\\.")))
1003 (depth (1- (length reftex-section-numbers)))
1004 (i depth) number-string)
1007 (aset reftex-section-numbers i 0)
1008 (setq number-string (or (car numbers) "0"))
1009 (if (string-match "\\`[A-Z]\\'" number-string)
1010 (aset reftex-section-numbers i
1011 (- (string-to-char number-string) ?A -1))
1012 (aset reftex-section-numbers i (string-to-number number-string)))
1015 (put 'reftex-section-numbers 'appendix appendix))
1017 (defun reftex-section-number (&optional level star)
1018 ;; Return a string with the current section number.
1019 ;; When LEVEL is non-nil, increase section numbers on that level.
1020 (let* ((depth (1- (length reftex-section-numbers))) idx n (string "")
1021 (appendix (get 'reftex-section-numbers 'appendix))
1022 (partspecial (and (not reftex-part-resets-chapter)
1024 ;; partspecial means, this is a part statement.
1025 ;; Parts do not reset the chapter counter, and the part number is
1026 ;; not included in the numbering of other sectioning levels.
1028 (when (and (> level -1) (not star))
1029 (aset reftex-section-numbers
1030 level (1+ (aref reftex-section-numbers level))))
1031 (setq idx (1+ level))
1033 (while (<= idx depth)
1034 (if (or (not partspecial)
1036 (aset reftex-section-numbers idx 0))
1039 (setq string (concat "Part " (reftex-roman-number
1040 (aref reftex-section-numbers 0))))
1041 (setq idx (if reftex-part-resets-chapter 0 1))
1042 (while (<= idx depth)
1043 (setq n (aref reftex-section-numbers idx))
1044 (if (not (and partspecial (not (equal string ""))))
1045 (setq string (concat string (if (not (string= string "")) "." "")
1046 (int-to-string n))))
1049 (if (string-match "\\`\\([@0]\\.\\)+" string)
1050 (setq string (replace-match "" nil nil string)))
1051 (if (string-match "\\(\\.0\\)+\\'" string)
1052 (setq string (replace-match "" nil nil string)))
1054 (string-match "\\`[0-9]+" string))
1058 (1- (+ ?A (string-to-number (match-string 0 string)))))
1059 (substring string (match-end 0))))))
1061 (concat (make-string (1- (length string)) ?\ ) "*")
1064 (defun reftex-roman-number (n)
1065 ;; Return as a string the roman number equal to N.
1068 (list '((1000 . "M") ( 900 . "CM") ( 500 . "D") ( 400 . "CD")
1069 ( 100 . "C") ( 90 . "XC") ( 50 . "L") ( 40 . "XL")
1070 ( 10 . "X") ( 9 . "IX") ( 5 . "V") ( 4 . "IV")
1074 (setq listel (pop list)
1078 (setq string (concat string s)
1079 nrest (- nrest i))))
1082 (provide 'reftex-parse)
1084 ;;; reftex-parse.el ends here