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