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