1 ;;; reftex-parse.el --- parser functions for RefTeX
3 ;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 ;; 2006, 2007 Free Software Foundation, Inc.
6 ;; Author: Carsten Dominik <dominik@science.uva.nl>
7 ;; Maintainer: auctex-devel@gnu.org
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
31 (eval-when-compile (require 'cl))
32 (provide 'reftex-parse)
35 (defmacro reftex-with-special-syntax (&rest body)
36 `(let ((saved-syntax (syntax-table)))
39 (set-syntax-table reftex-syntax-table)
40 (let ((case-fold-search nil))
42 (set-syntax-table saved-syntax))))
44 (defun reftex-parse-one ()
47 (let ((reftex-enable-partial-scans t))
48 (reftex-access-scan-info '(4))))
50 (defun reftex-parse-all ()
51 "Re-parse entire document."
53 (reftex-access-scan-info '(16)))
55 (defun reftex-do-parse (rescan &optional file)
56 "Do a document rescan. When allowed, do only a partial scan from FILE."
58 ;; Normalize the rescan argument
59 (setq rescan (cond ((eq rescan t) t)
61 ((equal rescan '(4)) t)
62 ((equal rescan '(16)) 1)
65 ;; Partial scans only when allowed
66 (unless reftex-enable-partial-scans
71 (let* ((old-list (symbol-value reftex-docstruct-symbol))
72 (master (reftex-TeX-master-file))
73 (true-master (file-truename master))
74 (master-dir (file-name-as-directory (file-name-directory master)))
75 (file (or file (buffer-file-name)))
76 (true-file (file-truename file))
77 (bibview-cache (assq 'bibview-cache old-list))
78 (index-tags (cdr (assq 'index-tags old-list)))
79 from-file appendix docstruct tmp)
81 ;; Make sure replacement is really an option here
82 (when (and (eq rescan t)
83 (not (and (member (list 'bof file) old-list)
84 (member (list 'eof file) old-list))))
85 ;; Scan whole document because no such file section exists
87 (when (string= true-file true-master)
88 ;; Scan whole document because this file is the master
91 ;; From which file do we start?
93 (cond ((eq rescan t) (or file master))
94 ((eq rescan 1) master)
95 (t (error "This should not happen (reftex-do-parse)"))))
97 ;; Reset index-tags if we scan everything
98 (if (equal rescan 1) (setq index-tags nil))
100 ;; Find active toc entry and initialize section-numbers
101 (setq reftex-active-toc (reftex-last-assoc-before-elt
102 'toc (list 'bof from-file) old-list)
103 appendix (reftex-last-assoc-before-elt
104 'appendix (list 'bof from-file) old-list))
106 (reftex-init-section-numbers reftex-active-toc appendix)
109 (message "Scanning entire document...")
110 (message "Scanning document from %s..." from-file))
112 (reftex-with-special-syntax
113 (save-window-excursion
117 (reftex-parse-from-file
118 from-file docstruct master-dir))
119 (reftex-kill-temporary-buffers)))))
121 (message "Scanning document... done")
123 ;; Turn the list around.
124 (setq docstruct (nreverse docstruct))
127 (setq docstruct (reftex-replace-label-list-segment
128 old-list docstruct (eq rescan 1)))
130 ;; Add all missing information
131 (unless (assq 'label-numbers docstruct)
132 (push (cons 'label-numbers nil) docstruct))
133 (unless (assq 'master-dir docstruct)
134 (push (cons 'master-dir master-dir) docstruct))
135 (unless (assq 'bibview-cache docstruct)
136 (push (cons 'bibview-cache (cdr bibview-cache)) docstruct))
137 (let* ((bof1 (memq (assq 'bof docstruct) docstruct))
138 (bof2 (assq 'bof (cdr bof1)))
139 (is-multi (not (not (and bof1 bof2))))
140 (entry (or (assq 'is-multi docstruct)
141 (car (push (list 'is-multi is-multi) docstruct)))))
142 (setcdr entry (cons is-multi nil)))
143 (and index-tags (setq index-tags (sort index-tags 'string<)))
144 (let ((index-tag-cell (assq 'index-tags docstruct)))
146 (setcdr index-tag-cell index-tags)
147 (push (cons 'index-tags index-tags) docstruct)))
148 (unless (assq 'xr docstruct)
149 (let* ((allxr (reftex-all-assq 'xr-doc docstruct))
152 (if (setq tmp (reftex-locate-file (nth 2 x) "tex"
155 (message "Can't find external document %s"
159 (alist (delq nil alist))
160 (allprefix (delq nil (mapcar 'car alist)))
161 (regexp (if allprefix
163 (mapconcat 'identity allprefix "\\|")
165 "\\\\\\\\\\\\"))) ; this will never match
166 (push (list 'xr alist regexp) docstruct)))
168 (set reftex-docstruct-symbol docstruct)
169 (put reftex-docstruct-symbol 'modified t)))
171 (defun reftex-everything-regexp ()
172 (if reftex-support-index
173 reftex-everything-regexp
174 reftex-everything-regexp-no-index))
177 (defun reftex-all-document-files (&optional relative)
178 "Return a list of all files belonging to the current document.
179 When RELATIVE is non-nil, give file names relative to directory
181 (let* ((all (symbol-value reftex-docstruct-symbol))
182 (master-dir (file-name-directory (reftex-TeX-master-file)))
183 (re (concat "\\`" (regexp-quote master-dir)))
185 (while (setq tmp (assoc 'bof all))
186 (setq file (nth 1 tmp)
187 all (cdr (memq tmp all)))
189 (string-match re file)
190 (setq file (substring file (match-end 0))))
191 (push file file-list))
192 (nreverse file-list)))
194 (defun reftex-parse-from-file (file docstruct master-dir)
195 ;; Scan the buffer for labels and save them in a list.
196 (let ((regexp (reftex-everything-regexp))
198 file-found tmp include-file
201 toc-entry index-entry next-buf buf)
204 (setq file-found (reftex-locate-file file "tex" master-dir))
205 (if (and (not file-found)
206 (setq buf (reftex-get-buffer-visiting file)))
207 (setq file-found (buffer-file-name buf)))
210 (push (list 'file-error file) docstruct)
215 (message "Scanning file %s" file)
218 (reftex-get-file-buffer-force
220 (not (eq t reftex-keep-temporary-buffers)))))
222 ;; Begin of file mark
223 (setq file (buffer-file-name))
224 (push (list 'bof file) docstruct)
226 (reftex-with-special-syntax
232 (while (re-search-forward regexp nil t)
238 (push (reftex-label-info (reftex-match-string 1) file bound)
246 (setq toc-entry (reftex-section-info file))
248 ;; It can happen that section info returns nil
249 (setq level (nth 5 toc-entry))
250 (setq highest-level (min highest-level level))
251 (if (= level highest-level)
254 (car (rassoc level reftex-section-levels-all))
257 (push toc-entry docstruct)
258 (setq reftex-active-toc toc-entry)))
261 ;; It's an include or input
262 (setq include-file (reftex-match-string 7))
263 ;; Test if this file should be ignored
264 (unless (delq nil (mapcar
265 (lambda (x) (string-match x include-file))
266 reftex-no-include-regexps))
269 (reftex-parse-from-file
271 docstruct master-dir))))
274 ;; Appendix starts here
275 (reftex-init-section-numbers nil t)
276 (push (cons 'appendix t) docstruct))
280 (when reftex-support-index
281 (setq index-entry (reftex-index-info file))
283 (add-to-list 'index-tags (nth 1 index-entry))
284 (push index-entry docstruct))))
287 ;; A macro with label
289 (let* ((mac (reftex-match-string 11))
290 (label (progn (goto-char (match-end 11))
293 (reftex-nth-arg-wrapper
295 (typekey (nth 1 (assoc mac reftex-env-or-mac-alist)))
296 (entry (progn (if typekey
298 (goto-char (match-end 0))
300 (goto-char (match-end 11))
301 (reftex-move-over-touching-args))
303 label file bound nil nil))))
304 (push entry docstruct))))
305 (t (error "This should not happen (reftex-parse-from-file)")))
308 ;; Find bibliography statement
309 (when (setq tmp (reftex-locate-bibliography-files master-dir))
310 (push (cons 'bib tmp) docstruct))
313 (when (re-search-forward
314 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\begin{thebibliography}" nil t)
315 (push (cons 'thebib file) docstruct))
317 ;; Find external document specifications
319 (while (re-search-forward "[\n\r][ \t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t)
320 (push (list 'xr-doc (reftex-match-string 2)
321 (reftex-match-string 3))
325 (push (list 'eof file) docstruct)))))
327 ;; Kill the scanned buffer
328 (reftex-kill-temporary-buffers next-buf))
333 (defun reftex-locate-bibliography-files (master-dir &optional files)
334 ;; Scan buffer for bibliography macro and return file list.
338 (goto-char (point-min))
339 (if (re-search-forward
341 ; "\\(\\`\\|[\n\r]\\)[^%]*\\\\\\("
342 "\\(^\\)[^%\n\r]*\\\\\\("
343 (mapconcat 'identity reftex-bibliography-commands "\\|")
344 "\\){[ \t]*\\([^}]+\\)") nil t)
346 (split-string (reftex-match-string 3)
347 "[ \t\n\r]*,[ \t\n\r]*")))))
352 (if (or (member x reftex-bibfile-ignore-list)
353 (delq nil (mapcar (lambda (re) (string-match re x))
354 reftex-bibfile-ignore-regexps)))
358 (reftex-locate-file x "bib" master-dir)))
362 (defun reftex-replace-label-list-segment (old insert &optional entirely)
363 ;; Replace the segment in OLD which corresponds to INSERT.
364 ;; Works with side effects, directly changes old.
365 ;; If entirely is t, just return INSERT.
366 ;; This function also makes sure the old toc markers do not point anywhere.
370 (reftex-silence-toc-markers old (length old))
373 (file (nth 1 (car insert)))
374 (eof-list (member (list 'eof file) old))
375 (bof-list (member (list 'bof file) old))
377 (if (not (and bof-list eof-list))
378 (error "Cannot splice")
380 (reftex-silence-toc-markers bof-list (- (length bof-list)
382 (setq n (- (length old) (length bof-list)))
383 (setcdr (nthcdr n new) (cdr insert))
384 (setcdr (nthcdr (1- (length new)) new) (cdr eof-list)))
387 (defun reftex-section-info (file)
388 ;; Return a section entry for the current match.
389 ;; Carefull: This function expects the match-data to be still in place!
390 (let* ((marker (set-marker (make-marker) (1- (match-beginning 3))))
391 (macro (reftex-match-string 3))
392 (prefix (save-match-data
393 (if (string-match "begin{\\([^}]+\\)}" macro)
394 (match-string 1 macro))))
395 (level-exp (cdr (assoc macro reftex-section-levels-all)))
396 (level (if (symbolp level-exp)
397 (save-match-data (funcall level-exp))
399 (star (= ?* (char-after (match-end 3))))
400 (unnumbered (or star (< level 0)))
402 (section-number (reftex-section-number level unnumbered))
403 (text1 (save-match-data
405 (reftex-context-substring prefix))))
406 (literal (buffer-substring-no-properties
407 (1- (match-beginning 3))
408 (min (point-max) (+ (match-end 0) (length text1) 1))))
409 ;; Literal can be too short since text1 too short. No big problem.
410 (text (reftex-nicify-text text1)))
412 ;; Add section number and indentation
415 (make-string (* reftex-level-indent level) ?\ )
416 (if (nth 1 reftex-label-menu-flags) ; section number flag
417 (concat section-number " "))
418 (if prefix (concat (capitalize prefix) ": ") "")
420 (list 'toc "toc" text file marker level section-number
421 literal (marker-position marker))))
423 (defun reftex-ensure-index-support (&optional abort)
424 ;; When index support is turned off, ask to turn it on and
425 ;; set the current prefix argument so that `reftex-access-scan-info'
426 ;; will rescan the entire document.
428 (reftex-support-index t)
429 ((y-or-n-p "Turn on index support and rescan entire document? ")
430 (setq reftex-support-index 'demanded
431 current-prefix-arg '(16)))
433 (error "No index support")
434 (message "No index support")
438 (defun reftex-index-info-safe (file)
439 (reftex-with-special-syntax
440 (reftex-index-info file)))
443 (defun reftex-index-info (file)
444 ;; Return an index entry for the current match.
445 ;; Carefull: This function expects the match-data to be still in place!
447 (let* ((macro (reftex-match-string 10))
448 (bom (match-beginning 10))
450 (entry (or (assoc macro reftex-index-macro-alist)
452 (exclude (nth 3 entry))
453 ;; The following is a test if this match should be excluded
454 (test-dummy (and (fboundp exclude)
458 (prefix (nth 2 entry))
460 (cond ((stringp itag) itag)
462 (progn (goto-char boa)
463 (or (reftex-nth-arg itag (nth 6 entry)) "idx")))
465 (arg (or (progn (goto-char boa)
466 (reftex-nth-arg (nth 5 entry) (nth 6 entry)))
468 (end-of-args (progn (goto-char boa)
469 (reftex-move-over-touching-args)
471 (end-of-context (progn (skip-chars-forward "^ \t\n\r") (point)))
473 (progn (goto-char bom)
474 (skip-chars-backward "^ \t\r\n")
476 (context (buffer-substring-no-properties
477 begin-of-context end-of-context))
478 (key-end (if (string-match reftex-index-key-end-re arg)
479 (1+ (match-beginning 0))))
480 (rawkey (substring arg 0 key-end))
482 (key (if prefix (concat prefix rawkey) rawkey))
483 (sortkey (downcase key))
484 (showkey (mapconcat 'identity
485 (split-string key reftex-index-level-re)
487 (goto-char end-of-args)
488 ;; 0 1 2 3 4 5 6 7 8 9
489 (list 'index index-tag context file bom arg key showkey sortkey key-end))))
491 (defun reftex-short-context (env parse &optional bound derive)
492 ;; Get about one line of useful context for the label definition at point.
495 (setq parse (if derive (cdr parse) (car parse))))
503 (reftex-context-substring)))
506 (if (string= env "section")
507 ;; special treatment for section labels
509 (if (and (re-search-backward reftex-section-or-include-regexp
513 (goto-char (match-end 0))
514 (reftex-context-substring))
515 (if reftex-active-toc
517 (string-match "{\\([^}]*\\)" (nth 7 reftex-active-toc))
518 (match-string 1 (nth 7 reftex-active-toc)))
519 "SECTION HEADING NOT FOUND")))
521 (goto-char reftex-default-context-position)
522 (unless (eq (string-to-char env) ?\\)
523 (reftex-move-over-touching-args))
524 (reftex-context-substring))))
528 (if (re-search-backward parse bound t)
530 (goto-char (match-end 0))
531 (reftex-context-substring))
532 "NO MATCH FOR CONTEXT REGEXP")))
536 (goto-char reftex-default-context-position)
539 (nth 6 (assoc env reftex-env-or-mac-alist))))
543 ;; A hook function. Call it.
545 (condition-case error-var
547 (error (format "HOOK ERROR: %s" (cdr error-var))))))
549 "INVALID VALUE OF PARSE"))))
551 (defun reftex-where-am-I ()
552 ;; Return the docstruct entry above point. Actually returns a cons
553 ;; cell in which the cdr is a flag indicating if the information is
554 ;; exact (t) or approximate (nil).
556 (let ((docstruct (symbol-value reftex-docstruct-symbol))
557 (cnt 0) rtn rtn-if-no-other
562 (setq found (re-search-backward (reftex-everything-regexp) nil t))
568 (car (member (list 'bof (buffer-file-name)) docstruct))
570 (assq 'bof docstruct) ;; for safety reasons
574 (assoc (reftex-match-string 1)
575 (symbol-value reftex-docstruct-symbol)))
578 (goto-char (1- (match-beginning 3)))
579 (let* ((list (member (list 'bof (buffer-file-name))
581 (endelt (car (member (list 'eof (buffer-file-name))
584 (while (and list (not (eq endelt (car list))))
585 (if (and (eq (car (car list)) 'toc)
586 (string= (buffer-file-name)
590 (or (and (markerp (nth 4 (car list)))
591 (marker-position (nth 4 (car list))))
593 ;; Fits with marker position or recorded position
594 (setq rtn1 (car list) list nil))
595 ((looking-at (reftex-make-regexp-allow-for-ctrl-m
597 ;; Same title: remember, but keep looking
598 (setq rtn-if-no-other (car list)))))
602 ;; Input or include...
604 (member (list 'eof (reftex-locate-file
605 (reftex-match-string 7) "tex"
606 (cdr (assq 'master-dir docstruct))))
609 (assq 'appendix (symbol-value reftex-docstruct-symbol)))
612 (when reftex-support-index
613 (let* ((index-info (save-excursion
614 (reftex-index-info-safe nil)))
615 (list (member (list 'bof (buffer-file-name))
617 (endelt (car (member (list 'eof (buffer-file-name))
619 dist last-dist last (n 0))
620 ;; Check all index entries with equal text
621 (while (and list (not (eq endelt (car list))))
622 (when (and (eq (car (car list)) 'index)
623 (string= (nth 2 index-info)
626 (setq dist (abs (- (point) (nth 4 (car list)))))
627 (if (or (not last-dist) (< dist last-dist))
628 (setq last-dist dist last (car list))))
629 (setq list (cdr list)))
630 ;; We are sure if we have only one, or a zero distance
631 (cond ((or (= n 1) (equal dist 0)) last)
632 ((> n 1) (setq cnt 2) last)
636 (goto-char (match-end 11))
637 (assoc (reftex-no-props
638 (reftex-nth-arg-wrapper
639 (reftex-match-string 11)))
640 (symbol-value reftex-docstruct-symbol))))
642 (error "This should not happen (reftex-where-am-I)"))))))
643 ;; Check if there was only a by-name match for the section.
644 (when (and (not rtn) rtn-if-no-other)
645 (setq rtn rtn-if-no-other
647 (cons rtn (eq cnt 1))))
649 (defun reftex-notice-new (&optional n force)
650 "Hook to handshake with RefTeX after something new has been inserted."
651 ;; Add a new entry to the docstruct list. If it is a section, renumber
652 ;; the following sections.
653 ;; FIXME: Put in a WHAT parameter and search backward until one is found.
654 ;; When N is given, go back that many matches of reftex-everything-regexp
655 ;; When FORCE is non-nil, also insert if `reftex-where-am-I' was uncertain.
658 (unless reftex-mode (throw 'exit nil))
659 (reftex-access-scan-info)
660 (let* ((docstruct (symbol-value reftex-docstruct-symbol))
661 here-I-am appendix tail entry star level
662 section-number context)
665 (when (re-search-backward (reftex-everything-regexp) nil t (or n 1))
668 (setq here-I-am (reftex-where-am-I))
669 (or here-I-am (throw 'exit nil))
670 (unless (or force (cdr here-I-am)) (throw 'exit nil))
671 (setq tail (memq (car here-I-am) docstruct))
672 (or tail (throw 'exit nil))
673 (setq reftex-active-toc (reftex-last-assoc-before-elt
674 'toc (car here-I-am) docstruct)
675 appendix (reftex-last-assoc-before-elt
676 'appendix (car here-I-am) docstruct))
678 ;; Initialize section numbers
679 (if (eq (car (car here-I-am)) 'appendix)
680 (reftex-init-section-numbers nil t)
681 (reftex-init-section-numbers reftex-active-toc appendix))
683 ;; Match the section command
684 (when (re-search-forward (reftex-everything-regexp) nil t)
687 (push (reftex-label-info (reftex-match-string 1) buffer-file-name)
691 (setq star (= ?* (char-after (match-end 3)))
692 entry (reftex-section-info (buffer-file-name))
694 ;; Insert the section info
695 (push entry (cdr tail))
697 ;; We are done unless we use section numbers
698 (unless (nth 1 reftex-label-menu-flags) (throw 'exit nil))
700 ;; Update the remaining toc items
701 (setq tail (cdr tail))
702 (while (and (setq tail (memq (assq 'toc (cdr tail)) tail))
703 (setq entry (car tail))
704 (>= (nth 5 entry) level))
705 (setq star (string-match "\\*" (nth 6 entry))
706 context (nth 2 entry)
708 (reftex-section-number (nth 5 entry) star))
709 (when (string-match "\\`\\([ \t]*\\)\\([.0-9A-Z]+\\)\\(.*\\)"
711 (when (and (not appendix)
712 (>= (string-to-char (match-string 2)) ?A))
713 ;; Just entered the appendex. Get out.
716 ;; Change the section number.
718 (concat (match-string 1 context)
720 (match-string 3 context))))))
723 (and reftex-support-index
724 (setq entry (reftex-index-info-safe buffer-file-name))
725 ;; FIXME: (add-to-list 'index-tags (nth 1 index-entry))
726 (push entry (cdr tail))))))))))
731 (defsubst reftex-move-to-previous-arg (&optional bound)
732 ;; Assuming that we are in front of a macro argument,
733 ;; move backward to the closing parenthesis of the previous argument.
734 ;; This function understands the splitting of macros over several lines
738 ((memq (preceding-char) '(?\] ?\})))
740 ((and reftex-allow-detached-macro-args
742 "[]}][ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*\\=" bound t))
743 (goto-char (1+ (match-beginning 0)))
747 (defun reftex-what-macro-safe (which &optional bound)
748 ;; reftex-what-macro with special syntax table.
749 (reftex-with-special-syntax
750 (reftex-what-macro which bound)))
752 (defun reftex-what-macro (which &optional bound)
753 ;; Find out if point is within the arguments of any TeX-macro.
754 ;; The return value is either ("\\macro" . (point)) or a list of them.
756 ;; If WHICH is nil, immediately return nil.
757 ;; If WHICH is 1, return innermost enclosing macro.
758 ;; If WHICH is t, return list of all macros enclosing point.
759 ;; If WHICH is a list of macros, look only for those macros and return the
760 ;; name of the first macro in this list found to enclose point.
761 ;; If the optional BOUND is an integer, bound backwards directed
762 ;; searches to this point. If it is nil, limit to nearest \section -
765 ;; This function is pretty stable, but can be fooled if the text contains
766 ;; things like \macro{aa}{bb} where \macro is defined to take only one
767 ;; argument. As RefTeX cannot know this, the string "bb" would still be
768 ;; considered an argument of macro \macro.
770 (unless reftex-section-regexp (reftex-compile-variables))
772 (if (null which) (throw 'exit nil))
773 (let ((bound (or bound (save-excursion (re-search-backward
774 reftex-section-regexp nil 1)
776 pos cmd-list cmd cnt cnt-opt entry)
779 (narrow-to-region (max 1 bound) (point-max))
780 ;; move back out of the current parenthesis
781 (while (condition-case nil
782 (progn (up-list -1) t)
784 (setq cnt 1 cnt-opt 0)
785 ;; move back over any touching sexps
786 (while (and (reftex-move-to-previous-arg bound)
788 (progn (backward-sexp) t)
790 (if (eq (following-char) ?\[) (incf cnt-opt))
793 (when (and (or (= (following-char) ?\[)
794 (= (following-char) ?\{))
795 (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t))
796 (setq cmd (reftex-match-string 0))
797 (when (looking-at "\\\\begin{[^}]*}")
798 (setq cmd (reftex-match-string 0)
800 ;; This does ignore optional arguments. Very hard to fix.
801 (when (setq entry (assoc cmd reftex-env-or-mac-alist))
802 (if (> cnt (or (nth 4 entry) 100))
807 (push (cons cmd (point)) cmd-list))
808 ((or (eq 1 which) (member cmd which))
809 (throw 'exit (cons cmd (point))))))
811 (nreverse cmd-list)))))
813 (defun reftex-what-environment (which &optional bound)
814 ;; Find out if point is inside a LaTeX environment.
815 ;; The return value is (e.g.) either ("equation" . (point)) or a list of
818 ;; If WHICH is nil, immediately return nil.
819 ;; If WHICH is 1, return innermost enclosing environment.
820 ;; If WHICH is t, return list of all environments enclosing point.
821 ;; If WHICH is a list of environments, look only for those environments and
822 ;; return the name of the first environment in this list found to enclose
825 ;; If the optional BOUND is an integer, bound backwards directed searches to
826 ;; this point. If it is nil, limit to nearest \section - like statement.
828 (unless reftex-section-regexp (reftex-compile-variables))
831 (if (null which) (throw 'exit nil))
832 (let ((bound (or bound (save-excursion (re-search-backward
833 reftex-section-regexp nil 1)
835 env-list end-list env)
836 (while (re-search-backward "\\\\\\(begin\\|end\\){\\([^}]+\\)}"
838 (setq env (buffer-substring-no-properties
839 (match-beginning 2) (match-end 2)))
841 ((string= (match-string 1) "end")
843 ((equal env (car end-list))
844 (setq end-list (cdr end-list)))
846 (push (cons env (point)) env-list))
847 ((or (eq 1 which) (member env which))
848 (throw 'exit (cons env (point))))))
849 (nreverse env-list)))))
851 (defun reftex-what-special-env (which &optional bound)
852 ;; Run the special environment parsers and return the matches.
854 ;; The return value is (e.g.) either ("my-parser-function" . (point))
855 ;; or a list of them.
857 ;; If WHICH is nil, immediately return nil.
858 ;; If WHICH is 1, return innermost enclosing environment.
859 ;; If WHICH is t, return list of all environments enclosing point.
860 ;; If WHICH is a list of environments, look only for those environments and
861 ;; return the name of the first environment in this list found to enclose
864 (unless reftex-section-regexp (reftex-compile-variables))
867 (if (null reftex-special-env-parsers) (throw 'exit nil))
868 (if (null which) (throw 'exit nil))
869 (let ((bound (or bound (save-excursion (re-search-backward
870 reftex-section-regexp nil 1)
872 (fun-list (if (listp which)
873 (mapcar (lambda (x) (if (memq x which) x nil))
874 reftex-special-env-parsers)
875 reftex-special-env-parsers))
877 ;; Call all functions
878 (setq specials (mapcar
881 (setq rtn (and fun (funcall fun bound)))
882 (if rtn (cons (symbol-name fun) rtn) nil)))
884 ;; Delete the non-matches
885 (setq specials (delq nil specials))
887 (setq specials (sort specials (lambda (a b) (> (cdr a) (cdr b)))))
892 (defsubst reftex-move-to-next-arg (&optional ignore)
893 ;; Assuming that we are at the end of a macro name or a macro argument,
894 ;; move forward to the opening parenthesis of the next argument.
895 ;; This function understands the splitting of macros over several lines
899 ((memq (following-char) '(?\[ ?\{)))
901 ((and reftex-allow-detached-macro-args
902 (looking-at "[ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*[[{]"))
903 (goto-char (1- (match-end 0)))
907 (defun reftex-nth-arg-wrapper (key)
908 (let ((entry (assoc key reftex-env-or-mac-alist)))
909 (reftex-nth-arg (nth 5 entry) (nth 6 entry))))
911 (defun reftex-nth-arg (n &optional opt-args)
912 ;; Return the nth following {} or [] parentheses content.
913 ;; OPT-ARGS is a list of argument numbers which are optional.
915 ;; If we are sitting at a macro start, skip to end of macro name.
916 (and (eq (following-char) ?\\) (skip-chars-forward "a-zA-Z*\\\\"))
919 ;; Special case: Skip all touching arguments
921 (reftex-move-over-touching-args)
922 (reftex-context-substring))
924 ;; Do the real thing.
927 (when (reftex-move-to-next-arg)
930 (while (and (member cnt opt-args)
931 (eq (following-char) ?\{))
934 (unless (and (condition-case nil
935 (or (forward-list 1) t)
937 (reftex-move-to-next-arg)
941 (while (and (memq cnt opt-args)
942 (eq (following-char) ?\{))
945 (> (skip-chars-forward "{\\[") 0))
946 (reftex-context-substring)
949 (defun reftex-move-over-touching-args ()
951 (while (memq (following-char) '(?\[ ?\{))
955 (defun reftex-context-substring (&optional to-end)
956 ;; Return up to 150 chars from point
957 ;; When point is just after a { or [, limit string to matching parenthesis
960 ;; Environment - find next \end
961 (buffer-substring-no-properties
965 ;; FIXME: This is not perfect
966 (if (re-search-forward "\\\\end{" nil t)
969 ((or (= (preceding-char) ?\{)
970 (= (preceding-char) ?\[))
971 ;; Inside a list - get only the list.
972 (buffer-substring-no-properties
980 (error (point-max))))))
982 ;; no list - just grab 150 characters
983 (buffer-substring-no-properties (point)
984 (min (+ (point) 150) (point-max))))))
986 ;; Variable holding the vector with section numbers
987 (defvar reftex-section-numbers (make-vector reftex-max-section-depth 0))
989 (defun reftex-init-section-numbers (&optional toc-entry appendix)
990 ;; Initialize the section numbers with zeros or with what is found
992 (let* ((level (or (nth 5 toc-entry) -1))
993 (numbers (nreverse (split-string (or (nth 6 toc-entry) "") "\\.")))
994 (depth (1- (length reftex-section-numbers)))
995 (i depth) number-string)
998 (aset reftex-section-numbers i 0)
999 (setq number-string (or (car numbers) "0"))
1000 (if (string-match "\\`[A-Z]\\'" number-string)
1001 (aset reftex-section-numbers i
1002 (- (string-to-char number-string) ?A -1))
1003 (aset reftex-section-numbers i (string-to-number number-string)))
1006 (put 'reftex-section-numbers 'appendix appendix))
1008 (defun reftex-section-number (&optional level star)
1009 ;; Return a string with the current section number.
1010 ;; When LEVEL is non-nil, increase section numbers on that level.
1011 (let* ((depth (1- (length reftex-section-numbers))) idx n (string "")
1012 (appendix (get 'reftex-section-numbers 'appendix))
1013 (partspecial (and (not reftex-part-resets-chapter)
1015 ;; partspecial means, this is a part statement.
1016 ;; Parts do not reset the chapter counter, and the part number is
1017 ;; not included in the numbering of other sectioning levels.
1019 (when (and (> level -1) (not star))
1020 (aset reftex-section-numbers
1021 level (1+ (aref reftex-section-numbers level))))
1022 (setq idx (1+ level))
1024 (while (<= idx depth)
1025 (if (or (not partspecial)
1027 (aset reftex-section-numbers idx 0))
1030 (setq string (concat "Part " (reftex-roman-number
1031 (aref reftex-section-numbers 0))))
1032 (setq idx (if reftex-part-resets-chapter 0 1))
1033 (while (<= idx depth)
1034 (setq n (aref reftex-section-numbers idx))
1035 (if (not (and partspecial (not (equal string ""))))
1036 (setq string (concat string (if (not (string= string "")) "." "")
1037 (int-to-string n))))
1040 (if (string-match "\\`\\([@0]\\.\\)+" string)
1041 (setq string (replace-match "" nil nil string)))
1042 (if (string-match "\\(\\.0\\)+\\'" string)
1043 (setq string (replace-match "" nil nil string)))
1045 (string-match "\\`[0-9]+" string))
1049 (1- (+ ?A (string-to-number (match-string 0 string)))))
1050 (substring string (match-end 0))))))
1052 (concat (make-string (1- (length string)) ?\ ) "*")
1055 (defun reftex-roman-number (n)
1056 ;; Return as a string the roman number equal to N.
1059 (list '((1000 . "M") ( 900 . "CM") ( 500 . "D") ( 400 . "CD")
1060 ( 100 . "C") ( 90 . "XC") ( 50 . "L") ( 40 . "XL")
1061 ( 10 . "X") ( 9 . "IX") ( 5 . "V") ( 4 . "IV")
1065 (setq listel (pop list)
1069 (setq string (concat string s)
1070 nrest (- nrest i))))
1073 ;;; arch-tag: 6a8168f7-abb9-4576-99dc-fcbc7ba901a3
1074 ;;; reftex-parse.el ends here