comparison lisp/textmodes/reftex-parse.el @ 25280:9b601931b795

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