Spelling fixes.
[emacs.git] / lisp / textmodes / reftex-parse.el
blob1a0f7ec58366a34dd7f45dce1ee198a7f5753ade
1 ;;; reftex-parse.el --- parser functions for RefTeX
3 ;; Copyright (C) 1997-2011 Free Software Foundation, Inc.
5 ;; Author: Carsten Dominik <dominik@science.uva.nl>
6 ;; Maintainer: auctex-devel@gnu.org
7 ;; Version: 4.31
8 ;; Package: reftex
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 3 of the License, or
15 ;; (at your option) any later version.
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. If not, see <http://www.gnu.org/licenses/>.
25 ;;; Commentary:
27 ;;; Code:
29 (eval-when-compile (require 'cl))
30 (provide 'reftex-parse)
31 (require 'reftex)
33 (defmacro reftex-with-special-syntax (&rest body)
34 `(let ((saved-syntax (syntax-table)))
35 (unwind-protect
36 (progn
37 (set-syntax-table reftex-syntax-table)
38 (let ((case-fold-search nil))
39 ,@body))
40 (set-syntax-table saved-syntax))))
42 (defun reftex-parse-one ()
43 "Re-parse this file."
44 (interactive)
45 (let ((reftex-enable-partial-scans t))
46 (reftex-access-scan-info '(4))))
48 (defun reftex-parse-all ()
49 "Re-parse entire document."
50 (interactive)
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)
58 ((eq rescan 1) 1)
59 ((equal rescan '(4)) t)
60 ((equal rescan '(16)) 1)
61 (t 1)))
63 ;; Partial scans only when allowed
64 (unless reftex-enable-partial-scans
65 (setq rescan 1))
67 ;; Do the scanning.
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
84 (setq rescan 1))
85 (when (string= true-file true-master)
86 ;; Scan whole document because this file is the master
87 (setq rescan 1))
89 ;; From which file do we start?
90 (setq from-file
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)
106 (if (eq rescan 1)
107 (message "Scanning entire document...")
108 (message "Scanning document from %s..." from-file))
110 (reftex-with-special-syntax
111 (save-window-excursion
112 (save-excursion
113 (unwind-protect
114 (setq docstruct
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))
124 ;; Set or insert
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)))
143 (if index-tag-cell
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))
148 (alist (mapcar
149 (lambda (x)
150 (if (setq tmp (reftex-locate-file (nth 2 x) "tex"
151 master-dir))
152 (cons (nth 1 x) tmp)
153 (message "Can't find external document %s"
154 (nth 2 x))
155 nil))
156 allxr))
157 (alist (delq nil alist))
158 (allprefix (delq nil (mapcar 'car alist)))
159 (regexp (if allprefix
160 (concat "\\`\\("
161 (mapconcat 'identity allprefix "\\|")
162 "\\)")
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 ;;;###autoload
175 (defun reftex-all-document-files (&optional relative)
176 "Return a list of all files belonging to the current document.
177 When RELATIVE is non-nil, give file names relative to directory
178 of master file."
179 (let* ((all (symbol-value reftex-docstruct-symbol))
180 (master-dir (file-name-directory (reftex-TeX-master-file)))
181 (re (concat "\\`" (regexp-quote master-dir)))
182 file-list tmp file)
183 (while (setq tmp (assoc 'bof all))
184 (setq file (nth 1 tmp)
185 all (cdr (memq tmp all)))
186 (and relative
187 (string-match re file)
188 (setq file (substring file (match-end 0))))
189 (push file file-list))
190 (nreverse file-list)))
192 ;; Bound in the caller, reftex-do-parse.
193 (defvar index-tags)
195 (defun reftex-parse-from-file (file docstruct master-dir)
196 ;; Scan the buffer for labels and save them in a list.
197 (let ((regexp (reftex-everything-regexp))
198 (bound 0)
199 file-found tmp include-file
200 (level 1)
201 (highest-level 100)
202 toc-entry index-entry next-buf buf)
204 (catch 'exit
205 (setq file-found (reftex-locate-file file "tex" master-dir))
206 (if (and (not file-found)
207 (setq buf (reftex-get-buffer-visiting file)))
208 (setq file-found (buffer-file-name buf)))
210 (unless file-found
211 (push (list 'file-error file) docstruct)
212 (throw 'exit nil))
214 (save-excursion
216 (message "Scanning file %s" file)
217 (set-buffer
218 (setq next-buf
219 (reftex-get-file-buffer-force
220 file-found
221 (not (eq t reftex-keep-temporary-buffers)))))
223 ;; Begin of file mark
224 (setq file (buffer-file-name))
225 (push (list 'bof file) docstruct)
227 (reftex-with-special-syntax
228 (save-excursion
229 (save-restriction
230 (widen)
231 (goto-char 1)
233 (while (re-search-forward regexp nil t)
235 (cond
237 ((match-end 1)
238 ;; It is a label
239 (push (reftex-label-info (reftex-match-string 1) file bound)
240 docstruct))
242 ((match-end 3)
243 ;; It is a section
244 (setq bound (point))
246 ;; Insert in List
247 (setq toc-entry (reftex-section-info file))
248 (when toc-entry
249 ;; It can happen that section info returns nil
250 (setq level (nth 5 toc-entry))
251 (setq highest-level (min highest-level level))
252 (if (= level highest-level)
253 (message
254 "Scanning %s %s ..."
255 (car (rassoc level reftex-section-levels-all))
256 (nth 6 toc-entry)))
258 (push toc-entry docstruct)
259 (setq reftex-active-toc toc-entry)))
261 ((match-end 7)
262 ;; It's an include or input
263 (setq include-file (reftex-match-string 7))
264 ;; Test if this file should be ignored
265 (unless (delq nil (mapcar
266 (lambda (x) (string-match x include-file))
267 reftex-no-include-regexps))
268 ;; Parse it
269 (setq docstruct
270 (reftex-parse-from-file
271 include-file
272 docstruct master-dir))))
274 ((match-end 9)
275 ;; Appendix starts here
276 (reftex-init-section-numbers nil t)
277 (push (cons 'appendix t) docstruct))
279 ((match-end 10)
280 ;; Index entry
281 (when reftex-support-index
282 (setq index-entry (reftex-index-info file))
283 (when index-entry
284 (add-to-list 'index-tags (nth 1 index-entry))
285 (push index-entry docstruct))))
287 ((match-end 11)
288 ;; A macro with label
289 (save-excursion
290 (let* ((mac (reftex-match-string 11))
291 (label (progn (goto-char (match-end 11))
292 (save-match-data
293 (reftex-no-props
294 (reftex-nth-arg-wrapper
295 mac)))))
296 (typekey (nth 1 (assoc mac reftex-env-or-mac-alist)))
297 (entry (progn (if typekey
298 ;; A typing macro
299 (goto-char (match-end 0))
300 ;; A neutral macro
301 (goto-char (match-end 11))
302 (reftex-move-over-touching-args))
303 (reftex-label-info
304 label file bound nil nil))))
305 (push entry docstruct))))
306 (t (error "This should not happen (reftex-parse-from-file)")))
309 ;; Find bibliography statement
310 (when (setq tmp (reftex-locate-bibliography-files master-dir))
311 (push (cons 'bib tmp) docstruct))
313 (goto-char 1)
314 (when (re-search-forward
315 "\\(\\`\\|[\n\r]\\)[ \t]*\\\\begin{thebibliography}" nil t)
316 (push (cons 'thebib file) docstruct))
318 ;; Find external document specifications
319 (goto-char 1)
320 (while (re-search-forward "[\n\r][ \t]*\\\\externaldocument\\(\\[\\([^]]*\\)\\]\\)?{\\([^}]+\\)}" nil t)
321 (push (list 'xr-doc (reftex-match-string 2)
322 (reftex-match-string 3))
323 docstruct))
325 ;; End of file mark
326 (push (list 'eof file) docstruct)))))
328 ;; Kill the scanned buffer
329 (reftex-kill-temporary-buffers next-buf))
331 ;; Return the list
332 docstruct))
334 (defun reftex-locate-bibliography-files (master-dir &optional files)
335 ;; Scan buffer for bibliography macro and return file list.
337 (unless files
338 (save-excursion
339 (goto-char (point-min))
340 (if (re-search-forward
341 (concat
342 ; "\\(\\`\\|[\n\r]\\)[^%]*\\\\\\("
343 "\\(^\\)[^%\n\r]*\\\\\\("
344 (mapconcat 'identity reftex-bibliography-commands "\\|")
345 "\\){[ \t]*\\([^}]+\\)") nil t)
346 (setq files
347 (split-string (reftex-match-string 3)
348 "[ \t\n\r]*,[ \t\n\r]*")))))
349 (when files
350 (setq files
351 (mapcar
352 (lambda (x)
353 (if (or (member x reftex-bibfile-ignore-list)
354 (delq nil (mapcar (lambda (re) (string-match re x))
355 reftex-bibfile-ignore-regexps)))
356 ;; excluded file
358 ;; find the file
359 (reftex-locate-file x "bib" master-dir)))
360 files))
361 (delq nil files)))
363 (defun reftex-replace-label-list-segment (old insert &optional entirely)
364 ;; Replace the segment in OLD which corresponds to INSERT.
365 ;; Works with side effects, directly changes old.
366 ;; If entirely is t, just return INSERT.
367 ;; This function also makes sure the old toc markers do not point anywhere.
369 (cond
370 (entirely
371 (reftex-silence-toc-markers old (length old))
372 insert)
373 (t (let* ((new old)
374 (file (nth 1 (car insert)))
375 (eof-list (member (list 'eof file) old))
376 (bof-list (member (list 'bof file) old))
378 (if (not (and bof-list eof-list))
379 (error "Cannot splice")
380 ;; Splice
381 (reftex-silence-toc-markers bof-list (- (length bof-list)
382 (length eof-list)))
383 (setq n (- (length old) (length bof-list)))
384 (setcdr (nthcdr n new) (cdr insert))
385 (setcdr (nthcdr (1- (length new)) new) (cdr eof-list)))
386 new))))
388 (defun reftex-section-info (file)
389 ;; Return a section entry for the current match.
390 ;; Careful: This function expects the match-data to be still in place!
391 (let* ((marker (set-marker (make-marker) (1- (match-beginning 3))))
392 (macro (reftex-match-string 3))
393 (prefix (save-match-data
394 (if (string-match "begin{\\([^}]+\\)}" macro)
395 (match-string 1 macro))))
396 (level-exp (cdr (assoc macro reftex-section-levels-all)))
397 (level (if (symbolp level-exp)
398 (save-match-data (funcall level-exp))
399 level-exp))
400 (star (= ?* (char-after (match-end 3))))
401 (unnumbered (or star (< level 0)))
402 (level (abs level))
403 (section-number (reftex-section-number level unnumbered))
404 (text1 (save-match-data
405 (save-excursion
406 (reftex-context-substring prefix))))
407 (literal (buffer-substring-no-properties
408 (1- (match-beginning 3))
409 (min (point-max) (+ (match-end 0) (length text1) 1))))
410 ;; Literal can be too short since text1 too short. No big problem.
411 (text (reftex-nicify-text text1)))
413 ;; Add section number and indentation
414 (setq text
415 (concat
416 (make-string (* reftex-level-indent level) ?\ )
417 (if (nth 1 reftex-label-menu-flags) ; section number flag
418 (concat section-number " "))
419 (if prefix (concat (capitalize prefix) ": ") "")
420 text))
421 (list 'toc "toc" text file marker level section-number
422 literal (marker-position marker))))
424 (defun reftex-ensure-index-support (&optional abort)
425 ;; When index support is turned off, ask to turn it on and
426 ;; set the current prefix argument so that `reftex-access-scan-info'
427 ;; will rescan the entire document.
428 (cond
429 (reftex-support-index t)
430 ((y-or-n-p "Turn on index support and rescan entire document? ")
431 (setq reftex-support-index 'demanded
432 current-prefix-arg '(16)))
433 (t (if abort
434 (error "No index support")
435 (message "No index support")
436 (ding)
437 (sit-for 1)))))
439 (defun reftex-index-info-safe (file)
440 (reftex-with-special-syntax
441 (reftex-index-info file)))
443 (defvar test-dummy)
444 (defun reftex-index-info (file)
445 ;; Return an index entry for the current match.
446 ;; Careful: This function expects the match-data to be still in place!
447 (catch 'exit
448 (let* ((macro (reftex-match-string 10))
449 (bom (match-beginning 10))
450 (boa (match-end 10))
451 (entry (or (assoc macro reftex-index-macro-alist)
452 (throw 'exit nil)))
453 (exclude (nth 3 entry))
454 ;; The following is a test if this match should be excluded
455 (test-dummy (and (fboundp exclude)
456 (funcall exclude)
457 (throw 'exit nil)))
458 (itag (nth 1 entry))
459 (prefix (nth 2 entry))
460 (index-tag
461 (cond ((stringp itag) itag)
462 ((integerp itag)
463 (progn (goto-char boa)
464 (or (reftex-nth-arg itag (nth 6 entry)) "idx")))
465 (t "idx")))
466 (arg (or (progn (goto-char boa)
467 (reftex-nth-arg (nth 5 entry) (nth 6 entry)))
468 ""))
469 (end-of-args (progn (goto-char boa)
470 (reftex-move-over-touching-args)
471 (point)))
472 (end-of-context (progn (skip-chars-forward "^ \t\n\r") (point)))
473 (begin-of-context
474 (progn (goto-char bom)
475 (skip-chars-backward "^ \t\r\n")
476 (point)))
477 (context (buffer-substring-no-properties
478 begin-of-context end-of-context))
479 (key-end (if (string-match reftex-index-key-end-re arg)
480 (1+ (match-beginning 0))))
481 (rawkey (substring arg 0 key-end))
483 (key (if prefix (concat prefix rawkey) rawkey))
484 (sortkey (downcase key))
485 (showkey (mapconcat 'identity
486 (split-string key reftex-index-level-re)
487 " ! ")))
488 (goto-char end-of-args)
489 ;; 0 1 2 3 4 5 6 7 8 9
490 (list 'index index-tag context file bom arg key showkey sortkey key-end))))
492 (defun reftex-short-context (env parse &optional bound derive)
493 ;; Get about one line of useful context for the label definition at point.
495 (if (consp parse)
496 (setq parse (if derive (cdr parse) (car parse))))
498 (reftex-nicify-text
500 (cond
502 ((null parse)
503 (save-excursion
504 (reftex-context-substring)))
506 ((eq parse t)
507 (if (string= env "section")
508 ;; special treatment for section labels
509 (save-excursion
510 (if (and (re-search-backward reftex-section-or-include-regexp
511 (point-min) t)
512 (match-end 2))
513 (progn
514 (goto-char (match-end 0))
515 (reftex-context-substring))
516 (if reftex-active-toc
517 (progn
518 (string-match "{\\([^}]*\\)" (nth 7 reftex-active-toc))
519 (match-string 1 (nth 7 reftex-active-toc)))
520 "SECTION HEADING NOT FOUND")))
521 (save-excursion
522 (goto-char reftex-default-context-position)
523 (unless (eq (string-to-char env) ?\\)
524 (reftex-move-over-touching-args))
525 (reftex-context-substring))))
527 ((stringp parse)
528 (save-excursion
529 (if (re-search-backward parse bound t)
530 (progn
531 (goto-char (match-end 0))
532 (reftex-context-substring))
533 "NO MATCH FOR CONTEXT REGEXP")))
535 ((integerp parse)
536 (or (save-excursion
537 (goto-char reftex-default-context-position)
538 (reftex-nth-arg
539 parse
540 (nth 6 (assoc env reftex-env-or-mac-alist))))
541 ""))
543 ((fboundp parse)
544 ;; A hook function. Call it.
545 (save-excursion
546 (condition-case error-var
547 (funcall parse env)
548 (error (format "HOOK ERROR: %s" (cdr error-var))))))
550 "INVALID VALUE OF PARSE"))))
552 (defun reftex-where-am-I ()
553 ;; Return the docstruct entry above point. Actually returns a cons
554 ;; cell in which the cdr is a flag indicating if the information is
555 ;; exact (t) or approximate (nil).
557 (let ((docstruct (symbol-value reftex-docstruct-symbol))
558 (cnt 0) rtn rtn-if-no-other
559 found)
560 (save-excursion
561 (while (not rtn)
562 (incf cnt)
563 (setq found (re-search-backward (reftex-everything-regexp) nil t))
564 (setq rtn
565 (cond
566 ((not found)
567 ;; no match
569 (car (member (list 'bof (buffer-file-name)) docstruct))
570 (not (setq cnt 2))
571 (assq 'bof docstruct) ;; for safety reasons
572 'corrupted))
573 ((match-end 1)
574 ;; Label
575 (assoc (reftex-match-string 1)
576 (symbol-value reftex-docstruct-symbol)))
577 ((match-end 3)
578 ;; Section
579 (goto-char (1- (match-beginning 3)))
580 (let* ((list (member (list 'bof (buffer-file-name))
581 docstruct))
582 (endelt (car (member (list 'eof (buffer-file-name))
583 list)))
584 rtn1)
585 (while (and list (not (eq endelt (car list))))
586 (if (and (eq (car (car list)) 'toc)
587 (string= (buffer-file-name)
588 (nth 3 (car list))))
589 (cond
590 ((equal (point)
591 (or (and (markerp (nth 4 (car list)))
592 (marker-position (nth 4 (car list))))
593 (nth 8 (car list))))
594 ;; Fits with marker position or recorded position
595 (setq rtn1 (car list) list nil))
596 ((looking-at (reftex-make-regexp-allow-for-ctrl-m
597 (nth 7 (car list))))
598 ;; Same title: remember, but keep looking
599 (setq rtn-if-no-other (car list)))))
600 (pop list))
601 rtn1))
602 ((match-end 7)
603 ;; Input or include...
604 (car
605 (member (list 'eof (reftex-locate-file
606 (reftex-match-string 7) "tex"
607 (cdr (assq 'master-dir docstruct))))
608 docstruct)))
609 ((match-end 9)
610 (assq 'appendix (symbol-value reftex-docstruct-symbol)))
611 ((match-end 10)
612 ;; Index entry
613 (when reftex-support-index
614 (let* ((index-info (save-excursion
615 (reftex-index-info-safe nil)))
616 (list (member (list 'bof (buffer-file-name))
617 docstruct))
618 (endelt (car (member (list 'eof (buffer-file-name))
619 list)))
620 dist last-dist last (n 0))
621 ;; Check all index entries with equal text
622 (while (and list (not (eq endelt (car list))))
623 (when (and (eq (car (car list)) 'index)
624 (string= (nth 2 index-info)
625 (nth 2 (car list))))
626 (incf n)
627 (setq dist (abs (- (point) (nth 4 (car list)))))
628 (if (or (not last-dist) (< dist last-dist))
629 (setq last-dist dist last (car list))))
630 (setq list (cdr list)))
631 ;; We are sure if we have only one, or a zero distance
632 (cond ((or (= n 1) (equal dist 0)) last)
633 ((> n 1) (setq cnt 2) last)
634 (t nil)))))
635 ((match-end 11)
636 (save-excursion
637 (goto-char (match-end 11))
638 (assoc (reftex-no-props
639 (reftex-nth-arg-wrapper
640 (reftex-match-string 11)))
641 (symbol-value reftex-docstruct-symbol))))
643 (error "This should not happen (reftex-where-am-I)"))))))
644 ;; Check if there was only a by-name match for the section.
645 (when (and (not rtn) rtn-if-no-other)
646 (setq rtn rtn-if-no-other
647 cnt 2))
648 (cons rtn (eq cnt 1))))
650 (defun reftex-notice-new (&optional n force)
651 "Hook to handshake with RefTeX after something new has been inserted."
652 ;; Add a new entry to the docstruct list. If it is a section, renumber
653 ;; the following sections.
654 ;; FIXME: Put in a WHAT parameter and search backward until one is found.
655 ;; When N is given, go back that many matches of reftex-everything-regexp
656 ;; When FORCE is non-nil, also insert if `reftex-where-am-I' was uncertain.
657 (condition-case nil
658 (catch 'exit
659 (unless reftex-mode (throw 'exit nil))
660 (reftex-access-scan-info)
661 (let* ((docstruct (symbol-value reftex-docstruct-symbol))
662 here-I-am appendix tail entry star level
663 section-number context)
665 (save-excursion
666 (when (re-search-backward (reftex-everything-regexp) nil t (or n 1))
668 ;; Find where we are
669 (setq here-I-am (reftex-where-am-I))
670 (or here-I-am (throw 'exit nil))
671 (unless (or force (cdr here-I-am)) (throw 'exit nil))
672 (setq tail (memq (car here-I-am) docstruct))
673 (or tail (throw 'exit nil))
674 (setq reftex-active-toc (reftex-last-assoc-before-elt
675 'toc (car here-I-am) docstruct)
676 appendix (reftex-last-assoc-before-elt
677 'appendix (car here-I-am) docstruct))
679 ;; Initialize section numbers
680 (if (eq (car (car here-I-am)) 'appendix)
681 (reftex-init-section-numbers nil t)
682 (reftex-init-section-numbers reftex-active-toc appendix))
684 ;; Match the section command
685 (when (re-search-forward (reftex-everything-regexp) nil t)
686 (cond
687 ((match-end 1)
688 (push (reftex-label-info (reftex-match-string 1) buffer-file-name)
689 (cdr tail)))
691 ((match-end 3)
692 (setq star (= ?* (char-after (match-end 3)))
693 entry (reftex-section-info (buffer-file-name))
694 level (nth 5 entry))
695 ;; Insert the section info
696 (push entry (cdr tail))
698 ;; We are done unless we use section numbers
699 (unless (nth 1 reftex-label-menu-flags) (throw 'exit nil))
701 ;; Update the remaining toc items
702 (setq tail (cdr tail))
703 (while (and (setq tail (memq (assq 'toc (cdr tail)) tail))
704 (setq entry (car tail))
705 (>= (nth 5 entry) level))
706 (setq star (string-match "\\*" (nth 6 entry))
707 context (nth 2 entry)
708 section-number
709 (reftex-section-number (nth 5 entry) star))
710 (when (string-match "\\`\\([ \t]*\\)\\([.0-9A-Z]+\\)\\(.*\\)"
711 context)
712 (when (and (not appendix)
713 (>= (string-to-char (match-string 2)) ?A))
714 ;; Just entered the appendix. Get out.
715 (throw 'exit nil))
717 ;; Change the section number.
718 (setf (nth 2 entry)
719 (concat (match-string 1 context)
720 section-number
721 (match-string 3 context))))))
722 ((match-end 10)
723 ;; Index entry
724 (and reftex-support-index
725 (setq entry (reftex-index-info-safe buffer-file-name))
726 ;; FIXME: (add-to-list 'index-tags (nth 1 index-entry))
727 (push entry (cdr tail))))))))))
729 (error nil))
732 (defsubst reftex-move-to-previous-arg (&optional bound)
733 ;; Assuming that we are in front of a macro argument,
734 ;; move backward to the closing parenthesis of the previous argument.
735 ;; This function understands the splitting of macros over several lines
736 ;; in TeX.
737 (cond
738 ;; Just to be quick:
739 ((memq (preceding-char) '(?\] ?\})))
740 ;; Do a search
741 ((and reftex-allow-detached-macro-args
742 (re-search-backward
743 "[]}][ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*\\=" bound t))
744 (goto-char (1+ (match-beginning 0)))
746 (t nil)))
748 (defun reftex-what-macro-safe (which &optional bound)
749 ;; reftex-what-macro with special syntax table.
750 (reftex-with-special-syntax
751 (reftex-what-macro which bound)))
753 (defun reftex-what-macro (which &optional bound)
754 ;; Find out if point is within the arguments of any TeX-macro.
755 ;; The return value is either ("\\macro" . (point)) or a list of them.
757 ;; If WHICH is nil, immediately return nil.
758 ;; If WHICH is 1, return innermost enclosing macro.
759 ;; If WHICH is t, return list of all macros enclosing point.
760 ;; If WHICH is a list of macros, look only for those macros and return the
761 ;; name of the first macro in this list found to enclose point.
762 ;; If the optional BOUND is an integer, bound backwards directed
763 ;; searches to this point. If it is nil, limit to nearest \section -
764 ;; like statement.
766 ;; This function is pretty stable, but can be fooled if the text contains
767 ;; things like \macro{aa}{bb} where \macro is defined to take only one
768 ;; argument. As RefTeX cannot know this, the string "bb" would still be
769 ;; considered an argument of macro \macro.
771 (unless reftex-section-regexp (reftex-compile-variables))
772 (catch 'exit
773 (if (null which) (throw 'exit nil))
774 (let ((bound (or bound (save-excursion (re-search-backward
775 reftex-section-regexp nil 1)
776 (point))))
777 pos cmd-list cmd cnt cnt-opt entry)
778 (save-restriction
779 (save-excursion
780 (narrow-to-region (max (point-min) bound) (point-max))
781 ;; move back out of the current parenthesis
782 (while (condition-case nil
783 (let ((forward-sexp-function nil))
784 (up-list -1) t)
785 (error nil))
786 (setq cnt 1 cnt-opt 0)
787 ;; move back over any touching sexps
788 (while (and (reftex-move-to-previous-arg bound)
789 (condition-case nil
790 (let ((forward-sexp-function nil))
791 (backward-sexp) t)
792 (error nil)))
793 (if (eq (following-char) ?\[) (incf cnt-opt))
794 (incf cnt))
795 (setq pos (point))
796 (when (and (or (= (following-char) ?\[)
797 (= (following-char) ?\{))
798 (re-search-backward "\\\\[*a-zA-Z]+\\=" nil t))
799 (setq cmd (reftex-match-string 0))
800 (when (looking-at "\\\\begin{[^}]*}")
801 (setq cmd (reftex-match-string 0)
802 cnt (1- cnt)))
803 ;; This does ignore optional arguments. Very hard to fix.
804 (when (setq entry (assoc cmd reftex-env-or-mac-alist))
805 (if (> cnt (or (nth 4 entry) 100))
806 (setq cmd nil)))
807 (cond
808 ((null cmd))
809 ((eq t which)
810 (push (cons cmd (point)) cmd-list))
811 ((or (eq 1 which) (member cmd which))
812 (throw 'exit (cons cmd (point))))))
813 (goto-char pos)))
814 (nreverse cmd-list)))))
816 (defun reftex-what-environment (which &optional bound)
817 ;; Find out if point is inside a LaTeX environment.
818 ;; The return value is (e.g.) either ("equation" . (point)) or a list of
819 ;; them.
821 ;; If WHICH is nil, immediately return nil.
822 ;; If WHICH is 1, return innermost enclosing environment.
823 ;; If WHICH is t, return list of all environments enclosing point.
824 ;; If WHICH is a list of environments, look only for those environments and
825 ;; return the name of the first environment in this list found to enclose
826 ;; point.
828 ;; If the optional BOUND is an integer, bound backwards directed searches to
829 ;; this point. If it is nil, limit to nearest \section - like statement.
831 (unless reftex-section-regexp (reftex-compile-variables))
832 (catch 'exit
833 (save-excursion
834 (if (null which) (throw 'exit nil))
835 (let ((bound (or bound (save-excursion (re-search-backward
836 reftex-section-regexp nil 1)
837 (point))))
838 env-list end-list env)
839 (while (re-search-backward "\\\\\\(begin\\|end\\){\\([^}]+\\)}"
840 bound t)
841 (setq env (buffer-substring-no-properties
842 (match-beginning 2) (match-end 2)))
843 (cond
844 ((string= (match-string 1) "end")
845 (push env end-list))
846 ((equal env (car end-list))
847 (setq end-list (cdr end-list)))
848 ((eq t which)
849 (push (cons env (point)) env-list))
850 ((or (eq 1 which) (member env which))
851 (throw 'exit (cons env (point))))))
852 (nreverse env-list)))))
854 (defun reftex-what-special-env (which &optional bound)
855 ;; Run the special environment parsers and return the matches.
857 ;; The return value is (e.g.) either ("my-parser-function" . (point))
858 ;; or a list of them.
860 ;; If WHICH is nil, immediately return nil.
861 ;; If WHICH is 1, return innermost enclosing environment.
862 ;; If WHICH is t, return list of all environments enclosing point.
863 ;; If WHICH is a list of environments, look only for those environments and
864 ;; return the name of the first environment in this list found to enclose
865 ;; point.
867 (unless reftex-section-regexp (reftex-compile-variables))
868 (catch 'exit
869 (save-excursion
870 (if (null reftex-special-env-parsers) (throw 'exit nil))
871 (if (null which) (throw 'exit nil))
872 (let ((bound (or bound (save-excursion (re-search-backward
873 reftex-section-regexp nil 1)
874 (point))))
875 (fun-list (if (listp which)
876 (mapcar (lambda (x) (if (memq x which) x nil))
877 reftex-special-env-parsers)
878 reftex-special-env-parsers))
879 specials rtn)
880 ;; Call all functions
881 (setq specials (mapcar
882 (lambda (fun)
883 (save-excursion
884 (setq rtn (and fun (funcall fun bound)))
885 (if rtn (cons (symbol-name fun) rtn) nil)))
886 fun-list))
887 ;; Delete the non-matches
888 (setq specials (delq nil specials))
889 ;; Sort
890 (setq specials (sort specials (lambda (a b) (> (cdr a) (cdr b)))))
891 (if (eq which t)
892 specials
893 (car specials))))))
895 (defsubst reftex-move-to-next-arg (&optional ignore)
896 ;; Assuming that we are at the end of a macro name or a macro argument,
897 ;; move forward to the opening parenthesis of the next argument.
898 ;; This function understands the splitting of macros over several lines
899 ;; in TeX.
900 (cond
901 ;; Just to be quick:
902 ((memq (following-char) '(?\[ ?\{)))
903 ;; Do a search
904 ((and reftex-allow-detached-macro-args
905 (looking-at "[ \t]*[\n\r]?\\([ \t]*%[^\n\r]*[\n\r]\\)*[ \t]*[[{]"))
906 (goto-char (1- (match-end 0)))
908 (t nil)))
910 (defun reftex-nth-arg-wrapper (key)
911 (let ((entry (assoc key reftex-env-or-mac-alist)))
912 (reftex-nth-arg (nth 5 entry) (nth 6 entry))))
914 (defun reftex-nth-arg (n &optional opt-args)
915 ;; Return the nth following {} or [] parentheses content.
916 ;; OPT-ARGS is a list of argument numbers which are optional.
918 ;; If we are sitting at a macro start, skip to end of macro name.
919 (and (eq (following-char) ?\\) (skip-chars-forward "a-zA-Z*\\\\"))
921 (if (= n 1000)
922 ;; Special case: Skip all touching arguments
923 (progn
924 (reftex-move-over-touching-args)
925 (reftex-context-substring))
927 ;; Do the real thing.
928 (let ((cnt 1))
930 (when (reftex-move-to-next-arg)
932 (while (< cnt n)
933 (while (and (member cnt opt-args)
934 (eq (following-char) ?\{))
935 (incf cnt))
936 (when (< cnt n)
937 (unless (and (condition-case nil
938 (or (forward-list 1) t)
939 (error nil))
940 (reftex-move-to-next-arg)
941 (incf cnt))
942 (setq cnt 1000))))
944 (while (and (memq cnt opt-args)
945 (eq (following-char) ?\{))
946 (incf cnt)))
947 (if (and (= n cnt)
948 (> (skip-chars-forward "{\\[") 0))
949 (reftex-context-substring)
950 nil))))
952 (defun reftex-move-over-touching-args ()
953 (condition-case nil
954 (while (memq (following-char) '(?\[ ?\{))
955 (forward-list 1))
956 (error nil)))
958 (defun reftex-context-substring (&optional to-end)
959 ;; Return up to 150 chars from point
960 ;; When point is just after a { or [, limit string to matching parenthesis
961 (cond
962 (to-end
963 ;; Environment - find next \end
964 (buffer-substring-no-properties
965 (point)
966 (min (+ (point) 150)
967 (save-match-data
968 ;; FIXME: This is not perfect
969 (if (re-search-forward "\\\\end{" nil t)
970 (match-beginning 0)
971 (point-max))))))
972 ((memq (preceding-char) '(?\{ ?\[))
973 ;; Inside a list - get only the list.
974 (buffer-substring-no-properties
975 (point)
976 (min (+ (point) 150)
977 (point-max)
978 (condition-case nil
979 (let ((forward-sexp-function nil)) ;Unneeded fanciness.
980 (up-list 1)
981 (1- (point)))
982 (error (point-max))))))
984 ;; no list - just grab 150 characters
985 (buffer-substring-no-properties (point)
986 (min (+ (point) 150) (point-max))))))
988 ;; Variable holding the vector with section numbers
989 (defvar reftex-section-numbers (make-vector reftex-max-section-depth 0))
991 (defun reftex-init-section-numbers (&optional toc-entry appendix)
992 ;; Initialize the section numbers with zeros or with what is found
993 ;; in the toc entry.
994 (let* ((level (or (nth 5 toc-entry) -1))
995 (numbers (nreverse (split-string (or (nth 6 toc-entry) "") "\\.")))
996 (depth (1- (length reftex-section-numbers)))
997 (i depth) number-string)
998 (while (>= i 0)
999 (if (> i level)
1000 (aset reftex-section-numbers i 0)
1001 (setq number-string (or (car numbers) "0"))
1002 (if (string-match "\\`[A-Z]\\'" number-string)
1003 (aset reftex-section-numbers i
1004 (- (string-to-char number-string) ?A -1))
1005 (aset reftex-section-numbers i (string-to-number number-string)))
1006 (pop numbers))
1007 (decf i)))
1008 (put 'reftex-section-numbers 'appendix appendix))
1010 (defun reftex-section-number (&optional level star)
1011 ;; Return a string with the current section number.
1012 ;; When LEVEL is non-nil, increase section numbers on that level.
1013 (let* ((depth (1- (length reftex-section-numbers))) idx n (string "")
1014 (appendix (get 'reftex-section-numbers 'appendix))
1015 (partspecial (and (not reftex-part-resets-chapter)
1016 (equal level 0))))
1017 ;; partspecial means, this is a part statement.
1018 ;; Parts do not reset the chapter counter, and the part number is
1019 ;; not included in the numbering of other sectioning levels.
1020 (when level
1021 (when (and (> level -1) (not star))
1022 (aset reftex-section-numbers
1023 level (1+ (aref reftex-section-numbers level))))
1024 (setq idx (1+ level))
1025 (when (not star)
1026 (while (<= idx depth)
1027 (if (or (not partspecial)
1028 (not (= idx 1)))
1029 (aset reftex-section-numbers idx 0))
1030 (incf idx))))
1031 (if partspecial
1032 (setq string (concat "Part " (reftex-roman-number
1033 (aref reftex-section-numbers 0))))
1034 (setq idx (if reftex-part-resets-chapter 0 1))
1035 (while (<= idx depth)
1036 (setq n (aref reftex-section-numbers idx))
1037 (if (not (and partspecial (not (equal string ""))))
1038 (setq string (concat string (if (not (string= string "")) "." "")
1039 (int-to-string n))))
1040 (incf idx))
1041 (save-match-data
1042 (if (string-match "\\`\\([@0]\\.\\)+" string)
1043 (setq string (replace-match "" nil nil string)))
1044 (if (string-match "\\(\\.0\\)+\\'" string)
1045 (setq string (replace-match "" nil nil string)))
1046 (if (and appendix
1047 (string-match "\\`[0-9]+" string))
1048 (setq string
1049 (concat
1050 (char-to-string
1051 (1- (+ ?A (string-to-number (match-string 0 string)))))
1052 (substring string (match-end 0))))))
1053 (if star
1054 (concat (make-string (1- (length string)) ?\ ) "*")
1055 string))))
1057 (defun reftex-roman-number (n)
1058 ;; Return as a string the roman number equal to N.
1059 (let ((nrest n)
1060 (string "")
1061 (list '((1000 . "M") ( 900 . "CM") ( 500 . "D") ( 400 . "CD")
1062 ( 100 . "C") ( 90 . "XC") ( 50 . "L") ( 40 . "XL")
1063 ( 10 . "X") ( 9 . "IX") ( 5 . "V") ( 4 . "IV")
1064 ( 1 . "I")))
1065 listel i s)
1066 (while (>= nrest 1)
1067 (setq listel (pop list)
1068 i (car listel)
1069 s (cdr listel))
1070 (while (>= nrest i)
1071 (setq string (concat string s)
1072 nrest (- nrest i))))
1073 string))
1075 ;;; reftex-parse.el ends here