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.
29 (eval-when-compile (require 'cl
))
30 (provide 'reftex-parse
)
33 (defmacro reftex-with-special-syntax
(&rest body
)
34 `(let ((saved-syntax (syntax-table)))
37 (set-syntax-table reftex-syntax-table
)
38 (let ((case-fold-search nil
))
40 (set-syntax-table saved-syntax
))))
42 (defun reftex-parse-one ()
45 (let ((reftex-enable-partial-scans t
))
46 (reftex-access-scan-info '(4))))
48 (defun reftex-parse-all ()
49 "Re-parse entire document."
51 (reftex-access-scan-info '(16)))
53 (defun reftex-do-parse (rescan &optional file
)
54 "Do a document rescan. When allowed, do only a partial scan from FILE."
56 ;; Normalize the rescan argument
57 (setq rescan
(cond ((eq rescan t
) t
)
59 ((equal rescan
'(4)) t
)
60 ((equal rescan
'(16)) 1)
63 ;; Partial scans only when allowed
64 (unless reftex-enable-partial-scans
69 (let* ((old-list (symbol-value reftex-docstruct-symbol
))
70 (master (reftex-TeX-master-file))
71 (true-master (file-truename master
))
72 (master-dir (file-name-as-directory (file-name-directory master
)))
73 (file (or file
(buffer-file-name)))
74 (true-file (file-truename file
))
75 (bibview-cache (assq 'bibview-cache old-list
))
76 (index-tags (cdr (assq 'index-tags old-list
)))
77 from-file appendix docstruct tmp
)
79 ;; Make sure replacement is really an option here
80 (when (and (eq rescan t
)
81 (not (and (member (list 'bof file
) old-list
)
82 (member (list 'eof file
) old-list
))))
83 ;; Scan whole document because no such file section exists
85 (when (string= true-file true-master
)
86 ;; Scan whole document because this file is the master
89 ;; From which file do we start?
91 (cond ((eq rescan t
) (or file master
))
92 ((eq rescan
1) master
)
93 (t (error "This should not happen (reftex-do-parse)"))))
95 ;; Reset index-tags if we scan everything
96 (if (equal rescan
1) (setq index-tags nil
))
98 ;; Find active toc entry and initialize section-numbers
99 (setq reftex-active-toc
(reftex-last-assoc-before-elt
100 'toc
(list 'bof from-file
) old-list
)
101 appendix
(reftex-last-assoc-before-elt
102 'appendix
(list 'bof from-file
) old-list
))
104 (reftex-init-section-numbers reftex-active-toc appendix
)
107 (message "Scanning entire document...")
108 (message "Scanning document from %s..." from-file
))
110 (reftex-with-special-syntax
111 (save-window-excursion
115 (reftex-parse-from-file
116 from-file docstruct master-dir
))
117 (reftex-kill-temporary-buffers)))))
119 (message "Scanning document... done")
121 ;; Turn the list around.
122 (setq docstruct
(nreverse docstruct
))
125 (setq docstruct
(reftex-replace-label-list-segment
126 old-list docstruct
(eq rescan
1)))
128 ;; Add all missing information
129 (unless (assq 'label-numbers docstruct
)
130 (push (cons 'label-numbers nil
) docstruct
))
131 (unless (assq 'master-dir docstruct
)
132 (push (cons 'master-dir master-dir
) docstruct
))
133 (unless (assq 'bibview-cache docstruct
)
134 (push (cons 'bibview-cache
(cdr bibview-cache
)) docstruct
))
135 (let* ((bof1 (memq (assq 'bof docstruct
) docstruct
))
136 (bof2 (assq 'bof
(cdr bof1
)))
137 (is-multi (not (not (and bof1 bof2
))))
138 (entry (or (assq 'is-multi docstruct
)
139 (car (push (list 'is-multi is-multi
) docstruct
)))))
140 (setcdr entry
(cons is-multi nil
)))
141 (and index-tags
(setq index-tags
(sort index-tags
'string
<)))
142 (let ((index-tag-cell (assq 'index-tags docstruct
)))
144 (setcdr index-tag-cell index-tags
)
145 (push (cons 'index-tags index-tags
) docstruct
)))
146 (unless (assq 'xr docstruct
)
147 (let* ((allxr (reftex-all-assq 'xr-doc docstruct
))
150 (if (setq tmp
(reftex-locate-file (nth 2 x
) "tex"
153 (message "Can't find external document %s"
157 (alist (delq nil alist
))
158 (allprefix (delq nil
(mapcar 'car alist
)))
159 (regexp (if allprefix
161 (mapconcat 'identity allprefix
"\\|")
163 "\\\\\\\\\\\\"))) ; this will never match
164 (push (list 'xr alist regexp
) docstruct
)))
166 (set reftex-docstruct-symbol docstruct
)
167 (put reftex-docstruct-symbol
'modified t
)))
169 (defun reftex-everything-regexp ()
170 (if reftex-support-index
171 reftex-everything-regexp
172 reftex-everything-regexp-no-index
))
174 (defun reftex-all-document-files (&optional relative
)
175 "Return a list of all files belonging to the current document.
176 When RELATIVE is non-nil, give file names relative to directory
178 (let* ((all (symbol-value reftex-docstruct-symbol
))
179 (master-dir (file-name-directory (reftex-TeX-master-file)))
180 (re (concat "\\`" (regexp-quote master-dir
)))
182 (while (setq tmp
(assoc 'bof all
))
183 (setq file
(nth 1 tmp
)
184 all
(cdr (memq tmp all
)))
186 (string-match re file
)
187 (setq file
(substring file
(match-end 0))))
188 (push file file-list
))
189 (nreverse file-list
)))
191 (defun reftex-parse-from-file (file docstruct master-dir
)
192 ;; Scan the buffer for labels and save them in a list.
193 (let ((regexp (reftex-everything-regexp))
195 file-found tmp include-file
198 toc-entry index-entry next-buf buf
)
201 (setq file-found
(reftex-locate-file file
"tex" master-dir
))
202 (if (and (not file-found
)
203 (setq buf
(reftex-get-buffer-visiting file
)))
204 (setq file-found
(buffer-file-name buf
)))
207 (push (list 'file-error file
) docstruct
)
212 (message "Scanning file %s" file
)
215 (reftex-get-file-buffer-force
217 (not (eq t reftex-keep-temporary-buffers
)))))
219 ;; Begin of file mark
220 (setq file
(buffer-file-name))
221 (push (list 'bof file
) docstruct
)
223 (reftex-with-special-syntax
229 (while (re-search-forward regexp nil t
)
235 (push (reftex-label-info (reftex-match-string 1) file bound
)
243 (setq toc-entry
(reftex-section-info file
))
245 ;; It can happen that section info returns nil
246 (setq level
(nth 5 toc-entry
))
247 (setq highest-level
(min highest-level level
))
248 (if (= level highest-level
)
251 (car (rassoc level reftex-section-levels-all
))
254 (push toc-entry docstruct
)
255 (setq reftex-active-toc toc-entry
)))
258 ;; It's an include or input
259 (setq include-file
(reftex-match-string 7))
260 ;; Test if this file should be ignored
261 (unless (delq nil
(mapcar
262 (lambda (x) (string-match x include-file
))
263 reftex-no-include-regexps
))
266 (reftex-parse-from-file
268 docstruct master-dir
))))
271 ;; Appendix starts here
272 (reftex-init-section-numbers nil t
)
273 (push (cons 'appendix t
) docstruct
))
277 (when reftex-support-index
278 (setq index-entry
(reftex-index-info file
))
280 (add-to-list 'index-tags
(nth 1 index-entry
))
281 (push index-entry docstruct
))))
284 ;; A macro with label
286 (let* ((mac (reftex-match-string 11))
287 (label (progn (goto-char (match-end 11))
290 (reftex-nth-arg-wrapper
292 (typekey (nth 1 (assoc mac reftex-env-or-mac-alist
)))
293 (entry (progn (if typekey
295 (goto-char (match-end 0))
297 (goto-char (match-end 11))
298 (reftex-move-over-touching-args))
300 label file bound nil nil
))))
301 (push entry docstruct
))))
302 (t (error "This should not happen (reftex-parse-from-file)")))
305 ;; Find bibliography statement
306 (when (setq tmp
(reftex-locate-bibliography-files master-dir
))
307 (push (cons 'bib tmp
) docstruct
))
310 (when (re-search-forward
311 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\begin{thebibliography}" nil t
)
312 (push (cons 'thebib file
) docstruct
))
314 ;; Find external document specifications
316 (while (re-search-forward "[\n\r][ \t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t
)
317 (push (list 'xr-doc
(reftex-match-string 2)
318 (reftex-match-string 3))
322 (push (list 'eof file
) docstruct
)))))
324 ;; Kill the scanned buffer
325 (reftex-kill-temporary-buffers next-buf
))
330 (defun reftex-locate-bibliography-files (master-dir &optional files
)
331 ;; Scan buffer for bibliography macro and return file list.
335 (goto-char (point-min))
336 (if (re-search-forward
337 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\\\(no\\)?bibliography{[ \t]*\\([^}]+\\)" nil t
)
339 (split-string (reftex-match-string 3)
340 "[ \t\n\r]*,[ \t\n\r]*")))))
345 (if (or (member x reftex-bibfile-ignore-list
)
346 (delq nil
(mapcar (lambda (re) (string-match re x
))
347 reftex-bibfile-ignore-regexps
)))
351 (reftex-locate-file x
"bib" master-dir
)))
355 (defun reftex-replace-label-list-segment (old insert
&optional entirely
)
356 ;; Replace the segment in OLD which corresponds to INSERT.
357 ;; Works with side effects, directly changes old.
358 ;; If entirely is t, just return INSERT.
359 ;; This function also makes sure the old toc markers do not point anywhere.
363 (reftex-silence-toc-markers old
(length old
))
366 (file (nth 1 (car insert
)))
367 (eof-list (member (list 'eof file
) old
))
368 (bof-list (member (list 'bof file
) old
))
370 (if (not (and bof-list eof-list
))
371 (error "Cannot splice")
373 (reftex-silence-toc-markers bof-list
(- (length bof-list
)
375 (setq n
(- (length old
) (length bof-list
)))
376 (setcdr (nthcdr n new
) (cdr insert
))
377 (setcdr (nthcdr (1- (length new
)) new
) (cdr eof-list
)))
380 (defun reftex-section-info (file)
381 ;; Return a section entry for the current match.
382 ;; Carefull: This function expects the match-data to be still in place!
383 (let* ((marker (set-marker (make-marker) (1- (match-beginning 3))))
384 (macro (reftex-match-string 3))
385 (prefix (save-match-data
386 (if (string-match "begin{\\([^}]+\\)}" macro
)
387 (match-string 1 macro
))))
388 (level-exp (cdr (assoc macro reftex-section-levels-all
)))
389 (level (if (symbolp level-exp
)
390 (save-match-data (funcall level-exp
))
392 (star (= ?
* (char-after (match-end 3))))
393 (unnumbered (or star
(< level
0)))
395 (section-number (reftex-section-number level unnumbered
))
396 (text1 (save-match-data
398 (reftex-context-substring prefix
))))
399 (literal (buffer-substring-no-properties
400 (1- (match-beginning 3))
401 (min (point-max) (+ (match-end 0) (length text1
) 1))))
402 ;; Literal can be too short since text1 too short. No big problem.
403 (text (reftex-nicify-text text1
)))
405 ;; Add section number and indentation
408 (make-string (* reftex-level-indent level
) ?\
)
409 (if (nth 1 reftex-label-menu-flags
) ; section number flag
410 (concat section-number
" "))
411 (if prefix
(concat (capitalize prefix
) ": ") "")
413 (list 'toc
"toc" text file marker level section-number
414 literal
(marker-position marker
))))
416 (defun reftex-ensure-index-support (&optional abort
)
417 ;; When index support is turned off, ask to turn it on and
418 ;; set the current prefix argument so that `reftex-access-scan-info'
419 ;; will rescan the entire document.
421 (reftex-support-index t
)
422 ((y-or-n-p "Turn on index support and rescan entire document? ")
423 (setq reftex-support-index
'demanded
424 current-prefix-arg
'(16)))
426 (error "No index support")
427 (message "No index support")
431 (defun reftex-index-info-safe (file)
432 (reftex-with-special-syntax
433 (reftex-index-info file
)))
436 (defun reftex-index-info (file)
437 ;; Return an index entry for the current match.
438 ;; Carefull: This function expects the match-data to be still in place!
440 (let* ((macro (reftex-match-string 10))
441 (bom (match-beginning 10))
443 (entry (or (assoc macro reftex-index-macro-alist
)
445 (exclude (nth 3 entry
))
446 ;; The following is a test if this match should be excluded
447 (test-dummy (and (fboundp exclude
)
451 (prefix (nth 2 entry
))
453 (cond ((stringp itag
) itag
)
455 (progn (goto-char boa
)
456 (or (reftex-nth-arg itag
(nth 6 entry
)) "idx")))
458 (arg (or (progn (goto-char boa
)
459 (reftex-nth-arg (nth 5 entry
) (nth 6 entry
)))
461 (end-of-args (progn (goto-char boa
)
462 (reftex-move-over-touching-args)
464 (end-of-context (progn (skip-chars-forward "^ \t\n\r") (point)))
466 (progn (goto-char bom
)
467 (skip-chars-backward "^ \t\r\n")
469 (context (buffer-substring-no-properties
470 begin-of-context end-of-context
))
471 (key-end (if (string-match reftex-index-key-end-re arg
)
472 (1+ (match-beginning 0))))
473 (rawkey (substring arg
0 key-end
))
475 (key (if prefix
(concat prefix rawkey
) rawkey
))
476 (sortkey (downcase key
))
477 (showkey (mapconcat 'identity
478 (split-string key reftex-index-level-re
)
480 (goto-char end-of-args
)
481 ;; 0 1 2 3 4 5 6 7 8 9
482 (list 'index index-tag context file bom arg key showkey sortkey key-end
))))
484 (defun reftex-short-context (env parse
&optional bound derive
)
485 ;; Get about one line of useful context for the label definition at point.
488 (setq parse
(if derive
(cdr parse
) (car parse
))))
496 (reftex-context-substring)))
499 (if (string= env
"section")
500 ;; special treatment for section labels
502 (if (and (re-search-backward reftex-section-or-include-regexp
506 (goto-char (match-end 0))
507 (reftex-context-substring))
508 (if reftex-active-toc
510 (string-match "{\\([^}]*\\)" (nth 7 reftex-active-toc
))
511 (match-string 1 (nth 7 reftex-active-toc
)))
512 "SECTION HEADING NOT FOUND")))
514 (goto-char reftex-default-context-position
)
515 (unless (eq (string-to-char env
) ?
\\)
516 (reftex-move-over-touching-args))
517 (reftex-context-substring))))
521 (if (re-search-backward parse bound t
)
523 (goto-char (match-end 0))
524 (reftex-context-substring))
525 "NO MATCH FOR CONTEXT REGEXP")))
529 (goto-char reftex-default-context-position
)
532 (nth 6 (assoc env reftex-env-or-mac-alist
))))
536 ;; A hook function. Call it.
538 (condition-case error-var
540 (error (format "HOOK ERROR: %s" (cdr error-var
))))))
542 "ILLEGAL VALUE OF PARSE"))))
544 (defun reftex-where-am-I ()
545 ;; Return the docstruct entry above point. Actually returns a cons
546 ;; cell in which the cdr is a flag indicating if the information is
547 ;; exact (t) or approximate (nil).
549 (let ((docstruct (symbol-value reftex-docstruct-symbol
))
555 (setq found
(re-search-backward (reftex-everything-regexp) nil t
))
561 (car (member (list 'bof
(buffer-file-name)) docstruct
))
563 (assq 'bof docstruct
) ;; for safety reasons
567 (assoc (reftex-match-string 1)
568 (symbol-value reftex-docstruct-symbol
)))
571 (goto-char (1- (match-beginning 3)))
572 (let* ((list (member (list 'bof
(buffer-file-name))
574 (endelt (car (member (list 'eof
(buffer-file-name))
577 (while (and list
(not (eq endelt
(car list
))))
578 (if (and (eq (car (car list
)) 'toc
)
579 (string= (buffer-file-name)
583 (or (and (markerp (nth 4 (car list
)))
584 (marker-position (nth 4 (car list
))))
586 ;; Fits with marker position or recorded position
587 (setq rtn1
(car list
) list nil
))
588 ((looking-at (reftex-make-regexp-allow-for-ctrl-m
591 (setq rtn1
(car list
) list nil cnt
2))))
595 ;; Input or include...
597 (member (list 'eof
(reftex-locate-file
598 (reftex-match-string 7) "tex"
599 (cdr (assq 'master-dir docstruct
))))
602 (assq 'appendix
(symbol-value reftex-docstruct-symbol
)))
605 (when reftex-support-index
606 (let* ((index-info (save-excursion
607 (reftex-index-info-safe nil
)))
608 (list (member (list 'bof
(buffer-file-name))
610 (endelt (car (member (list 'eof
(buffer-file-name))
612 dist last-dist last
(n 0))
613 ;; Check all index entries with equal text
614 (while (and list
(not (eq endelt
(car list
))))
615 (when (and (eq (car (car list
)) 'index
)
616 (string= (nth 2 index-info
)
619 (setq dist
(abs (- (point) (nth 4 (car list
)))))
620 (if (or (not last-dist
) (< dist last-dist
))
621 (setq last-dist dist last
(car list
))))
622 (setq list
(cdr list
)))
623 ;; We are sure if we have only one, or a zero distance
624 (cond ((or (= n
1) (= dist
0)) last
)
625 ((> n
1) (setq cnt
2) last
)
629 (goto-char (match-end 11))
630 (assoc (reftex-no-props
631 (reftex-nth-arg-wrapper
632 (reftex-match-string 11)))
633 (symbol-value reftex-docstruct-symbol
))))
635 (error "This should not happen (reftex-where-am-I)"))))))
636 (cons rtn
(eq cnt
1))))
638 (defun reftex-notice-new (&optional n force
)
639 "Hook to handshake with RefTeX after something new has been inserted."
640 ;; Add a new entry to the docstruct list. If it is a section, renumber
641 ;; the following sections.
642 ;; FIXME: Put in a WHAT parameter
643 ;; When N is given, go back that many matches of reftex-everything-regexp
644 ;; When FORCE is non-nil, also insert if `reftex-where-am-I' was uncertain.
647 (unless reftex-mode
(throw 'exit nil
))
648 (reftex-access-scan-info)
649 (let* ((docstruct (symbol-value reftex-docstruct-symbol
))
650 here-I-am appendix tail entry star level
651 section-number context
)
654 (when (re-search-backward (reftex-everything-regexp) nil t
(or n
1))
657 (setq here-I-am
(reftex-where-am-I))
658 (or here-I-am
(throw 'exit nil
))
659 (unless (or force
(cdr here-I-am
)) (throw 'exit nil
))
660 (setq tail
(memq (car here-I-am
) docstruct
))
661 (or tail
(throw 'exit nil
))
662 (setq reftex-active-toc
(reftex-last-assoc-before-elt
663 'toc
(car here-I-am
) docstruct
)
664 appendix
(reftex-last-assoc-before-elt
665 'appendix
(car here-I-am
) docstruct
))
667 ;; Initialize section numbers
668 (if (eq (car (car here-I-am
)) 'appendix
)
669 (reftex-init-section-numbers nil t
)
670 (reftex-init-section-numbers reftex-active-toc appendix
))
672 ;; Match the section command
673 (when (re-search-forward (reftex-everything-regexp) nil t
)
676 (push (reftex-label-info (reftex-match-string 1) buffer-file-name
)
680 (setq star
(= ?
* (char-after (match-end 3)))
681 entry
(reftex-section-info (buffer-file-name))
683 ;; Insert the section info
684 (push entry
(cdr tail
))
686 ;; We are done unless we use section numbers
687 (unless (nth 1 reftex-label-menu-flags
) (throw 'exit nil
))
689 ;; Update the remaining toc items
690 (setq tail
(cdr tail
))
691 (while (and (setq tail
(memq (assq 'toc
(cdr tail
)) tail
))
692 (setq entry
(car tail
))
693 (>= (nth 5 entry
) level
))
694 (setq star
(string-match "\\*" (nth 6 entry
))
695 context
(nth 2 entry
)
697 (reftex-section-number (nth 5 entry
) star
))
698 (when (string-match "\\`\\([ \t]*\\)\\([.0-9A-Z]+\\)\\(.*\\)"
700 (when (and (not appendix
)
701 (>= (string-to-char (match-string 2)) ?A
))
702 ;; Just entered the appendex. Get out.
705 ;; Change the section number.
707 (concat (match-string 1 context
)
709 (match-string 3 context
))))))
712 (and reftex-support-index
713 (setq entry
(reftex-index-info-safe buffer-file-name
))
714 ;; FIXME: (add-to-list 'index-tags (nth 1 index-entry))
715 (push entry
(cdr tail
))))))))))
720 (defsubst reftex-move-to-previous-arg
(&optional bound
)
721 ;; Assuming that we are in front of a macro argument,
722 ;; move backward to the closing parenthesis of the previous argument.
723 ;; This function understands the splitting of macros over several lines
727 ((memq (preceding-char) '(?\
] ?\
})))
729 ((and reftex-allow-detached-macro-args
731 "[]}][ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*\\=" bound t
))
732 (goto-char (1+ (match-beginning 0)))
736 (defun reftex-what-macro-safe (which &optional bound
)
737 ;; reftex-what-macro with special syntax table.
738 (reftex-with-special-syntax
739 (reftex-what-macro which bound
)))
741 (defun reftex-what-macro (which &optional bound
)
742 ;; Find out if point is within the arguments of any TeX-macro.
743 ;; The return value is either ("\\macro" . (point)) or a list of them.
745 ;; If WHICH is nil, immediately return nil.
746 ;; If WHICH is 1, return innermost enclosing macro.
747 ;; If WHICH is t, return list of all macros enclosing point.
748 ;; If WHICH is a list of macros, look only for those macros and return the
749 ;; name of the first macro in this list found to enclose point.
750 ;; If the optional BOUND is an integer, bound backwards directed
751 ;; searches to this point. If it is nil, limit to nearest \section -
754 ;; This function is pretty stable, but can be fooled if the text contains
755 ;; things like \macro{aa}{bb} where \macro is defined to take only one
756 ;; argument. As RefTeX cannot know this, the string "bb" would still be
757 ;; considered an argument of macro \macro.
759 (unless reftex-section-regexp
(reftex-compile-variables))
761 (if (null which
) (throw 'exit nil
))
762 (let ((bound (or bound
(save-excursion (re-search-backward
763 reftex-section-regexp nil
1)
765 pos cmd-list cmd cnt cnt-opt entry
)
768 (narrow-to-region (max 1 bound
) (point-max))
769 ;; move back out of the current parenthesis
770 (while (condition-case nil
771 (progn (up-list -
1) t
)
773 (setq cnt
1 cnt-opt
0)
774 ;; move back over any touching sexps
775 (while (and (reftex-move-to-previous-arg bound
)
777 (progn (backward-sexp) t
)
779 (if (eq (following-char) ?\
[) (incf cnt-opt
))
782 (when (and (or (= (following-char) ?\
[)
783 (= (following-char) ?\
{))
784 (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t
))
785 (setq cmd
(reftex-match-string 0))
786 (when (looking-at "\\\\begin{[^}]*}")
787 (setq cmd
(reftex-match-string 0)
789 ;; This does ignore optional arguments. Very hard to fix.
790 (when (setq entry
(assoc cmd reftex-env-or-mac-alist
))
791 (if (> cnt
(or (nth 4 entry
) 100))
796 (push (cons cmd
(point)) cmd-list
))
797 ((or (eq 1 which
) (member cmd which
))
798 (throw 'exit
(cons cmd
(point))))))
800 (nreverse cmd-list
)))))
802 (defun reftex-what-environment (which &optional bound
)
803 ;; Find out if point is inside a LaTeX environment.
804 ;; The return value is (e.g.) either ("equation" . (point)) or a list of
807 ;; If WHICH is nil, immediately return nil.
808 ;; If WHICH is 1, return innermost enclosing environment.
809 ;; If WHICH is t, return list of all environments enclosing point.
810 ;; If WHICH is a list of environments, look only for those environments and
811 ;; return the name of the first environment in this list found to enclose
814 ;; If the optional BOUND is an integer, bound backwards directed searches to
815 ;; this point. If it is nil, limit to nearest \section - like statement.
817 (unless reftex-section-regexp
(reftex-compile-variables))
820 (if (null which
) (throw 'exit nil
))
821 (let ((bound (or bound
(save-excursion (re-search-backward
822 reftex-section-regexp nil
1)
824 env-list end-list env
)
825 (while (re-search-backward "\\\\\\(begin\\|end\\){\\([^}]+\\)}"
827 (setq env
(buffer-substring-no-properties
828 (match-beginning 2) (match-end 2)))
830 ((string= (match-string 1) "end")
832 ((equal env
(car end-list
))
833 (setq end-list
(cdr end-list
)))
835 (push (cons env
(point)) env-list
))
836 ((or (eq 1 which
) (member env which
))
837 (throw 'exit
(cons env
(point))))))
838 (nreverse env-list
)))))
840 (defun reftex-what-special-env (which &optional bound
)
841 ;; Run the special environment parsers and return the matches.
843 ;; The return value is (e.g.) either ("my-parser-function" . (point))
844 ;; or a list of them.
846 ;; If WHICH is nil, immediately return nil.
847 ;; If WHICH is 1, return innermost enclosing environment.
848 ;; If WHICH is t, return list of all environments enclosing point.
849 ;; If WHICH is a list of environments, look only for those environments and
850 ;; return the name of the first environment in this list found to enclose
853 (unless reftex-section-regexp
(reftex-compile-variables))
856 (if (null reftex-special-env-parsers
) (throw 'exit nil
))
857 (if (null which
) (throw 'exit nil
))
858 (let ((bound (or bound
(save-excursion (re-search-backward
859 reftex-section-regexp nil
1)
861 (fun-list (if (listp which
)
862 (mapcar (lambda (x) (if (memq x which
) x nil
))
863 reftex-special-env-parsers
)
864 reftex-special-env-parsers
))
866 ;; Call all functions
867 (setq specials
(mapcar
870 (setq rtn
(and fun
(funcall fun bound
)))
871 (if rtn
(cons (symbol-name fun
) rtn
) nil
)))
873 ;; Delete the non-matches
874 (setq specials
(delq nil specials
))
876 (setq specials
(sort specials
(lambda (a b
) (> (cdr a
) (cdr b
)))))
881 (defsubst reftex-move-to-next-arg
(&optional ignore
)
882 ;; Assuming that we are at the end of a macro name or a macro argument,
883 ;; move forward to the opening parenthesis of the next argument.
884 ;; This function understands the splitting of macros over several lines
888 ((memq (following-char) '(?\
[ ?\
{)))
890 ((and reftex-allow-detached-macro-args
891 (looking-at "[ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*[[{]"))
892 (goto-char (1- (match-end 0)))
896 (defun reftex-nth-arg-wrapper (key)
897 (let ((entry (assoc key reftex-env-or-mac-alist
)))
898 (reftex-nth-arg (nth 5 entry
) (nth 6 entry
))))
900 (defun reftex-nth-arg (n &optional opt-args
)
901 ;; Return the nth following {} or [] parentheses content.
902 ;; OPT-ARGS is a list of argument numbers which are optional.
904 ;; If we are sitting at a macro start, skip to end of macro name.
905 (and (eq (following-char) ?
\\) (skip-chars-forward "a-zA-Z*\\\\"))
908 ;; Special case: Skip all touching arguments
910 (reftex-move-over-touching-args)
911 (reftex-context-substring))
913 ;; Do the real thing.
916 (when (reftex-move-to-next-arg)
919 (while (and (member cnt opt-args
)
920 (eq (following-char) ?\
{))
923 (unless (and (condition-case nil
924 (or (forward-list 1) t
)
926 (reftex-move-to-next-arg)
930 (while (and (memq cnt opt-args
)
931 (eq (following-char) ?\
{))
934 (> (skip-chars-forward "{\\[") 0))
935 (reftex-context-substring)
938 (defun reftex-move-over-touching-args ()
940 (while (memq (following-char) '(?\
[ ?\
{))
944 (defun reftex-context-substring (&optional to-end
)
945 ;; Return up to 150 chars from point
946 ;; When point is just after a { or [, limit string to matching parenthesis
949 ;; Environment - find next \end
950 (buffer-substring-no-properties
954 ;; FIXME: THis is not perfect
955 (if (re-search-forward "\\\\end{" nil t
)
958 ((or (= (preceding-char) ?\
{)
959 (= (preceding-char) ?\
[))
960 ;; Inside a list - get only the list.
961 (buffer-substring-no-properties
969 (error (point-max))))))
971 ;; no list - just grab 150 characters
972 (buffer-substring-no-properties (point)
973 (min (+ (point) 150) (point-max))))))
975 ;; Variable holding the vector with section numbers
976 (defvar reftex-section-numbers
(make-vector reftex-max-section-depth
0))
978 (defun reftex-init-section-numbers (&optional toc-entry appendix
)
979 ;; Initialize the section numbers with zeros or with what is found
981 (let* ((level (or (nth 5 toc-entry
) -
1))
982 (numbers (nreverse (split-string (or (nth 6 toc-entry
) "") "\\.")))
983 (depth (1- (length reftex-section-numbers
)))
984 (i depth
) number-string
)
987 (aset reftex-section-numbers i
0)
988 (setq number-string
(or (car numbers
) "0"))
989 (if (string-match "\\`[A-Z]\\'" number-string
)
990 (aset reftex-section-numbers i
991 (- (string-to-char number-string
) ?A -
1))
992 (aset reftex-section-numbers i
(string-to-int number-string
)))
995 (put 'reftex-section-numbers
'appendix appendix
))
997 (defun reftex-section-number (&optional level star
)
998 ;; Return a string with the current section number.
999 ;; When LEVEL is non-nil, increase section numbers on that level.
1000 (let* ((depth (1- (length reftex-section-numbers
))) idx n
(string "")
1001 (appendix (get 'reftex-section-numbers
'appendix
)))
1003 (when (and (> level -
1) (not star
))
1004 (aset reftex-section-numbers
1005 level
(1+ (aref reftex-section-numbers level
))))
1006 (setq idx
(1+ level
))
1008 (while (<= idx depth
)
1009 (aset reftex-section-numbers idx
0)
1012 (while (<= idx depth
)
1013 (setq n
(aref reftex-section-numbers idx
))
1014 (setq string
(concat string
(if (not (string= string
"")) "." "")
1018 (if (string-match "\\`\\([@0]\\.\\)+" string
)
1019 (setq string
(replace-match "" nil nil string
)))
1020 (if (string-match "\\(\\.0\\)+\\'" string
)
1021 (setq string
(replace-match "" nil nil string
)))
1023 (string-match "\\`[0-9]+" string
))
1027 (1- (+ ?A
(string-to-int (match-string 0 string
)))))
1028 (substring string
(match-end 0))))))
1030 (concat (make-string (1- (length string
)) ?\
) "*")
1033 ;;; reftex-parse.el ends here