1 ;;; reftex-parse.el - Parser Functions for RefTeX
2 ;; Copyright (c) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
4 ;; Author: Carsten Dominik <dominik@strw.LeidenUniv.nl>
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 2, or (at your option)
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; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
25 (eval-when-compile (require 'cl))
26 (provide 'reftex-parse)
29 (defmacro reftex-with-special-syntax (&rest body)
30 `(let ((saved-syntax (syntax-table)))
33 (set-syntax-table reftex-syntax-table)
35 (set-syntax-table saved-syntax))))
37 (defun reftex-parse-one ()
40 (let ((reftex-enable-partial-scans t))
41 (reftex-access-scan-info '(4))))
43 (defun reftex-parse-all ()
44 "Re-parse entire document."
46 (reftex-access-scan-info '(16)))
48 (defun reftex-do-parse (rescan &optional file)
49 "Do a document rescan. When allowed, do only a partial scan from FILE."
51 ;; Normalize the rescan argument
52 (setq rescan (cond ((eq rescan t) t)
54 ((equal rescan '(4)) t)
55 ((equal rescan '(16)) 1)
58 ;; Partial scans only when allowed
59 (unless reftex-enable-partial-scans
64 (let* ((old-list (symbol-value reftex-docstruct-symbol))
65 (master (reftex-TeX-master-file))
66 (true-master (file-truename master))
67 (master-dir (file-name-as-directory (file-name-directory master)))
68 (file (or file (buffer-file-name)))
69 (true-file (file-truename file))
70 (bibview-cache (assq 'bibview-cache old-list))
71 (index-tags (cdr (assq 'index-tags old-list)))
72 from-file appendix docstruct tmp)
74 ;; Make sure replacement is really an option here
75 (when (and (eq rescan t)
76 (not (and (member (list 'bof file) old-list)
77 (member (list 'eof file) old-list))))
78 ;; Scan whole document because no such file section exists
80 (when (string= true-file true-master)
81 ;; Scan whole document because this file is the master
84 ;; From which file do we start?
86 (cond ((eq rescan t) (or file master))
87 ((eq rescan 1) master)
88 (t (error "This should not happen (reftex-do-parse)"))))
90 ;; Reset index-tags if we scan everything
91 (if (equal rescan 1) (setq index-tags nil))
93 ;; Find active toc entry and initialize section-numbers
94 (setq reftex-active-toc (reftex-last-assoc-before-elt
95 'toc (list 'bof from-file) old-list)
96 appendix (reftex-last-assoc-before-elt
97 'appendix (list 'bof from-file) old-list))
99 (reftex-init-section-numbers reftex-active-toc appendix)
102 (message "Scanning entire document...")
103 (message "Scanning document from %s..." from-file))
105 (reftex-with-special-syntax
106 (save-window-excursion
110 (reftex-parse-from-file
111 from-file docstruct master-dir))
112 (reftex-kill-temporary-buffers)))))
114 (message "Scanning document... done")
116 ;; Turn the list around.
117 (setq docstruct (nreverse docstruct))
120 (setq docstruct (reftex-replace-label-list-segment
121 old-list docstruct (eq rescan 1)))
123 ;; Add all missing information
124 (unless (assq 'label-numbers docstruct)
125 (push (cons 'label-numbers nil) docstruct))
126 (unless (assq 'master-dir docstruct)
127 (push (cons 'master-dir master-dir) docstruct))
128 (unless (assq 'bibview-cache docstruct)
129 (push (cons 'bibview-cache (cdr bibview-cache)) docstruct))
130 (let* ((bof1 (memq (assq 'bof docstruct) docstruct))
131 (bof2 (assq 'bof (cdr bof1)))
132 (is-multi (not (not (and bof1 bof2))))
133 (entry (or (assq 'is-multi docstruct)
134 (car (push (list 'is-multi is-multi) docstruct)))))
135 (setcdr entry (cons is-multi nil)))
136 (and index-tags (setq index-tags (sort index-tags 'string<)))
137 (let ((index-tag-cell (assq 'index-tags docstruct)))
139 (setcdr index-tag-cell index-tags)
140 (push (cons 'index-tags index-tags) docstruct)))
141 (unless (assq 'xr docstruct)
142 (let* ((allxr (reftex-all-assq 'xr-doc docstruct))
145 (if (setq tmp (reftex-locate-file (nth 2 x) "tex"
148 (message "Can't find external document %s"
152 (alist (delq nil alist))
153 (allprefix (delq nil (mapcar 'car alist)))
154 (regexp (if allprefix
156 (mapconcat 'identity allprefix "\\|")
158 "\\\\\\\\\\\\"))) ; this will never match
159 (push (list 'xr alist regexp) docstruct)))
161 (set reftex-docstruct-symbol docstruct)
162 (put reftex-docstruct-symbol 'modified t)))
164 (defun reftex-everything-regexp ()
165 (if reftex-support-index
166 reftex-everything-regexp
167 reftex-everything-regexp-no-index))
169 (defun reftex-all-document-files (&optional relative)
170 "Return a list of all files belonging to the current document.
171 When RELATIVE is non-nil, give file names relative to directory
173 (let* ((all (symbol-value reftex-docstruct-symbol))
174 (master-dir (file-name-directory (reftex-TeX-master-file)))
175 (re (concat "\\`" (regexp-quote master-dir)))
177 (while (setq tmp (assoc 'bof all))
178 (setq file (nth 1 tmp)
179 all (cdr (memq tmp all)))
181 (string-match re file)
182 (setq file (substring file (match-end 0))))
183 (push file file-list))
184 (nreverse file-list)))
186 (defun reftex-parse-from-file (file docstruct master-dir)
187 ;; Scan the buffer for labels and save them in a list.
188 (let ((regexp (reftex-everything-regexp))
190 file-found tmp include-file
193 toc-entry index-entry next-buf buf)
196 (setq file-found (reftex-locate-file file "tex" master-dir))
197 (if (and (not file-found)
198 (setq buf (reftex-get-buffer-visiting file)))
199 (setq file-found (buffer-file-name buf)))
202 (push (list 'file-error file) docstruct)
207 (message "Scanning file %s" file)
210 (reftex-get-file-buffer-force
212 (not (eq t reftex-keep-temporary-buffers)))))
214 ;; Begin of file mark
215 (setq file (buffer-file-name))
216 (push (list 'bof file) docstruct)
218 (reftex-with-special-syntax
224 (while (re-search-forward regexp nil t)
230 (push (reftex-label-info (reftex-match-string 1) file bound)
238 (setq toc-entry (reftex-section-info file))
240 ;; It can happen that section info returns nil
241 (setq level (nth 5 toc-entry))
242 (setq highest-level (min highest-level level))
243 (if (= level highest-level)
246 (car (rassoc level reftex-section-levels-all))
249 (push toc-entry docstruct)
250 (setq reftex-active-toc toc-entry)))
253 ;; It's an include or input
254 (setq include-file (reftex-match-string 7))
255 ;; Test if this file should be ignored
256 (unless (delq nil (mapcar
257 (lambda (x) (string-match x include-file))
258 reftex-no-include-regexps))
261 (reftex-parse-from-file
263 docstruct master-dir))))
266 ;; Appendix starts here
267 (reftex-init-section-numbers nil t)
268 (push (cons 'appendix t) docstruct))
272 (when reftex-support-index
273 (setq index-entry (reftex-index-info file))
275 (add-to-list 'index-tags (nth 1 index-entry))
276 (push index-entry docstruct))))
279 ;; A macro with label
281 (let* ((mac (reftex-match-string 11))
282 (label (progn (goto-char (match-end 11))
285 (reftex-nth-arg-wrapper
287 (typekey (nth 1 (assoc mac reftex-env-or-mac-alist)))
288 (entry (progn (if typekey
290 (goto-char (match-end 0))
292 (goto-char (match-end 11))
293 (reftex-move-over-touching-args))
295 label file bound nil nil))))
296 (push entry docstruct))))
297 (t (error "This should not happen (reftex-parse-from-file)")))
300 ;; Find bibliography statement
301 (when (setq tmp (reftex-locate-bibliography-files master-dir))
302 (push (cons 'bib tmp) docstruct))
305 (when (re-search-forward
306 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\begin{thebibliography}" nil t)
307 (push (cons 'thebib file) docstruct))
309 ;; Find external document specifications
311 (while (re-search-forward "[\n\r][ \t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t)
312 (push (list 'xr-doc (reftex-match-string 2)
313 (reftex-match-string 3))
317 (push (list 'eof file) docstruct)))))
319 ;; Kill the scanned buffer
320 (reftex-kill-temporary-buffers next-buf))
325 (defun reftex-locate-bibliography-files (master-dir &optional files)
326 ;; Scan buffer for bibliography macro and return file list.
330 (goto-char (point-min))
331 (if (re-search-forward
332 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\bibliography{[ \t]*\\([^}]+\\)" nil t)
334 (split-string (reftex-match-string 2)
335 "[ \t\n\r]*,[ \t\n\r]*")))))
340 (if (or (member x reftex-bibfile-ignore-list)
341 (delq nil (mapcar (lambda (re) (string-match re x))
342 reftex-bibfile-ignore-regexps)))
346 (reftex-locate-file x "bib" master-dir)))
350 (defun reftex-replace-label-list-segment (old insert &optional entirely)
351 ;; Replace the segment in OLD which corresponds to INSERT.
352 ;; Works with side effects, directly changes old.
353 ;; If entirely is t, just return INSERT.
354 ;; This function also makes sure the old toc markers do not point anywhere.
358 (reftex-silence-toc-markers old (length old))
361 (file (nth 1 (car insert)))
362 (eof-list (member (list 'eof file) old))
363 (bof-list (member (list 'bof file) old))
365 (if (not (and bof-list eof-list))
366 (error "Cannot splice")
368 (reftex-silence-toc-markers bof-list (- (length bof-list)
370 (setq n (- (length old) (length bof-list)))
371 (setcdr (nthcdr n new) (cdr insert))
372 (setcdr (nthcdr (1- (length new)) new) (cdr eof-list)))
375 (defun reftex-section-info (file)
376 ;; Return a section entry for the current match.
377 ;; Carefull: This function expects the match-data to be still in place!
378 (let* ((marker (set-marker (make-marker) (1- (match-beginning 3))))
379 (macro (reftex-match-string 3))
380 (prefix (save-match-data
381 (if (string-match "begin{\\([^}]+\\)}" macro)
382 (match-string 1 macro))))
383 (level-exp (cdr (assoc macro reftex-section-levels-all)))
384 (level (if (symbolp level-exp)
385 (save-match-data (funcall level-exp))
387 (star (= ?* (char-after (match-end 3))))
388 (unnumbered (or star (< level 0)))
390 (section-number (reftex-section-number level unnumbered))
391 (text1 (save-match-data
393 (reftex-context-substring prefix))))
394 (literal (buffer-substring-no-properties
395 (1- (match-beginning 3))
396 (min (point-max) (+ (match-end 0) (length text1) 1))))
397 ;; Literal can be too short since text1 too short. No big problem.
398 (text (reftex-nicify-text text1)))
400 ;; Add section number and indentation
403 (make-string (* reftex-level-indent level) ?\ )
404 (if (nth 1 reftex-label-menu-flags) ; section number flag
405 (concat section-number " "))
406 (if prefix (concat (capitalize prefix) ": ") "")
408 (list 'toc "toc" text file marker level section-number
409 literal (marker-position marker))))
411 (defun reftex-ensure-index-support (&optional abort)
412 ;; When index support is turned off, ask to turn it on and
413 ;; set the current prefix argument so that `reftex-access-scan-info'
414 ;; will rescan the entire document.
416 (reftex-support-index t)
417 ((y-or-n-p "Turn on index support and rescan entire document? ")
418 (setq reftex-support-index 'demanded
419 current-prefix-arg '(16)))
421 (error "No index support")
422 (message "No index support")
426 (defun reftex-index-info-safe (file)
427 (reftex-with-special-syntax
428 (reftex-index-info file)))
431 (defun reftex-index-info (file)
432 ;; Return an index entry for the current match.
433 ;; Carefull: This function expects the match-data to be still in place!
435 (let* ((macro (reftex-match-string 10))
436 (bom (match-beginning 10))
438 (entry (or (assoc macro reftex-index-macro-alist)
440 (exclude (nth 3 entry))
441 ;; The following is a test if this match should be excluded
442 (test-dummy (and (fboundp exclude)
446 (prefix (nth 2 entry))
448 (cond ((stringp itag) itag)
450 (progn (goto-char boa)
451 (or (reftex-nth-arg itag (nth 6 entry)) "idx")))
453 (arg (or (progn (goto-char boa)
454 (reftex-nth-arg (nth 5 entry) (nth 6 entry)))
456 (end-of-args (progn (goto-char boa)
457 (reftex-move-over-touching-args)
459 (end-of-context (progn (skip-chars-forward "^ \t\n\r") (point)))
461 (progn (goto-char bom)
462 (skip-chars-backward "^ \t\r\n")
464 (context (buffer-substring-no-properties
465 begin-of-context end-of-context))
466 (key-end (if (string-match reftex-index-key-end-re arg)
467 (1+ (match-beginning 0))))
468 (rawkey (substring arg 0 key-end))
470 (key (if prefix (concat prefix rawkey) rawkey))
471 (sortkey (downcase key))
472 (showkey (mapconcat 'identity
473 (split-string key reftex-index-level-re)
475 (goto-char end-of-args)
476 ;; 0 1 2 3 4 5 6 7 8 9
477 (list 'index index-tag context file bom arg key showkey sortkey key-end))))
479 (defun reftex-short-context (env parse &optional bound derive)
480 ;; Get about one line of useful context for the label definition at point.
483 (setq parse (if derive (cdr parse) (car parse))))
491 (reftex-context-substring)))
494 (if (string= env "section")
495 ;; special treatment for section labels
497 (if (and (re-search-backward reftex-section-or-include-regexp
501 (goto-char (match-end 0))
502 (reftex-context-substring))
503 (if reftex-active-toc
505 (string-match "{\\([^}]*\\)" (nth 7 reftex-active-toc))
506 (match-string 1 (nth 7 reftex-active-toc)))
507 "SECTION HEADING NOT FOUND")))
509 (goto-char reftex-default-context-position)
510 (unless (eq (string-to-char env) ?\\)
511 (reftex-move-over-touching-args))
512 (reftex-context-substring))))
516 (if (re-search-backward parse bound t)
518 (goto-char (match-end 0))
519 (reftex-context-substring))
520 "NO MATCH FOR CONTEXT REGEXP")))
524 (goto-char reftex-default-context-position)
527 (nth 6 (assoc env reftex-env-or-mac-alist))))
531 ;; A hook function. Call it.
533 (condition-case error-var
535 (error (format "HOOK ERROR: %s" (cdr error-var))))))
537 "ILLEGAL VALUE OF PARSE"))))
539 (defun reftex-where-am-I ()
540 ;; Return the docstruct entry above point. Actually returns a cons
541 ;; cell in which the cdr is a flag indicating if the information is
542 ;; exact (t) or approximate (nil).
544 (let ((docstruct (symbol-value reftex-docstruct-symbol))
550 (setq found (re-search-backward (reftex-everything-regexp) nil t))
556 (car (member (list 'bof (buffer-file-name)) docstruct))
558 (assq 'bof docstruct) ;; for safety reasons
562 (assoc (reftex-match-string 1)
563 (symbol-value reftex-docstruct-symbol)))
566 (goto-char (1- (match-beginning 3)))
567 (let* ((list (member (list 'bof (buffer-file-name))
569 (endelt (car (member (list 'eof (buffer-file-name))
572 (while (and list (not (eq endelt (car list))))
573 (if (and (eq (car (car list)) 'toc)
574 (string= (buffer-file-name)
578 (or (and (markerp (nth 4 (car list)))
579 (marker-position (nth 4 (car list))))
581 ;; Fits with marker position or recorded position
582 (setq rtn1 (car list) list nil))
583 ((looking-at (reftex-make-regexp-allow-for-ctrl-m
586 (setq rtn1 (car list) list nil cnt 2))))
590 ;; Input or include...
592 (member (list 'eof (reftex-locate-file
593 (reftex-match-string 7) "tex"
594 (cdr (assq 'master-dir docstruct))))
597 (assq 'appendix (symbol-value reftex-docstruct-symbol)))
600 (when reftex-support-index
601 (let* ((index-info (save-excursion
602 (reftex-index-info-safe nil)))
603 (list (member (list 'bof (buffer-file-name))
605 (endelt (car (member (list 'eof (buffer-file-name))
607 dist last-dist last (n 0))
608 ;; Check all index entries with equal text
609 (while (and list (not (eq endelt (car list))))
610 (when (and (eq (car (car list)) 'index)
611 (string= (nth 2 index-info)
614 (setq dist (abs (- (point) (nth 4 (car list)))))
615 (if (or (not last-dist) (< dist last-dist))
616 (setq last-dist dist last (car list))))
617 (setq list (cdr list)))
618 ;; We are sure if we have only one, or a zero distance
619 (cond ((or (= n 1) (= dist 0)) last)
620 ((> n 1) (setq cnt 2) last)
624 (goto-char (match-end 11))
625 (assoc (reftex-no-props
626 (reftex-nth-arg-wrapper
627 (reftex-match-string 11)))
628 (symbol-value reftex-docstruct-symbol))))
630 (error "This should not happen (reftex-where-am-I)"))))))
631 (cons rtn (eq cnt 1))))
633 (defun reftex-notice-new (&optional n force)
634 "Hook to handshake with RefTeX after something new has been inserted."
635 ;; Add a new entry to the docstruct list. If it is a section, renumber
636 ;; the following sections.
637 ;; FIXME: Put in a WHAT parameter
638 ;; When N is given, go back that many matches of reftex-everything-regexp
639 ;; When FORCE is non-nil, also insert if `reftex-where-am-I' was uncertain.
642 (unless reftex-mode (throw 'exit nil))
643 (reftex-access-scan-info)
644 (let* ((docstruct (symbol-value reftex-docstruct-symbol))
645 here-I-am appendix tail entry star level
646 section-number context)
649 (when (re-search-backward (reftex-everything-regexp) nil t (or n 1))
652 (setq here-I-am (reftex-where-am-I))
653 (or here-I-am (throw 'exit nil))
654 (unless (or force (cdr here-I-am)) (throw 'exit nil))
655 (setq tail (memq (car here-I-am) docstruct))
656 (or tail (throw 'exit nil))
657 (setq reftex-active-toc (reftex-last-assoc-before-elt
658 'toc (car here-I-am) docstruct)
659 appendix (reftex-last-assoc-before-elt
660 'appendix (car here-I-am) docstruct))
662 ;; Initialize section numbers
663 (if (eq (car (car here-I-am)) 'appendix)
664 (reftex-init-section-numbers nil t)
665 (reftex-init-section-numbers reftex-active-toc appendix))
667 ;; Match the section command
668 (when (re-search-forward (reftex-everything-regexp) nil t)
671 (push (reftex-label-info (reftex-match-string 1) buffer-file-name)
675 (setq star (= ?* (char-after (match-end 3)))
676 entry (reftex-section-info (buffer-file-name))
678 ;; Insert the section info
679 (push entry (cdr tail))
681 ;; We are done unless we use section numbers
682 (unless (nth 1 reftex-label-menu-flags) (throw 'exit nil))
684 ;; Update the remaining toc items
685 (setq tail (cdr tail))
686 (while (and (setq tail (memq (assq 'toc (cdr tail)) tail))
687 (setq entry (car tail))
688 (>= (nth 5 entry) level))
689 (setq star (string-match "\\*" (nth 6 entry))
690 context (nth 2 entry)
692 (reftex-section-number (nth 5 entry) star))
693 (when (string-match "\\`\\([ \t]*\\)\\([.0-9A-Z]+\\)\\(.*\\)"
695 (when (and (not appendix)
696 (>= (string-to-char (match-string 2)) ?A))
697 ;; Just entered the appendex. Get out.
700 ;; Change the section number.
702 (concat (match-string 1 context)
704 (match-string 3 context))))))
707 (and reftex-support-index
708 (setq entry (reftex-index-info-safe buffer-file-name))
709 ;; FIXME: (add-to-list 'index-tags (nth 1 index-entry))
710 (push entry (cdr tail))))))))))
715 (defsubst reftex-move-to-previous-arg (&optional bound)
716 ;; Assuming that we are in front of a macro argument,
717 ;; move backward to the closing parenthesis of the previous argument.
718 ;; This function understands the splitting of macros over several lines
722 ((memq (preceding-char) '(?\] ?\})))
724 ((and reftex-allow-detached-macro-args
726 "[]}][ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*\\=" bound t))
727 (goto-char (1+ (match-beginning 0)))
731 (defun reftex-what-macro-safe (which &optional bound)
732 ;; reftex-what-macro with special syntax table.
733 (reftex-with-special-syntax
734 (reftex-what-macro which bound)))
736 (defun reftex-what-macro (which &optional bound)
737 ;; Find out if point is within the arguments of any TeX-macro.
738 ;; The return value is either ("\\macro" . (point)) or a list of them.
740 ;; If WHICH is nil, immediately return nil.
741 ;; If WHICH is 1, return innermost enclosing macro.
742 ;; If WHICH is t, return list of all macros enclosing point.
743 ;; If WHICH is a list of macros, look only for those macros and return the
744 ;; name of the first macro in this list found to enclose point.
745 ;; If the optional BOUND is an integer, bound backwards directed
746 ;; searches to this point. If it is nil, limit to nearest \section -
749 ;; This function is pretty stable, but can be fooled if the text contains
750 ;; things like \macro{aa}{bb} where \macro is defined to take only one
751 ;; argument. As RefTeX cannot know this, the string "bb" would still be
752 ;; considered an argument of macro \macro.
754 (unless reftex-section-regexp (reftex-compile-variables))
756 (if (null which) (throw 'exit nil))
757 (let ((bound (or bound (save-excursion (re-search-backward
758 reftex-section-regexp nil 1)
760 pos cmd-list cmd cnt cnt-opt entry)
763 (narrow-to-region (max 1 bound) (point-max))
764 ;; move back out of the current parenthesis
765 (while (condition-case nil
766 (progn (up-list -1) t)
768 (setq cnt 1 cnt-opt 0)
769 ;; move back over any touching sexps
770 (while (and (reftex-move-to-previous-arg bound)
772 (progn (backward-sexp) t)
774 (if (eq (following-char) ?\[) (incf cnt-opt))
777 (when (and (or (= (following-char) ?\[)
778 (= (following-char) ?\{))
779 (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t))
780 (setq cmd (reftex-match-string 0))
781 (when (looking-at "\\\\begin{[^}]*}")
782 (setq cmd (reftex-match-string 0)
784 ;; This does ignore optional arguments. Very hard to fix.
785 (when (setq entry (assoc cmd reftex-env-or-mac-alist))
786 (if (> cnt (or (nth 4 entry) 100))
791 (push (cons cmd (point)) cmd-list))
792 ((or (eq 1 which) (member cmd which))
793 (throw 'exit (cons cmd (point))))))
795 (nreverse cmd-list)))))
797 (defun reftex-what-environment (which &optional bound)
798 ;; Find out if point is inside a LaTeX environment.
799 ;; The return value is (e.g.) either ("equation" . (point)) or a list of
802 ;; If WHICH is nil, immediately return nil.
803 ;; If WHICH is 1, return innermost enclosing environment.
804 ;; If WHICH is t, return list of all environments enclosing point.
805 ;; If WHICH is a list of environments, look only for those environments and
806 ;; return the name of the first environment in this list found to enclose
809 ;; If the optional BOUND is an integer, bound backwards directed searches to
810 ;; this point. If it is nil, limit to nearest \section - like statement.
812 (unless reftex-section-regexp (reftex-compile-variables))
815 (if (null which) (throw 'exit nil))
816 (let ((bound (or bound (save-excursion (re-search-backward
817 reftex-section-regexp nil 1)
819 env-list end-list env)
820 (while (re-search-backward "\\\\\\(begin\\|end\\){\\([^}]+\\)}"
822 (setq env (buffer-substring-no-properties
823 (match-beginning 2) (match-end 2)))
825 ((string= (match-string 1) "end")
827 ((equal env (car end-list))
828 (setq end-list (cdr end-list)))
830 (push (cons env (point)) env-list))
831 ((or (eq 1 which) (member env which))
832 (throw 'exit (cons env (point))))))
833 (nreverse env-list)))))
835 (defun reftex-what-special-env (which &optional bound)
836 ;; Run the special environment parsers and return the matches.
838 ;; The return value is (e.g.) either ("my-parser-function" . (point))
839 ;; or a list of them.
841 ;; If WHICH is nil, immediately return nil.
842 ;; If WHICH is 1, return innermost enclosing environment.
843 ;; If WHICH is t, return list of all environments enclosing point.
844 ;; If WHICH is a list of environments, look only for those environments and
845 ;; return the name of the first environment in this list found to enclose
848 (unless reftex-section-regexp (reftex-compile-variables))
851 (if (null reftex-special-env-parsers) (throw 'exit nil))
852 (if (null which) (throw 'exit nil))
853 (let ((bound (or bound (save-excursion (re-search-backward
854 reftex-section-regexp nil 1)
856 (fun-list (if (listp which)
857 (mapcar (lambda (x) (if (memq x which) x nil))
858 reftex-special-env-parsers)
859 reftex-special-env-parsers))
861 ;; Call all functions
862 (setq specials (mapcar
865 (setq rtn (and fun (funcall fun bound)))
866 (if rtn (cons (symbol-name fun) rtn) nil)))
868 ;; Delete the non-matches
869 (setq specials (delq nil specials))
871 (setq specials (sort specials (lambda (a b) (> (cdr a) (cdr b)))))
876 (defsubst reftex-move-to-next-arg (&optional ignore)
877 ;; Assuming that we are at the end of a macro name or a macro argument,
878 ;; move forward to the opening parenthesis of the next argument.
879 ;; This function understands the splitting of macros over several lines
883 ((memq (following-char) '(?\[ ?\{)))
885 ((and reftex-allow-detached-macro-args
886 (looking-at "[ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*[[{]"))
887 (goto-char (1- (match-end 0)))
891 (defun reftex-nth-arg-wrapper (key)
892 (let ((entry (assoc key reftex-env-or-mac-alist)))
893 (reftex-nth-arg (nth 5 entry) (nth 6 entry))))
895 (defun reftex-nth-arg (n &optional opt-args)
896 ;; Return the nth following {} or [] parentheses content.
897 ;; OPT-ARGS is a list of argument numbers which are optional.
899 ;; If we are sitting at a macro start, skip to end of macro name.
900 (and (eq (following-char) ?\\) (skip-chars-forward "a-zA-Z*\\\\"))
903 ;; Special case: Skip all touching arguments
905 (reftex-move-over-touching-args)
906 (reftex-context-substring))
908 ;; Do the real thing.
911 (when (reftex-move-to-next-arg)
914 (while (and (member cnt opt-args)
915 (eq (following-char) ?\{))
918 (unless (and (condition-case nil
919 (or (forward-list 1) t)
921 (reftex-move-to-next-arg)
925 (while (and (memq cnt opt-args)
926 (eq (following-char) ?\{))
929 (> (skip-chars-forward "{\\[") 0))
930 (reftex-context-substring)
933 (defun reftex-move-over-touching-args ()
935 (while (memq (following-char) '(?\[ ?\{))
939 (defun reftex-context-substring (&optional to-end)
940 ;; Return up to 150 chars from point
941 ;; When point is just after a { or [, limit string to matching parenthesis
944 ;; Environment - find next \end
945 (buffer-substring-no-properties
949 ;; FIXME: THis is not perfect
950 (if (re-search-forward "\\\\end{" nil t)
953 ((or (= (preceding-char) ?\{)
954 (= (preceding-char) ?\[))
955 ;; Inside a list - get only the list.
956 (buffer-substring-no-properties
964 (error (point-max))))))
966 ;; no list - just grab 150 characters
967 (buffer-substring-no-properties (point)
968 (min (+ (point) 150) (point-max))))))
970 ;; Variable holding the vector with section numbers
971 (defvar reftex-section-numbers (make-vector reftex-max-section-depth 0))
973 (defun reftex-init-section-numbers (&optional toc-entry appendix)
974 ;; Initialize the section numbers with zeros or with what is found
976 (let* ((level (or (nth 5 toc-entry) -1))
977 (numbers (nreverse (split-string (or (nth 6 toc-entry) "") "\\.")))
978 (depth (1- (length reftex-section-numbers)))
979 (i depth) number-string)
982 (aset reftex-section-numbers i 0)
983 (setq number-string (or (car numbers) "0"))
984 (if (string-match "\\`[A-Z]\\'" number-string)
985 (aset reftex-section-numbers i
986 (- (string-to-char number-string) ?A -1))
987 (aset reftex-section-numbers i (string-to-int number-string)))
990 (put 'reftex-section-numbers 'appendix appendix))
992 (defun reftex-section-number (&optional level star)
993 ;; Return a string with the current section number.
994 ;; When LEVEL is non-nil, increase section numbers on that level.
995 (let* ((depth (1- (length reftex-section-numbers))) idx n (string "")
996 (appendix (get 'reftex-section-numbers 'appendix)))
998 (when (and (> level -1) (not star))
999 (aset reftex-section-numbers
1000 level (1+ (aref reftex-section-numbers level))))
1001 (setq idx (1+ level))
1003 (while (<= idx depth)
1004 (aset reftex-section-numbers idx 0)
1007 (while (<= idx depth)
1008 (setq n (aref reftex-section-numbers idx))
1009 (setq string (concat string (if (not (string= string "")) "." "")
1013 (if (string-match "\\`\\([@0]\\.\\)+" string)
1014 (setq string (replace-match "" nil nil string)))
1015 (if (string-match "\\(\\.0\\)+\\'" string)
1016 (setq string (replace-match "" nil nil string)))
1018 (string-match "\\`[0-9]+" string))
1022 (1- (+ ?A (string-to-int (match-string 0 string)))))
1023 (substring string (match-end 0))))))
1025 (concat (make-string (1- (length string)) ?\ ) "*")
1028 ;;; reftex-parse.el ends here