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