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