Mercurial > emacs
diff lisp/textmodes/reftex-dcr.el @ 27170:3cba3e588544
renamed reftex-vcr.el to reftex-dcr.el
author | Carsten Dominik <dominik@science.uva.nl> |
---|---|
date | Wed, 05 Jan 2000 09:15:48 +0000 |
parents | |
children | f70a80cecdd3 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/textmodes/reftex-dcr.el Wed Jan 05 09:15:48 2000 +0000 @@ -0,0 +1,475 @@ +;;; reftex-dcr.el - Viewing cross references and citations with RefTeX +;; Copyright (c) 1997, 1998, 1999 Free Software Foundation, Inc. + +;; Author: Carsten Dominik <dominik@strw.LeidenUniv.nl> +;; Version: 4.9 +;; Keywords: tex + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +(eval-when-compile (require 'cl)) +(provide 'reftex-vcr) +(provide 'reftex-dcr) +(require 'reftex) +;;; + +(defun reftex-view-crossref (&optional arg auto-how) + "View cross reference of macro at point. Point must be on the KEY +argument. When at at `\ref' macro, show corresponding `\label' +definition, also in external documents (`xr'). When on a label, show +a locations where KEY is referenced. Subsequent calls find additional +locations. When on a `\cite', show the associated `\bibitem' macro or +the BibTeX database entry. When on a `\bibitem', show a `\cite' macro +which uses this KEY. When on an `\index', show other locations marked +by the same index entry. +To define additional cross referencing items, use the option +`reftex-view-crossref-extra'. See also `reftex-view-crossref-from-bibtex'. +With one or two C-u prefixes, enforce rescanning of the document. +With argument 2, select the window showing the cross reference. +AUTO-HOW is only for the automatic crossref display and is handed through +to the functions `reftex-view-cr-cite' and `reftex-view-cr-ref'." + + (interactive "P") + ;; See where we are. + (let* ((macro (car (reftex-what-macro-safe 1))) + (key (reftex-this-word "^{}%\n\r,")) + dw) + + (if (or (null macro) (reftex-in-comment)) + (error "Not on a crossref macro argument")) + + (setq reftex-call-back-to-this-buffer (current-buffer)) + + (cond + ((string-match "\\`\\\\cite\\|cite\\*?\\'" macro) + ;; A citation macro: search for bibitems or BibTeX entries + (setq dw (reftex-view-cr-cite arg key auto-how))) + ((string-match "\\`\\\\ref\\|ref\\(range\\)?\\*?\\'" macro) + ;; A reference macro: search for labels + (setq dw (reftex-view-cr-ref arg key auto-how))) + (auto-how nil) ;; No further action for automatic display (speed) + ((or (equal macro "\\label") + (member macro reftex-macros-with-labels)) + ;; A label macro: search for reference macros + (reftex-access-scan-info arg) + (setq dw (reftex-view-regexp-match + (format reftex-find-reference-format (regexp-quote key)) + 4 nil nil))) + ((equal macro "\\bibitem") + ;; A bibitem macro: search for citations + (reftex-access-scan-info arg) + (setq dw (reftex-view-regexp-match + (format reftex-find-citation-regexp-format (regexp-quote key)) + 3 nil nil))) + ((member macro reftex-macros-with-index) + (reftex-access-scan-info arg) + (setq dw (reftex-view-regexp-match + (format reftex-find-index-entry-regexp-format + (regexp-quote key)) + 3 nil nil))) + (t + (reftex-access-scan-info arg) + (catch 'exit + (let ((list reftex-view-crossref-extra) + entry mre action group) + (while (setq entry (pop list)) + (setq mre (car entry) + action (nth 1 entry) + group (nth 2 entry)) + (when (string-match mre macro) + (setq dw (reftex-view-regexp-match + (format action key) group nil nil)) + (throw 'exit t)))) + (error "Not on a crossref macro argument")))) + (if (and (eq arg 2) (windowp dw)) (select-window dw)))) + +(defun reftex-view-cr-cite (arg key how) + ;; View crossreference of a ref cite. HOW can have the values + ;; nil: Show in another window. + ;; echo: Show one-line info in echo area. + ;; tmp-window: Show in small window and arrange for window to disappear. + + ;; Ensure access to scanning info + (reftex-access-scan-info (or arg current-prefix-arg)) + + (if (eq how 'tmp-window) + ;; Remember the window configuration + (put 'reftex-auto-view-crossref 'last-window-conf + (current-window-configuration))) + + (let (files size item (pos (point)) (win (selected-window)) pop-win) + ;; Find the citation mode and the file list + (cond + ((assq 'bib (symbol-value reftex-docstruct-symbol)) + (setq item nil + files (reftex-get-bibfile-list))) + ((assq 'thebib (symbol-value reftex-docstruct-symbol)) + (setq item t + files (reftex-uniquify + (mapcar 'cdr + (reftex-all-assq + 'thebib (symbol-value reftex-docstruct-symbol)))))) + (reftex-default-bibliography + (setq item nil + files (reftex-default-bibliography))) + (how) ;; don't throw for special display + (t (error "Cannot display crossref"))) + + (if (eq how 'echo) + ;; Display in Echo area + (reftex-echo-cite key files item) + ;; Display in a window + (if (not (eq how 'tmp-window)) + ;; Normal display + (reftex-pop-to-bibtex-entry key files nil t item) + ;; A temporary window + (condition-case nil + (reftex-pop-to-bibtex-entry key files nil t item) + (error (goto-char pos) + (message "cite: no such citation key %s" key) + (error ""))) + ;; Resize the window + (setq size (max 1 (count-lines (point) + (reftex-end-of-bib-entry item)))) + (let ((window-min-height 2)) + (shrink-window (1- (- (window-height) size))) + (recenter 0)) + ;; Arrange restoration + (add-hook 'pre-command-hook 'reftex-restore-window-conf)) + + ;; Normal display in other window + (add-hook 'pre-command-hook 'reftex-highlight-shall-die) + (setq pop-win (selected-window)) + (select-window win) + (goto-char pos) + (when (equal arg 2) + (select-window pop-win))))) + +(defun reftex-view-cr-ref (arg label how) + ;; View crossreference of a ref macro. HOW can have the values + ;; nil: Show in another window. + ;; echo: Show one-line info in echo area. + ;; tmp-window: Show in small window and arrange for window to disappear. + + ;; Ensure access to scanning info + (reftex-access-scan-info (or arg current-prefix-arg)) + + (if (eq how 'tmp-window) + ;; Remember the window configuration + (put 'reftex-auto-view-crossref 'last-window-conf + (current-window-configuration))) + + (let* ((xr-data (assoc 'xr (symbol-value reftex-docstruct-symbol))) + (xr-re (nth 2 xr-data)) + (entry (assoc label (symbol-value reftex-docstruct-symbol))) + (win (selected-window)) pop-win (pos (point))) + + (if (and (not entry) (stringp label) xr-re (string-match xr-re label)) + ;; Label is defined in external document + (save-excursion + (save-match-data + (set-buffer + (or (reftex-get-file-buffer-force + (cdr (assoc (match-string 1 label) (nth 1 + xr-data)))) + (error "Problem with external label %s" label)))) + (setq label (substring label (match-end 1))) + (reftex-access-scan-info) + (setq entry + (assoc label (symbol-value reftex-docstruct-symbol))))) + (if (eq how 'echo) + ;; Display in echo area + (reftex-echo-ref label entry (symbol-value reftex-docstruct-symbol)) + (let ((window-conf (current-window-configuration))) + (condition-case nil + (reftex-show-label-location entry t nil t t) + (error (set-window-configuration window-conf) + (message "ref: Label %s not found" label) + (error "ref: Label %s not found" label)))) ;; 2nd is line OK + (add-hook 'pre-command-hook 'reftex-highlight-shall-die) + + (when (eq how 'tmp-window) + ;; Resize window and arrange restauration + (shrink-window (1- (- (window-height) 9))) + (recenter '(4)) + (add-hook 'pre-command-hook 'reftex-restore-window-conf)) + (setq pop-win (selected-window)) + (select-window win) + (goto-char pos) + (when (equal arg 2) + (select-window pop-win))))) + +(defun reftex-mouse-view-crossref (ev) + "View cross reference of \\ref or \\cite macro where you click. +If the macro at point is a \\ref, show the corresponding label definition. +If it is a \\cite, show the BibTeX database entry. +If there is no such macro at point, search forward to find one. +With argument, actually select the window showing the cross reference." + (interactive "e") + (mouse-set-point ev) + (reftex-view-crossref current-prefix-arg)) + +(defun reftex-view-crossref-when-idle () + ;; Display info about crossref at point in echo area or a window. + ;; This function was desigend to work with an idle timer. + ;; We try to get out of here as quickly as possible if the call is useless. + (and reftex-mode + ;; Make sure message area is free if we need it. + (or (eq reftex-auto-view-crossref 'window) (not (current-message))) + ;; Make sure we are not already displaying this one + (not (memq last-command '(reftex-view-crossref + reftex-mouse-view-crossref))) + ;; Quick precheck if this might be a relevant spot + ;; FIXME: Can fail with backslash in comment + (save-excursion + (search-backward "\\" nil t) + (looking-at "\\\\[a-zA-Z]*\\(cite\\|ref\\)")) + + (condition-case nil + (let ((current-prefix-arg nil)) + (cond + ((eq reftex-auto-view-crossref t) + (reftex-view-crossref -1 'echo)) + ((eq reftex-auto-view-crossref 'window) + (reftex-view-crossref -1 'tmp-window)) + (t nil))) + (error nil)))) + +(defun reftex-restore-window-conf () + (set-window-configuration (get 'reftex-auto-view-crossref 'last-window-conf)) + (put 'reftex-auto-view-crossref 'last-window-conf nil) + (remove-hook 'pre-command-hook 'reftex-restore-window-conf)) + +(defun reftex-echo-ref (label entry docstruct) + ;; Display crossref info in echo area. + (cond + ((null docstruct) + (message (substitute-command-keys (format reftex-no-info-message "ref")))) + ((null entry) + (message "ref: unknown label: %s" label)) + (t + (when (stringp (nth 2 entry)) + (message "ref(%s): %s" (nth 1 entry) (nth 2 entry))) + (let ((buf (get-buffer " *Echo Area*"))) + (when buf + (save-excursion + (set-buffer buf) + (run-hooks 'reftex-display-copied-context-hook))))))) + +(defun reftex-echo-cite (key files item) + ;; Display citation info in echo area. + (let* ((cache (assq 'bibview-cache (symbol-value reftex-docstruct-symbol))) + (cache-entry (assoc key (cdr cache))) + entry string buf (all-files files)) + + (if (and reftex-cache-cite-echo cache-entry) + ;; We can just use the cache + (setq string (cdr cache-entry)) + + ;; Need to look in the database + (unless reftex-revisit-to-echo + (setq files (reftex-visited-files files))) + + (setq entry + (condition-case nil + (save-excursion + (reftex-pop-to-bibtex-entry key files nil nil item t)) + (error + (if (and files (= (length all-files) (length files))) + (message "cite: no such database entry: %s" key) + (message (substitute-command-keys + (format reftex-no-info-message "cite")))) + nil))) + (when entry + (if item + (setq string (reftex-nicify-text entry)) + (setq string (reftex-make-cite-echo-string + (reftex-parse-bibtex-entry entry) + reftex-docstruct-symbol))))) + (unless (or (null string) (equal string "")) + (message "cite: %s" string)) + (when (setq buf (get-buffer " *Echo Area*")) + (save-excursion + (set-buffer buf) + (run-hooks 'reftex-display-copied-context-hook))))) + +(defvar reftex-use-itimer-in-xemacs nil + "*Non-nil means use the idle timers in XEmacs for crossref display. +Currently, idle timer restart is broken and we use the post-command-hook.") + +(defun reftex-toggle-auto-view-crossref () + "Toggle the automatic display of crossref information in the echo area. +When active, leaving point idle in the argument of a \\ref or \\cite macro +will display info in the echo area." + (interactive) + (if reftex-auto-view-crossref-timer + (progn + (if (featurep 'xemacs) + (if reftex-use-itimer-in-xemacs + (delete-itimer reftex-auto-view-crossref-timer) + (remove-hook 'post-command-hook 'reftex-start-itimer-once)) + (cancel-timer reftex-auto-view-crossref-timer)) + (setq reftex-auto-view-crossref-timer nil) + (message "Automatic display of crossref information was turned off")) + (setq reftex-auto-view-crossref-timer + (if (featurep 'xemacs) + (if reftex-use-itimer-in-xemacs + (start-itimer "RefTeX Idle Timer" + 'reftex-view-crossref-when-idle + reftex-idle-time reftex-idle-time t) + (add-hook 'post-command-hook 'reftex-start-itimer-once) + t) + (run-with-idle-timer + reftex-idle-time t 'reftex-view-crossref-when-idle))) + (unless reftex-auto-view-crossref + (setq reftex-auto-view-crossref t)) + (message "Automatic display of crossref information was turned on"))) + +(defun reftex-start-itimer-once () + (and reftex-mode + (not (itimer-live-p reftex-auto-view-crossref-timer)) + (setq reftex-auto-view-crossref-timer + (start-itimer "RefTeX Idle Timer" + 'reftex-view-crossref-when-idle + reftex-idle-time nil t)))) + +(defun reftex-view-crossref-from-bibtex (&optional arg) + "View location in a LaTeX document which cites the BibTeX entry at point. +Since BibTeX files can be used by many LaTeX documents, this function +prompts upon first use for a buffer in RefTeX mode. To reset this +link to a document, call the function with with a prefix arg. +Calling this function several times find successive citation locations." + (interactive "P") + (when arg + ;; Break connection to reference buffer + (remprop 'reftex-bibtex-view-cite-locations :ref-buffer)) + (let ((ref-buffer (get 'reftex-bibtex-view-cite-locations :ref-buffer))) + ;; Establish connection to reference buffer + (unless ref-buffer + (setq ref-buffer + (save-excursion + (completing-read + "Reference buffer: " + (delq nil + (mapcar + (lambda (b) + (set-buffer b) + (if reftex-mode (list (buffer-name b)) nil)) + (buffer-list))) + nil t))) + (put 'reftex-bibtex-view-cite-locations :ref-buffer ref-buffer)) + ;; Search for citations + (bibtex-beginning-of-entry) + (if (looking-at + "@[a-zA-Z]+[ \t\n\r]*[{(][ \t\n\r]*\\([^, \t\r\n}]+\\)") + (progn + (goto-char (match-beginning 1)) + (reftex-view-regexp-match + (format reftex-find-citation-regexp-format + (regexp-quote (match-string 1))) + 3 arg ref-buffer)) + (error "Cannot find citation key in BibTeX entry")))) + +(defun reftex-view-regexp-match (re &optional highlight-group new ref-buffer) + ;; Search for RE in current document or in the document of REF-BUFFER. + ;; Continue the search, if the same re was searched last. + ;; Highlight the group HIGHLIGHT-GROUP of the match. + ;; When NEW is non-nil, start a new search regardless. + ;; Match point is displayed in another window. + ;; Upon success, returns the window which displays the match. + + ;;; Decide if new search or continued search + (let* ((oldprop (get 'reftex-view-regexp-match :props)) + (newprop (list (current-buffer) re)) + (cont (and (not new) (equal oldprop newprop))) + (cnt (if cont (get 'reftex-view-regexp-match :cnt) 0)) + (current-window (selected-window)) + (window-conf (current-window-configuration)) + match pop-window) + (switch-to-buffer-other-window (or ref-buffer (current-buffer))) + ;; Search + (condition-case nil + (if cont + (setq match (reftex-global-search-continue)) + (reftex-access-scan-info) + (setq match (reftex-global-search re (reftex-all-document-files)))) + (error nil)) + ;; Evaluate the match. + (if match + (progn + (put 'reftex-view-regexp-match :props newprop) + (put 'reftex-view-regexp-match :cnt (incf cnt)) + (reftex-highlight 0 (match-beginning highlight-group) + (match-end highlight-group)) + (add-hook 'pre-command-hook 'reftex-highlight-shall-die) + (setq pop-window (selected-window))) + (remprop 'reftex-view-regexp-match :props) + (or cont (set-window-configuration window-conf))) + (select-window current-window) + (if match + (progn + (message "Match Nr. %s" cnt) + pop-window) + (if cont + (error "No further matches (total number of matches: %d)" cnt) + (error "No matches"))))) + +(defvar reftex-global-search-marker (make-marker)) +(defun reftex-global-search (regexp file-list) + ;; Start a search for REGEXP in all files of FILE-LIST + (put 'reftex-global-search :file-list file-list) + (put 'reftex-global-search :regexp regexp) + (move-marker reftex-global-search-marker nil) + (reftex-global-search-continue)) + +(defun reftex-global-search-continue () + ;; Continue a global search started with `reftex-global-search' + (unless (get 'reftex-global-search :file-list) + (error "No global search to continue")) + (let* ((file-list (get 'reftex-global-search :file-list)) + (regexp (get 'reftex-global-search :regexp)) + (buf (or (marker-buffer reftex-global-search-marker) + (reftex-get-file-buffer-force (car file-list)))) + (pos (or (marker-position reftex-global-search-marker) 1)) + file) + ;; Take up starting position + (unless buf (error "No such buffer %s" buf)) + (switch-to-buffer buf) + (widen) + (goto-char pos) + ;; Search and switch file if necessary + (if (catch 'exit + (while t + (when (re-search-forward regexp nil t) + (move-marker reftex-global-search-marker (point)) + (throw 'exit t)) + ;; No match - goto next file + (pop file-list) + (or file-list (throw 'exit nil)) + (setq file (car file-list) + buf (reftex-get-file-buffer-force file)) + (unless buf (error "Cannot access file %s" file)) + (put 'reftex-global-search :file-list file-list) + (switch-to-buffer buf) + (widen) + (goto-char 1))) + t + (move-marker reftex-global-search-marker nil) + (error "All files processed")))) + +;;; reftex-dcr.el ends here