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