1 ;;; reftex-parse.el - Parser Functions for RefTeX
4 ;;; See main file reftex.el for licensing information
6 (eval-when-compile (require 'cl))
7 (provide 'reftex-parse)
10 (defmacro reftex-with-special-syntax (&rest body)
11 `(let ((saved-syntax (syntax-table)))
14 (set-syntax-table reftex-syntax-table)
16 (set-syntax-table saved-syntax))))
18 (defun reftex-parse-one ()
21 (let ((reftex-enable-partial-scans t))
22 (reftex-access-scan-info '(4))))
24 (defun reftex-parse-all ()
25 "Re-parse entire document."
27 (reftex-access-scan-info '(16)))
29 (defun reftex-do-parse (rescan &optional file)
30 "Do a document rescan. When allowed, do only a partial scan from FILE."
32 ;; Normalize the rescan argument
33 (setq rescan (cond ((eq rescan t) t)
35 ((equal rescan '(4)) t)
36 ((equal rescan '(16)) 1)
39 ;; Partial scans only when allowed
40 (unless reftex-enable-partial-scans
45 (let* ((old-list (symbol-value reftex-docstruct-symbol))
46 (master (reftex-TeX-master-file))
47 (true-master (file-truename master))
48 (master-dir (file-name-as-directory (file-name-directory master)))
49 (file (or file (buffer-file-name)))
50 (true-file (file-truename file))
51 (bibview-cache (assq 'bibview-cache old-list))
52 (index-tags (cdr (assq 'index-tags old-list)))
53 from-file appendix docstruct tmp)
55 ;; Make sure replacement is really an option here
56 (when (and (eq rescan t)
57 (not (and (member (list 'bof file) old-list)
58 (member (list 'eof file) old-list))))
59 ;; Scan whole document because no such file section exists
61 (when (string= true-file true-master)
62 ;; Scan whole document because this file is the master
65 ;; From which file do we start?
67 (cond ((eq rescan t) (or file master))
68 ((eq rescan 1) master)
69 (t (error "This should not happen (reftex-do-parse)"))))
71 ;; Reset index-tags if we scan everything
72 (if (equal rescan 1) (setq index-tags nil))
74 ;; Find active toc entry and initialize section-numbers
75 (setq reftex-active-toc (reftex-last-assoc-before-elt
76 'toc (list 'bof from-file) old-list)
77 appendix (reftex-last-assoc-before-elt
78 'appendix (list 'bof from-file) old-list))
80 (reftex-init-section-numbers reftex-active-toc appendix)
83 (message "Scanning entire document...")
84 (message "Scanning document from %s..." from-file))
86 (reftex-with-special-syntax
87 (save-window-excursion
91 (reftex-parse-from-file
92 from-file docstruct master-dir))
93 (reftex-kill-temporary-buffers)))))
95 (message "Scanning document... done")
97 ;; Turn the list around.
98 (setq docstruct (nreverse docstruct))
101 (setq docstruct (reftex-replace-label-list-segment
102 old-list docstruct (eq rescan 1)))
104 ;; Add all missing information
105 (unless (assq 'label-numbers docstruct)
106 (push (cons 'label-numbers nil) docstruct))
107 (unless (assq 'master-dir docstruct)
108 (push (cons 'master-dir master-dir) docstruct))
109 (unless (assq 'bibview-cache docstruct)
110 (push (cons 'bibview-cache (cdr bibview-cache)) docstruct))
111 (let* ((bof1 (memq (assq 'bof docstruct) docstruct))
112 (bof2 (assq 'bof (cdr bof1)))
113 (is-multi (not (not (and bof1 bof2))))
114 (entry (or (assq 'is-multi docstruct)
115 (car (push (list 'is-multi is-multi) docstruct)))))
116 (setcdr entry (cons is-multi nil)))
117 (and index-tags (setq index-tags (sort index-tags 'string<)))
118 (let ((index-tag-cell (assq 'index-tags docstruct)))
120 (setcdr index-tag-cell index-tags)
121 (push (cons 'index-tags index-tags) docstruct)))
122 (unless (assq 'xr docstruct)
123 (let* ((allxr (reftex-all-assq 'xr-doc docstruct))
126 (if (setq tmp (reftex-locate-file (nth 2 x) "tex"
129 (message "Can't find external document %s"
133 (alist (delq nil alist))
134 (allprefix (delq nil (mapcar 'car alist)))
135 (regexp (if allprefix
137 (mapconcat 'identity allprefix "\\|")
139 "\\\\\\\\\\\\"))) ; this will never match
140 (push (list 'xr alist regexp) docstruct)))
142 (set reftex-docstruct-symbol docstruct)
143 (put reftex-docstruct-symbol 'modified t)))
145 (defun reftex-everything-regexp ()
146 (if reftex-support-index
147 reftex-everything-regexp
148 reftex-everything-regexp-no-index))
150 (defun reftex-all-document-files (&optional relative)
151 "Return a list of all files belonging to the current document.
152 When RELATIVE is non-nil, give file names relative to directory
154 (let* ((all (symbol-value reftex-docstruct-symbol))
155 (master-dir (file-name-directory (reftex-TeX-master-file)))
156 (re (concat "\\`" (regexp-quote master-dir)))
158 (while (setq tmp (assoc 'bof all))
159 (setq file (nth 1 tmp)
160 all (cdr (memq tmp all)))
162 (string-match re file)
163 (setq file (substring file (match-end 0))))
164 (push file file-list))
165 (nreverse file-list)))
167 (defun reftex-parse-from-file (file docstruct master-dir)
168 ;; Scan the buffer for labels and save them in a list.
169 (let ((regexp (reftex-everything-regexp))
171 file-found tmp include-file
174 toc-entry index-entry next-buf buf)
177 (setq file-found (reftex-locate-file file "tex" master-dir))
178 (if (and (not file-found)
179 (setq buf (reftex-get-buffer-visiting file)))
180 (setq file-found (buffer-file-name buf)))
183 (push (list 'file-error file) docstruct)
188 (message "Scanning file %s" file)
191 (reftex-get-file-buffer-force
193 (not (eq t reftex-keep-temporary-buffers)))))
195 ;; Begin of file mark
196 (setq file (buffer-file-name))
197 (push (list 'bof file) docstruct)
199 (reftex-with-special-syntax
205 (while (re-search-forward regexp nil t)
211 (push (reftex-label-info (reftex-match-string 1) file bound)
219 (setq toc-entry (reftex-section-info file))
221 ;; It can happen that section info returns nil
222 (setq level (nth 5 toc-entry))
223 (setq highest-level (min highest-level level))
224 (if (= level highest-level)
227 (car (rassoc level reftex-section-levels-all))
230 (push toc-entry docstruct)
231 (setq reftex-active-toc toc-entry)))
234 ;; It's an include or input
235 (setq include-file (reftex-match-string 7))
236 ;; Test if this file should be ignored
237 (unless (delq nil (mapcar
238 (lambda (x) (string-match x include-file))
239 reftex-no-include-regexps))
242 (reftex-parse-from-file
244 docstruct master-dir))))
247 ;; Appendix starts here
248 (reftex-init-section-numbers nil t)
249 (push (cons 'appendix t) docstruct))
253 (when reftex-support-index
254 (setq index-entry (reftex-index-info file))
256 (add-to-list 'index-tags (nth 1 index-entry))
257 (push index-entry docstruct))))
260 ;; A macro with label
262 (let* ((mac (reftex-match-string 11))
263 (label (progn (goto-char (match-end 11))
266 (reftex-nth-arg-wrapper
268 (typekey (nth 1 (assoc mac reftex-env-or-mac-alist)))
269 (entry (progn (if typekey
271 (goto-char (match-end 0))
273 (goto-char (match-end 11))
274 (reftex-move-over-touching-args))
276 label file bound nil nil))))
277 (push entry docstruct))))
278 (t (error "This should not happen (reftex-parse-from-file)")))
281 ;; Find bibliography statement
282 (when (setq tmp (reftex-locate-bibliography-files master-dir))
283 (push (cons 'bib tmp) docstruct))
286 (when (re-search-forward
287 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\begin{thebibliography}" nil t)
288 (push (cons 'thebib file) docstruct))
290 ;; Find external document specifications
292 (while (re-search-forward "[\n\r][ \t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t)
293 (push (list 'xr-doc (reftex-match-string 2)
294 (reftex-match-string 3))
298 (push (list 'eof file) docstruct)))))
300 ;; Kill the scanned buffer
301 (reftex-kill-temporary-buffers next-buf))
306 (defun reftex-locate-bibliography-files (master-dir &optional files)
307 ;; Scan buffer for bibliography macro and return file list.
311 (goto-char (point-min))
312 (if (re-search-forward
313 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\bibliography{[ \t]*\\([^}]+\\)" nil t)
315 (split-string (reftex-match-string 2)
316 "[ \t\n\r]*,[ \t\n\r]*")))))
321 (if (or (member x reftex-bibfile-ignore-list)
322 (delq nil (mapcar (lambda (re) (string-match re x))
323 reftex-bibfile-ignore-regexps)))
327 (reftex-locate-file x "bib" master-dir)))
331 (defun reftex-replace-label-list-segment (old insert &optional entirely)
332 ;; Replace the segment in OLD which corresponds to INSERT.
333 ;; Works with side effects, directly changes old.
334 ;; If entirely is t, just return INSERT.
335 ;; This function also makes sure the old toc markers do not point anywhere.
339 (reftex-silence-toc-markers old (length old))
342 (file (nth 1 (car insert)))
343 (eof-list (member (list 'eof file) old))
344 (bof-list (member (list 'bof file) old))
346 (if (not (and bof-list eof-list))
347 (error "Cannot splice")
349 (reftex-silence-toc-markers bof-list (- (length bof-list)
351 (setq n (- (length old) (length bof-list)))
352 (setcdr (nthcdr n new) (cdr insert))
353 (setcdr (nthcdr (1- (length new)) new) (cdr eof-list)))
356 (defun reftex-section-info (file)
357 ;; Return a section entry for the current match.
358 ;; Carefull: This function expects the match-data to be still in place!
359 (let* ((marker (set-marker (make-marker) (1- (match-beginning 3))))
360 (macro (reftex-match-string 3))
361 (prefix (save-match-data
362 (if (string-match "begin{\\([^}]+\\)}" macro)
363 (match-string 1 macro))))
364 (level-exp (cdr (assoc macro reftex-section-levels-all)))
365 (level (if (symbolp level-exp)
366 (save-match-data (funcall level-exp))
368 (star (= ?* (char-after (match-end 3))))
369 (unnumbered (or star (< level 0)))
371 (section-number (reftex-section-number level unnumbered))
372 (text1 (save-match-data
374 (reftex-context-substring prefix))))
375 (literal (buffer-substring-no-properties
376 (1- (match-beginning 3))
377 (min (point-max) (+ (match-end 0) (length text1) 1))))
378 ;; Literal can be too short since text1 too short. No big problem.
379 (text (reftex-nicify-text text1)))
381 ;; Add section number and indentation
384 (make-string (* reftex-level-indent level) ?\ )
385 (if (nth 1 reftex-label-menu-flags) ; section number flag
386 (concat section-number " "))
387 (if prefix (concat (capitalize prefix) ": ") "")
389 (list 'toc "toc" text file marker level section-number
390 literal (marker-position marker))))
392 (defun reftex-ensure-index-support (&optional abort)
393 ;; When index support is turned off, ask to turn it on and
394 ;; set the current prefix argument so that `reftex-access-scan-info'
395 ;; will rescan the entire document.
397 (reftex-support-index t)
398 ((y-or-n-p "Turn on index support and rescan entire document? ")
399 (setq reftex-support-index 'demanded
400 current-prefix-arg '(16)))
402 (error "No index support")
403 (message "No index support")
407 (defun reftex-index-info-safe (file)
408 (reftex-with-special-syntax
409 (reftex-index-info file)))
412 (defun reftex-index-info (file)
413 ;; Return an index entry for the current match.
414 ;; Carefull: This function expects the match-data to be still in place!
416 (let* ((macro (reftex-match-string 10))
417 (bom (match-beginning 10))
419 (entry (or (assoc macro reftex-index-macro-alist)
421 (exclude (nth 3 entry))
422 ;; The following is a test if this match should be excluded
423 (test-dummy (and (fboundp exclude)
427 (prefix (nth 2 entry))
429 (cond ((stringp itag) itag)
431 (progn (goto-char boa)
432 (or (reftex-nth-arg itag (nth 6 entry)) "idx")))
434 (arg (or (progn (goto-char boa)
435 (reftex-nth-arg (nth 5 entry) (nth 6 entry)))
437 (end-of-args (progn (goto-char boa)
438 (reftex-move-over-touching-args)
440 (end-of-context (progn (skip-chars-forward "^ \t\n\r") (point)))
442 (progn (goto-char bom)
443 (skip-chars-backward "^ \t\r\n")
445 (context (buffer-substring-no-properties
446 begin-of-context end-of-context))
447 (key-end (if (string-match reftex-index-key-end-re arg)
448 (1+ (match-beginning 0))))
449 (rawkey (substring arg 0 key-end))
451 (key (if prefix (concat prefix rawkey) rawkey))
452 (sortkey (downcase key))
453 (showkey (mapconcat 'identity
454 (split-string key reftex-index-level-re)
456 (goto-char end-of-args)
457 ;; 0 1 2 3 4 5 6 7 8 9
458 (list 'index index-tag context file bom arg key showkey sortkey key-end))))
460 (defun reftex-short-context (env parse &optional bound derive)
461 ;; Get about one line of useful context for the label definition at point.
464 (setq parse (if derive (cdr parse) (car parse))))
472 (reftex-context-substring)))
475 (if (string= env "section")
476 ;; special treatment for section labels
478 (if (and (re-search-backward reftex-section-or-include-regexp
482 (goto-char (match-end 0))
483 (reftex-context-substring))
484 (if reftex-active-toc
486 (string-match "{\\([^}]*\\)" (nth 7 reftex-active-toc))
487 (match-string 1 (nth 7 reftex-active-toc)))
488 "SECTION HEADING NOT FOUND")))
490 (goto-char reftex-default-context-position)
491 (unless (eq (string-to-char env) ?\\)
492 (reftex-move-over-touching-args))
493 (reftex-context-substring))))
497 (if (re-search-backward parse bound t)
499 (goto-char (match-end 0))
500 (reftex-context-substring))
501 "NO MATCH FOR CONTEXT REGEXP")))
505 (goto-char reftex-default-context-position)
508 (nth 6 (assoc env reftex-env-or-mac-alist))))
512 ;; A hook function. Call it.
514 (condition-case error-var
516 (error (format "HOOK ERROR: %s" (cdr error-var))))))
518 "ILLEGAL VALUE OF PARSE"))))
520 (defun reftex-where-am-I ()
521 ;; Return the docstruct entry above point. Actually returns a cons
522 ;; cell in which the cdr is a flag indicating if the information is
523 ;; exact (t) or approximate (nil).
525 (let ((docstruct (symbol-value reftex-docstruct-symbol))
531 (setq found (re-search-backward (reftex-everything-regexp) nil t))
537 (car (member (list 'bof (buffer-file-name)) docstruct))
539 (assq 'bof docstruct) ;; for safety reasons
543 (assoc (reftex-match-string 1)
544 (symbol-value reftex-docstruct-symbol)))
547 (goto-char (1- (match-beginning 3)))
548 (let* ((list (member (list 'bof (buffer-file-name))
550 (endelt (car (member (list 'eof (buffer-file-name))
553 (while (and list (not (eq endelt (car list))))
554 (if (and (eq (car (car list)) 'toc)
555 (string= (buffer-file-name)
559 (or (and (markerp (nth 4 (car list)))
560 (marker-position (nth 4 (car list))))
562 ;; Fits with marker position or recorded position
563 (setq rtn1 (car list) list nil))
564 ((looking-at (reftex-make-regexp-allow-for-ctrl-m
567 (setq rtn1 (car list) list nil cnt 2))))
571 ;; Input or include...
573 (member (list 'eof (reftex-locate-file
574 (reftex-match-string 7) "tex"
575 (cdr (assq 'master-dir docstruct))))
578 (assq 'appendix (symbol-value reftex-docstruct-symbol)))
581 (when reftex-support-index
582 (let* ((index-info (save-excursion
583 (reftex-index-info-safe nil)))
584 (list (member (list 'bof (buffer-file-name))
586 (endelt (car (member (list 'eof (buffer-file-name))
588 dist last-dist last (n 0))
589 ;; Check all index entries with equal text
590 (while (and list (not (eq endelt (car list))))
591 (when (and (eq (car (car list)) 'index)
592 (string= (nth 2 index-info)
595 (setq dist (abs (- (point) (nth 4 (car list)))))
596 (if (or (not last-dist) (< dist last-dist))
597 (setq last-dist dist last (car list))))
598 (setq list (cdr list)))
599 ;; We are sure if we have only one, or a zero distance
600 (cond ((or (= n 1) (= dist 0)) last)
601 ((> n 1) (setq cnt 2) last)
605 (goto-char (match-end 11))
606 (assoc (reftex-no-props
607 (reftex-nth-arg-wrapper
608 (reftex-match-string 11)))
609 (symbol-value reftex-docstruct-symbol))))
611 (error "This should not happen (reftex-where-am-I)"))))))
612 (cons rtn (eq cnt 1))))
614 (defun reftex-notice-new (&optional n force)
615 "Hook to handshake with RefTeX after something new has been inserted."
616 ;; Add a new entry to the docstruct list. If it is a section, renumber
617 ;; the following sections.
618 ;; FIXME: Put in a WHAT parameter
619 ;; When N is given, go back that many matches of reftex-everything-regexp
620 ;; When FORCE is non-nil, also insert if `reftex-where-am-I' was uncertain.
623 (unless reftex-mode (throw 'exit nil))
624 (reftex-access-scan-info)
625 (let* ((docstruct (symbol-value reftex-docstruct-symbol))
626 here-I-am appendix tail entry star level
627 section-number context)
630 (when (re-search-backward (reftex-everything-regexp) nil t (or n 1))
633 (setq here-I-am (reftex-where-am-I))
634 (or here-I-am (throw 'exit nil))
635 (unless (or force (cdr here-I-am)) (throw 'exit nil))
636 (setq tail (memq (car here-I-am) docstruct))
637 (or tail (throw 'exit nil))
638 (setq reftex-active-toc (reftex-last-assoc-before-elt
639 'toc (car here-I-am) docstruct)
640 appendix (reftex-last-assoc-before-elt
641 'appendix (car here-I-am) docstruct))
643 ;; Initialize section numbers
644 (if (eq (car (car here-I-am)) 'appendix)
645 (reftex-init-section-numbers nil t)
646 (reftex-init-section-numbers reftex-active-toc appendix))
648 ;; Match the section command
649 (when (re-search-forward (reftex-everything-regexp) nil t)
652 (push (reftex-label-info (reftex-match-string 1) buffer-file-name)
656 (setq star (= ?* (char-after (match-end 3)))
657 entry (reftex-section-info (buffer-file-name))
659 ;; Insert the section info
660 (push entry (cdr tail))
662 ;; We are done unless we use section numbers
663 (unless (nth 1 reftex-label-menu-flags) (throw 'exit nil))
665 ;; Update the remaining toc items
666 (setq tail (cdr tail))
667 (while (and (setq tail (memq (assq 'toc (cdr tail)) tail))
668 (setq entry (car tail))
669 (>= (nth 5 entry) level))
670 (setq star (string-match "\\*" (nth 6 entry))
671 context (nth 2 entry)
673 (reftex-section-number (nth 5 entry) star))
674 (when (string-match "\\`\\([ \t]*\\)\\([.0-9A-Z]+\\)\\(.*\\)"
676 (when (and (not appendix)
677 (>= (string-to-char (match-string 2)) ?A))
678 ;; Just entered the appendex. Get out.
681 ;; Change the section number.
683 (concat (match-string 1 context)
685 (match-string 3 context))))))
688 (and reftex-support-index
689 (setq entry (reftex-index-info-safe buffer-file-name))
690 ;; FIXME: (add-to-list 'index-tags (nth 1 index-entry))
691 (push entry (cdr tail))))))))))
696 (defsubst reftex-move-to-previous-arg (&optional bound)
697 ;; Assuming that we are in front of a macro argument,
698 ;; move backward to the closing parenthesis of the previous argument.
699 ;; This function understands the splitting of macros over several lines
703 ((memq (preceding-char) '(?\] ?\})))
705 ((and reftex-allow-detached-macro-args
707 "[]}][ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*\\=" bound t))
708 (goto-char (1+ (match-beginning 0)))
712 (defun reftex-what-macro-safe (which &optional bound)
713 ;; reftex-what-macro with special syntax table.
714 (reftex-with-special-syntax
715 (reftex-what-macro which bound)))
717 (defun reftex-what-macro (which &optional bound)
718 ;; Find out if point is within the arguments of any TeX-macro.
719 ;; The return value is either ("\\macro" . (point)) or a list of them.
721 ;; If WHICH is nil, immediately return nil.
722 ;; If WHICH is 1, return innermost enclosing macro.
723 ;; If WHICH is t, return list of all macros enclosing point.
724 ;; If WHICH is a list of macros, look only for those macros and return the
725 ;; name of the first macro in this list found to enclose point.
726 ;; If the optional BOUND is an integer, bound backwards directed
727 ;; searches to this point. If it is nil, limit to nearest \section -
730 ;; This function is pretty stable, but can be fooled if the text contains
731 ;; things like \macro{aa}{bb} where \macro is defined to take only one
732 ;; argument. As RefTeX cannot know this, the string "bb" would still be
733 ;; considered an argument of macro \macro.
735 (unless reftex-section-regexp (reftex-compile-variables))
737 (if (null which) (throw 'exit nil))
738 (let ((bound (or bound (save-excursion (re-search-backward
739 reftex-section-regexp nil 1)
741 pos cmd-list cmd cnt cnt-opt entry)
744 (narrow-to-region (max 1 bound) (point-max))
745 ;; move back out of the current parenthesis
746 (while (condition-case nil
747 (progn (up-list -1) t)
749 (setq cnt 1 cnt-opt 0)
750 ;; move back over any touching sexps
751 (while (and (reftex-move-to-previous-arg bound)
753 (progn (backward-sexp) t)
755 (if (eq (following-char) ?\[) (incf cnt-opt))
758 (when (and (or (= (following-char) ?\[)
759 (= (following-char) ?\{))
760 (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t))
761 (setq cmd (reftex-match-string 0))
762 (when (looking-at "\\\\begin{[^}]*}")
763 (setq cmd (reftex-match-string 0)
765 ;; This does ignore optional arguments. Very hard to fix.
766 (when (setq entry (assoc cmd reftex-env-or-mac-alist))
767 (if (> cnt (or (nth 4 entry) 100))
772 (push (cons cmd (point)) cmd-list))
773 ((or (eq 1 which) (member cmd which))
774 (throw 'exit (cons cmd (point))))))
776 (nreverse cmd-list)))))
778 (defun reftex-what-environment (which &optional bound)
779 ;; Find out if point is inside a LaTeX environment.
780 ;; The return value is (e.g.) either ("equation" . (point)) or a list of
783 ;; If WHICH is nil, immediately return nil.
784 ;; If WHICH is 1, return innermost enclosing environment.
785 ;; If WHICH is t, return list of all environments enclosing point.
786 ;; If WHICH is a list of environments, look only for those environments and
787 ;; return the name of the first environment in this list found to enclose
790 ;; If the optional BOUND is an integer, bound backwards directed searches to
791 ;; this point. If it is nil, limit to nearest \section - like statement.
793 (unless reftex-section-regexp (reftex-compile-variables))
796 (if (null which) (throw 'exit nil))
797 (let ((bound (or bound (save-excursion (re-search-backward
798 reftex-section-regexp nil 1)
800 env-list end-list env)
801 (while (re-search-backward "\\\\\\(begin\\|end\\){\\([^}]+\\)}"
803 (setq env (buffer-substring-no-properties
804 (match-beginning 2) (match-end 2)))
806 ((string= (match-string 1) "end")
808 ((equal env (car end-list))
809 (setq end-list (cdr end-list)))
811 (push (cons env (point)) env-list))
812 ((or (eq 1 which) (member env which))
813 (throw 'exit (cons env (point))))))
814 (nreverse env-list)))))
816 (defun reftex-what-special-env (which &optional bound)
817 ;; Run the special environment parsers and return the matches.
819 ;; The return value is (e.g.) either ("my-parser-function" . (point))
820 ;; or a list of them.
822 ;; If WHICH is nil, immediately return nil.
823 ;; If WHICH is 1, return innermost enclosing environment.
824 ;; If WHICH is t, return list of all environments enclosing point.
825 ;; If WHICH is a list of environments, look only for those environments and
826 ;; return the name of the first environment in this list found to enclose
829 (unless reftex-section-regexp (reftex-compile-variables))
832 (if (null reftex-special-env-parsers) (throw 'exit nil))
833 (if (null which) (throw 'exit nil))
834 (let ((bound (or bound (save-excursion (re-search-backward
835 reftex-section-regexp nil 1)
837 (fun-list (if (listp which)
838 (mapcar (lambda (x) (if (memq x which) x nil))
839 reftex-special-env-parsers)
840 reftex-special-env-parsers))
842 ;; Call all functions
843 (setq specials (mapcar
846 (setq rtn (and fun (funcall fun bound)))
847 (if rtn (cons (symbol-name fun) rtn) nil)))
849 ;; Delete the non-matches
850 (setq specials (delq nil specials))
852 (setq specials (sort specials (lambda (a b) (> (cdr a) (cdr b)))))
857 (defsubst reftex-move-to-next-arg (&optional ignore)
858 ;; Assuming that we are at the end of a macro name or a macro argument,
859 ;; move forward to the opening parenthesis of the next argument.
860 ;; This function understands the splitting of macros over several lines
864 ((memq (following-char) '(?\[ ?\{)))
866 ((and reftex-allow-detached-macro-args
867 (looking-at "[ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*[[{]"))
868 (goto-char (1- (match-end 0)))
872 (defun reftex-nth-arg-wrapper (key)
873 (let ((entry (assoc key reftex-env-or-mac-alist)))
874 (reftex-nth-arg (nth 5 entry) (nth 6 entry))))
876 (defun reftex-nth-arg (n &optional opt-args)
877 ;; Return the nth following {} or [] parentheses content.
878 ;; OPT-ARGS is a list of argument numbers which are optional.
880 ;; If we are sitting at a macro start, skip to end of macro name.
881 (and (eq (following-char) ?\\) (skip-chars-forward "a-zA-Z*\\\\"))
884 ;; Special case: Skip all touching arguments
886 (reftex-move-over-touching-args)
887 (reftex-context-substring))
889 ;; Do the real thing.
892 (when (reftex-move-to-next-arg)
895 (while (and (member cnt opt-args)
896 (eq (following-char) ?\{))
899 (unless (and (condition-case nil
900 (or (forward-list 1) t)
902 (reftex-move-to-next-arg)
906 (while (and (memq cnt opt-args)
907 (eq (following-char) ?\{))
910 (> (skip-chars-forward "{\\[") 0))
911 (reftex-context-substring)
914 (defun reftex-move-over-touching-args ()
916 (while (memq (following-char) '(?\[ ?\{))
920 (defun reftex-context-substring (&optional to-end)
921 ;; Return up to 150 chars from point
922 ;; When point is just after a { or [, limit string to matching parenthesis
925 ;; Environment - find next \end
926 (buffer-substring-no-properties
930 ;; FIXME: THis is not perfect
931 (if (re-search-forward "\\\\end{" nil t)
934 ((or (= (preceding-char) ?\{)
935 (= (preceding-char) ?\[))
936 ;; Inside a list - get only the list.
937 (buffer-substring-no-properties
945 (error (point-max))))))
947 ;; no list - just grab 150 characters
948 (buffer-substring-no-properties (point)
949 (min (+ (point) 150) (point-max))))))
951 ;; Variable holding the vector with section numbers
952 (defvar reftex-section-numbers (make-vector reftex-max-section-depth 0))
954 (defun reftex-init-section-numbers (&optional toc-entry appendix)
955 ;; Initialize the section numbers with zeros or with what is found
957 (let* ((level (or (nth 5 toc-entry) -1))
958 (numbers (nreverse (split-string (or (nth 6 toc-entry) "") "\\.")))
959 (depth (1- (length reftex-section-numbers)))
960 (i depth) number-string)
963 (aset reftex-section-numbers i 0)
964 (setq number-string (or (car numbers) "0"))
965 (if (string-match "\\`[A-Z]\\'" number-string)
966 (aset reftex-section-numbers i
967 (- (string-to-char number-string) ?A -1))
968 (aset reftex-section-numbers i (string-to-int number-string)))
971 (put 'reftex-section-numbers 'appendix appendix))
973 (defun reftex-section-number (&optional level star)
974 ;; Return a string with the current section number.
975 ;; When LEVEL is non-nil, increase section numbers on that level.
976 (let* ((depth (1- (length reftex-section-numbers))) idx n (string "")
977 (appendix (get 'reftex-section-numbers 'appendix)))
979 (when (and (> level -1) (not star))
980 (aset reftex-section-numbers
981 level (1+ (aref reftex-section-numbers level))))
982 (setq idx (1+ level))
984 (while (<= idx depth)
985 (aset reftex-section-numbers idx 0)
988 (while (<= idx depth)
989 (setq n (aref reftex-section-numbers idx))
990 (setq string (concat string (if (not (string= string "")) "." "")
994 (if (string-match "\\`\\([@0]\\.\\)+" string)
995 (setq string (replace-match "" nil nil string)))
996 (if (string-match "\\(\\.0\\)+\\'" string)
997 (setq string (replace-match "" nil nil string)))
999 (string-match "\\`[0-9]+" string))
1003 (1- (+ ?A (string-to-int (match-string 0 string)))))
1004 (substring string (match-end 0))))))
1006 (concat (make-string (1- (length string)) ?\ ) "*")
1009 ;;; reftex-parse.el ends here