(text-mode): Use mode-require-final-newline.
[bpt/emacs.git] / lisp / textmodes / reftex-dcr.el
CommitLineData
3afbc435 1;;; reftex-dcr.el --- viewing cross references and citations with RefTeX
3666daf6 2;; Copyright (c) 1997, 1998, 1999, 2000, 2003 Free Software Foundation, Inc.
3ba2590f 3
6fbeb429 4;; Author: Carsten Dominik <dominik@science.uva.nl>
3666daf6 5;; Version: 4.21
9f286482 6;;
3ba2590f
RS
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING. If not, write to the
22;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23;; Boston, MA 02111-1307, USA.
1a9461d0 24
3afbc435
PJ
25;;; Commentary:
26
27;;; Code:
28
7c4d13cc 29(eval-when-compile (require 'cl))
df543367 30(provide 'reftex-dcr)
9f286482 31(provide 'reftex-vcr)
1a9461d0
CD
32(require 'reftex)
33;;;
34
35(defun reftex-view-crossref (&optional arg auto-how)
36 "View cross reference of macro at point. Point must be on the KEY
5f52a7df 37argument. When at at `\\ref' macro, show corresponding `\\label'
1a9461d0
CD
38definition, also in external documents (`xr'). When on a label, show
39a locations where KEY is referenced. Subsequent calls find additional
5f52a7df
AS
40locations. When on a `\\cite', show the associated `\\bibitem' macro or
41the BibTeX database entry. When on a `\\bibitem', show a `\\cite' macro
42which uses this KEY. When on an `\\index', show other locations marked
1a9461d0
CD
43by the same index entry.
44To define additional cross referencing items, use the option
45`reftex-view-crossref-extra'. See also `reftex-view-crossref-from-bibtex'.
46With one or two C-u prefixes, enforce rescanning of the document.
47With argument 2, select the window showing the cross reference.
48AUTO-HOW is only for the automatic crossref display and is handed through
49to the functions `reftex-view-cr-cite' and `reftex-view-cr-ref'."
50
51 (interactive "P")
52 ;; See where we are.
53 (let* ((macro (car (reftex-what-macro-safe 1)))
4e33ebe0 54 (key (reftex-this-word "^{}%\n\r, \t"))
3666daf6 55 dw)
1a9461d0
CD
56
57 (if (or (null macro) (reftex-in-comment))
3666daf6 58 (error "Not on a crossref macro argument"))
1a9461d0
CD
59
60 (setq reftex-call-back-to-this-buffer (current-buffer))
61
62 (cond
d8fb2015 63 ((string-match "\\`\\\\cite\\|cite\\*?\\'\\|bibentry" macro)
1a9461d0
CD
64 ;; A citation macro: search for bibitems or BibTeX entries
65 (setq dw (reftex-view-cr-cite arg key auto-how)))
66 ((string-match "\\`\\\\ref\\|ref\\(range\\)?\\*?\\'" macro)
67 ;; A reference macro: search for labels
68 (setq dw (reftex-view-cr-ref arg key auto-how)))
69 (auto-how nil) ;; No further action for automatic display (speed)
70 ((or (equal macro "\\label")
3666daf6 71 (member macro reftex-macros-with-labels))
1a9461d0
CD
72 ;; A label macro: search for reference macros
73 (reftex-access-scan-info arg)
74 (setq dw (reftex-view-regexp-match
3666daf6
CD
75 (format reftex-find-reference-format (regexp-quote key))
76 4 nil nil)))
1a9461d0
CD
77 ((equal macro "\\bibitem")
78 ;; A bibitem macro: search for citations
79 (reftex-access-scan-info arg)
80 (setq dw (reftex-view-regexp-match
3666daf6
CD
81 (format reftex-find-citation-regexp-format (regexp-quote key))
82 4 nil nil)))
1a9461d0
CD
83 ((member macro reftex-macros-with-index)
84 (reftex-access-scan-info arg)
85 (setq dw (reftex-view-regexp-match
3666daf6
CD
86 (format reftex-find-index-entry-regexp-format
87 (regexp-quote key))
88 3 nil nil)))
89 (t
1a9461d0
CD
90 (reftex-access-scan-info arg)
91 (catch 'exit
3666daf6
CD
92 (let ((list reftex-view-crossref-extra)
93 entry mre action group)
94 (while (setq entry (pop list))
95 (setq mre (car entry)
96 action (nth 1 entry)
97 group (nth 2 entry))
98 (when (string-match mre macro)
99 (setq dw (reftex-view-regexp-match
100 (format action key) group nil nil))
101 (throw 'exit t))))
102 (error "Not on a crossref macro argument"))))
1a9461d0 103 (if (and (eq arg 2) (windowp dw)) (select-window dw))))
3666daf6 104
1a9461d0 105(defun reftex-view-cr-cite (arg key how)
3666daf6 106 ;; View crossreference of a ref cite. HOW can have the values
1a9461d0
CD
107 ;; nil: Show in another window.
108 ;; echo: Show one-line info in echo area.
109 ;; tmp-window: Show in small window and arrange for window to disappear.
110
111 ;; Ensure access to scanning info
112 (reftex-access-scan-info (or arg current-prefix-arg))
113
114 (if (eq how 'tmp-window)
115 ;; Remember the window configuration
3666daf6
CD
116 (put 'reftex-auto-view-crossref 'last-window-conf
117 (current-window-configuration)))
1a9461d0 118
20cd3579 119 (let (files size item (pos (point)) (win (selected-window)) pop-win
3666daf6 120 (bibtype (reftex-bib-or-thebib)))
1a9461d0
CD
121 ;; Find the citation mode and the file list
122 (cond
20cd3579
CD
123; ((assq 'bib (symbol-value reftex-docstruct-symbol))
124 ((eq bibtype 'bib)
1a9461d0 125 (setq item nil
3666daf6 126 files (reftex-get-bibfile-list)))
20cd3579
CD
127; ((assq 'thebib (symbol-value reftex-docstruct-symbol))
128 ((eq bibtype 'thebib)
1a9461d0 129 (setq item t
3666daf6
CD
130 files (reftex-uniquify
131 (mapcar 'cdr
132 (reftex-all-assq
133 'thebib (symbol-value reftex-docstruct-symbol))))))
1a9461d0
CD
134 (reftex-default-bibliography
135 (setq item nil
3666daf6 136 files (reftex-default-bibliography)))
1a9461d0
CD
137 (how) ;; don't throw for special display
138 (t (error "Cannot display crossref")))
139
140 (if (eq how 'echo)
3666daf6
CD
141 ;; Display in Echo area
142 (reftex-echo-cite key files item)
1a9461d0
CD
143 ;; Display in a window
144 (if (not (eq how 'tmp-window))
3666daf6
CD
145 ;; Normal display
146 (reftex-pop-to-bibtex-entry key files nil t item)
147 ;; A temporary window
148 (condition-case nil
149 (reftex-pop-to-bibtex-entry key files nil t item)
150 (error (goto-char pos)
151 (message "cite: no such citation key %s" key)
152 (error "")))
153 ;; Resize the window
154 (setq size (max 1 (count-lines (point)
155 (reftex-end-of-bib-entry item))))
156 (let ((window-min-height 2))
157 (shrink-window (1- (- (window-height) size)))
158 (recenter 0))
159 ;; Arrange restoration
160 (add-hook 'pre-command-hook 'reftex-restore-window-conf))
161
162 ;; Normal display in other window
1a9461d0
CD
163 (add-hook 'pre-command-hook 'reftex-highlight-shall-die)
164 (setq pop-win (selected-window))
165 (select-window win)
166 (goto-char pos)
167 (when (equal arg 2)
3666daf6 168 (select-window pop-win)))))
1a9461d0
CD
169
170(defun reftex-view-cr-ref (arg label how)
3666daf6 171 ;; View crossreference of a ref macro. HOW can have the values
1a9461d0
CD
172 ;; nil: Show in another window.
173 ;; echo: Show one-line info in echo area.
174 ;; tmp-window: Show in small window and arrange for window to disappear.
175
176 ;; Ensure access to scanning info
177 (reftex-access-scan-info (or arg current-prefix-arg))
3666daf6 178
1a9461d0
CD
179 (if (eq how 'tmp-window)
180 ;; Remember the window configuration
3666daf6
CD
181 (put 'reftex-auto-view-crossref 'last-window-conf
182 (current-window-configuration)))
1a9461d0
CD
183
184 (let* ((xr-data (assoc 'xr (symbol-value reftex-docstruct-symbol)))
3666daf6
CD
185 (xr-re (nth 2 xr-data))
186 (entry (assoc label (symbol-value reftex-docstruct-symbol)))
187 (win (selected-window)) pop-win (pos (point)))
1a9461d0
CD
188
189 (if (and (not entry) (stringp label) xr-re (string-match xr-re label))
3666daf6
CD
190 ;; Label is defined in external document
191 (save-excursion
192 (save-match-data
193 (set-buffer
194 (or (reftex-get-file-buffer-force
195 (cdr (assoc (match-string 1 label) (nth 1
196 xr-data))))
197 (error "Problem with external label %s" label))))
198 (setq label (substring label (match-end 1)))
199 (reftex-access-scan-info)
200 (setq entry
201 (assoc label (symbol-value reftex-docstruct-symbol)))))
1a9461d0 202 (if (eq how 'echo)
3666daf6
CD
203 ;; Display in echo area
204 (reftex-echo-ref label entry (symbol-value reftex-docstruct-symbol))
1a9461d0 205 (let ((window-conf (current-window-configuration)))
3666daf6
CD
206 (condition-case nil
207 (reftex-show-label-location entry t nil t t)
208 (error (set-window-configuration window-conf)
209 (message "ref: Label %s not found" label)
210 (error "ref: Label %s not found" label)))) ;; 2nd is line OK
1a9461d0
CD
211 (add-hook 'pre-command-hook 'reftex-highlight-shall-die)
212
213 (when (eq how 'tmp-window)
3666daf6
CD
214 ;; Resize window and arrange restauration
215 (shrink-window (1- (- (window-height) 9)))
216 (recenter '(4))
217 (add-hook 'pre-command-hook 'reftex-restore-window-conf))
1a9461d0
CD
218 (setq pop-win (selected-window))
219 (select-window win)
220 (goto-char pos)
221 (when (equal arg 2)
3666daf6 222 (select-window pop-win)))))
1a9461d0
CD
223
224(defun reftex-mouse-view-crossref (ev)
225 "View cross reference of \\ref or \\cite macro where you click.
226If the macro at point is a \\ref, show the corresponding label definition.
227If it is a \\cite, show the BibTeX database entry.
228If there is no such macro at point, search forward to find one.
229With argument, actually select the window showing the cross reference."
230 (interactive "e")
231 (mouse-set-point ev)
232 (reftex-view-crossref current-prefix-arg))
233
234(defun reftex-view-crossref-when-idle ()
235 ;; Display info about crossref at point in echo area or a window.
236 ;; This function was desigend to work with an idle timer.
237 ;; We try to get out of here as quickly as possible if the call is useless.
238 (and reftex-mode
239 ;; Make sure message area is free if we need it.
240 (or (eq reftex-auto-view-crossref 'window) (not (current-message)))
241 ;; Make sure we are not already displaying this one
242 (not (memq last-command '(reftex-view-crossref
3666daf6 243 reftex-mouse-view-crossref)))
1a9461d0
CD
244 ;; Quick precheck if this might be a relevant spot
245 ;; FIXME: Can fail with backslash in comment
3666daf6
CD
246 (save-excursion
247 (search-backward "\\" nil t)
248 (looking-at "\\\\[a-zA-Z]*\\(cite\\|ref\\|bibentry\\)"))
1a9461d0
CD
249
250 (condition-case nil
3666daf6
CD
251 (let ((current-prefix-arg nil))
252 (cond
253 ((eq reftex-auto-view-crossref t)
254 (reftex-view-crossref -1 'echo))
255 ((eq reftex-auto-view-crossref 'window)
256 (reftex-view-crossref -1 'tmp-window))
257 (t nil)))
258 (error nil))))
1a9461d0
CD
259
260(defun reftex-restore-window-conf ()
261 (set-window-configuration (get 'reftex-auto-view-crossref 'last-window-conf))
262 (put 'reftex-auto-view-crossref 'last-window-conf nil)
263 (remove-hook 'pre-command-hook 'reftex-restore-window-conf))
3666daf6 264
1a9461d0
CD
265(defun reftex-echo-ref (label entry docstruct)
266 ;; Display crossref info in echo area.
267 (cond
268 ((null docstruct)
269 (message (substitute-command-keys (format reftex-no-info-message "ref"))))
270 ((null entry)
271 (message "ref: unknown label: %s" label))
272 (t
273 (when (stringp (nth 2 entry))
274 (message "ref(%s): %s" (nth 1 entry) (nth 2 entry)))
275 (let ((buf (get-buffer " *Echo Area*")))
276 (when buf
3666daf6
CD
277 (save-excursion
278 (set-buffer buf)
279 (run-hooks 'reftex-display-copied-context-hook)))))))
1a9461d0
CD
280
281(defun reftex-echo-cite (key files item)
282 ;; Display citation info in echo area.
283 (let* ((cache (assq 'bibview-cache (symbol-value reftex-docstruct-symbol)))
3666daf6
CD
284 (cache-entry (assoc key (cdr cache)))
285 entry string buf (all-files files))
1a9461d0
CD
286
287 (if (and reftex-cache-cite-echo cache-entry)
3666daf6
CD
288 ;; We can just use the cache
289 (setq string (cdr cache-entry))
1a9461d0
CD
290
291 ;; Need to look in the database
292 (unless reftex-revisit-to-echo
3666daf6
CD
293 (setq files (reftex-visited-files files)))
294
295 (setq entry
296 (condition-case nil
297 (save-excursion
298 (reftex-pop-to-bibtex-entry key files nil nil item t))
299 (error
300 (if (and files (= (length all-files) (length files)))
301 (message "cite: no such database entry: %s" key)
302 (message (substitute-command-keys
303 (format reftex-no-info-message "cite"))))
304 nil)))
1a9461d0 305 (when entry
3666daf6
CD
306 (if item
307 (setq string (reftex-nicify-text entry))
308 (setq string (reftex-make-cite-echo-string
309 (reftex-parse-bibtex-entry entry)
310 reftex-docstruct-symbol)))))
1a9461d0
CD
311 (unless (or (null string) (equal string ""))
312 (message "cite: %s" string))
313 (when (setq buf (get-buffer " *Echo Area*"))
314 (save-excursion
3666daf6
CD
315 (set-buffer buf)
316 (run-hooks 'reftex-display-copied-context-hook)))))
1a9461d0
CD
317
318(defvar reftex-use-itimer-in-xemacs nil
319 "*Non-nil means use the idle timers in XEmacs for crossref display.
320Currently, idle timer restart is broken and we use the post-command-hook.")
321
322(defun reftex-toggle-auto-view-crossref ()
323 "Toggle the automatic display of crossref information in the echo area.
324When active, leaving point idle in the argument of a \\ref or \\cite macro
325will display info in the echo area."
326 (interactive)
327 (if reftex-auto-view-crossref-timer
328 (progn
3666daf6
CD
329 (if (featurep 'xemacs)
330 (if reftex-use-itimer-in-xemacs
331 (delete-itimer reftex-auto-view-crossref-timer)
332 (remove-hook 'post-command-hook 'reftex-start-itimer-once))
333 (cancel-timer reftex-auto-view-crossref-timer))
334 (setq reftex-auto-view-crossref-timer nil)
335 (message "Automatic display of crossref information was turned off"))
1a9461d0 336 (setq reftex-auto-view-crossref-timer
3666daf6
CD
337 (if (featurep 'xemacs)
338 (if reftex-use-itimer-in-xemacs
339 (start-itimer "RefTeX Idle Timer"
340 'reftex-view-crossref-when-idle
341 reftex-idle-time reftex-idle-time t)
342 (add-hook 'post-command-hook 'reftex-start-itimer-once)
343 t)
344 (run-with-idle-timer
345 reftex-idle-time t 'reftex-view-crossref-when-idle)))
1a9461d0
CD
346 (unless reftex-auto-view-crossref
347 (setq reftex-auto-view-crossref t))
348 (message "Automatic display of crossref information was turned on")))
349
350(defun reftex-start-itimer-once ()
351 (and reftex-mode
3666daf6
CD
352 (not (itimer-live-p reftex-auto-view-crossref-timer))
353 (setq reftex-auto-view-crossref-timer
354 (start-itimer "RefTeX Idle Timer"
355 'reftex-view-crossref-when-idle
356 reftex-idle-time nil t))))
1a9461d0
CD
357
358(defun reftex-view-crossref-from-bibtex (&optional arg)
359 "View location in a LaTeX document which cites the BibTeX entry at point.
360Since BibTeX files can be used by many LaTeX documents, this function
361prompts upon first use for a buffer in RefTeX mode. To reset this
362link to a document, call the function with with a prefix arg.
363Calling this function several times find successive citation locations."
364 (interactive "P")
3666daf6 365 (when arg
1a9461d0 366 ;; Break connection to reference buffer
d8fb2015 367 (put 'reftex-bibtex-view-cite-locations :ref-buffer nil))
1a9461d0
CD
368 (let ((ref-buffer (get 'reftex-bibtex-view-cite-locations :ref-buffer)))
369 ;; Establish connection to reference buffer
370 (unless ref-buffer
371 (setq ref-buffer
3666daf6
CD
372 (save-excursion
373 (completing-read
374 "Reference buffer: "
375 (delq nil
376 (mapcar
377 (lambda (b)
378 (set-buffer b)
379 (if reftex-mode (list (buffer-name b)) nil))
380 (buffer-list)))
381 nil t)))
1a9461d0
CD
382 (put 'reftex-bibtex-view-cite-locations :ref-buffer ref-buffer))
383 ;; Search for citations
384 (bibtex-beginning-of-entry)
385 (if (looking-at
3666daf6
CD
386 "@[a-zA-Z]+[ \t\n\r]*[{(][ \t\n\r]*\\([^, \t\r\n}]+\\)")
387 (progn
388 (goto-char (match-beginning 1))
389 (reftex-view-regexp-match
390 (format reftex-find-citation-regexp-format
391 (regexp-quote (match-string 1)))
392 4 arg ref-buffer))
1a9461d0
CD
393 (error "Cannot find citation key in BibTeX entry"))))
394
395(defun reftex-view-regexp-match (re &optional highlight-group new ref-buffer)
396 ;; Search for RE in current document or in the document of REF-BUFFER.
397 ;; Continue the search, if the same re was searched last.
398 ;; Highlight the group HIGHLIGHT-GROUP of the match.
399 ;; When NEW is non-nil, start a new search regardless.
400 ;; Match point is displayed in another window.
401 ;; Upon success, returns the window which displays the match.
402
403 ;;; Decide if new search or continued search
404 (let* ((oldprop (get 'reftex-view-regexp-match :props))
3666daf6
CD
405 (newprop (list (current-buffer) re))
406 (cont (and (not new) (equal oldprop newprop)))
407 (cnt (if cont (get 'reftex-view-regexp-match :cnt) 0))
408 (current-window (selected-window))
409 (window-conf (current-window-configuration))
410 match pop-window)
1a9461d0
CD
411 (switch-to-buffer-other-window (or ref-buffer (current-buffer)))
412 ;; Search
413 (condition-case nil
3666daf6
CD
414 (if cont
415 (setq match (reftex-global-search-continue))
416 (reftex-access-scan-info)
417 (setq match (reftex-global-search re (reftex-all-document-files))))
1a9461d0
CD
418 (error nil))
419 ;; Evaluate the match.
420 (if match
3666daf6
CD
421 (progn
422 (put 'reftex-view-regexp-match :props newprop)
423 (put 'reftex-view-regexp-match :cnt (incf cnt))
424 (reftex-highlight 0 (match-beginning highlight-group)
425 (match-end highlight-group))
426 (add-hook 'pre-command-hook 'reftex-highlight-shall-die)
427 (setq pop-window (selected-window)))
d8fb2015 428 (put 'reftex-view-regexp-match :props nil)
1a9461d0
CD
429 (or cont (set-window-configuration window-conf)))
430 (select-window current-window)
431 (if match
3666daf6
CD
432 (progn
433 (message "Match Nr. %s" cnt)
434 pop-window)
1a9461d0 435 (if cont
3666daf6
CD
436 (error "No further matches (total number of matches: %d)" cnt)
437 (error "No matches")))))
1a9461d0
CD
438
439(defvar reftex-global-search-marker (make-marker))
440(defun reftex-global-search (regexp file-list)
441 ;; Start a search for REGEXP in all files of FILE-LIST
442 (put 'reftex-global-search :file-list file-list)
443 (put 'reftex-global-search :regexp regexp)
444 (move-marker reftex-global-search-marker nil)
445 (reftex-global-search-continue))
446
447(defun reftex-global-search-continue ()
448 ;; Continue a global search started with `reftex-global-search'
449 (unless (get 'reftex-global-search :file-list)
450 (error "No global search to continue"))
451 (let* ((file-list (get 'reftex-global-search :file-list))
3666daf6
CD
452 (regexp (get 'reftex-global-search :regexp))
453 (buf (or (marker-buffer reftex-global-search-marker)
454 (reftex-get-file-buffer-force (car file-list))))
455 (pos (or (marker-position reftex-global-search-marker) 1))
456 file)
1a9461d0
CD
457 ;; Take up starting position
458 (unless buf (error "No such buffer %s" buf))
459 (switch-to-buffer buf)
460 (widen)
461 (goto-char pos)
462 ;; Search and switch file if necessary
463 (if (catch 'exit
3666daf6
CD
464 (while t
465 (when (re-search-forward regexp nil t)
466 (move-marker reftex-global-search-marker (point))
467 (throw 'exit t))
468 ;; No match - goto next file
469 (pop file-list)
470 (or file-list (throw 'exit nil))
471 (setq file (car file-list)
472 buf (reftex-get-file-buffer-force file))
473 (unless buf (error "Cannot access file %s" file))
474 (put 'reftex-global-search :file-list file-list)
475 (switch-to-buffer buf)
476 (widen)
477 (goto-char 1)))
478 t
1a9461d0
CD
479 (move-marker reftex-global-search-marker nil)
480 (error "All files processed"))))
481
ab5796a9 482;;; arch-tag: d2f52b56-744e-44ad-830d-1fc193b90eda
df543367 483;;; reftex-dcr.el ends here