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