comparison lisp/textmodes/refer.el @ 16473:4ef76e689d69

(refer-bib-directory): New variable, list of directories where to look for bib files. Special values `texinputs' and `bibinputs' mean take directory list from corresponding environment variable. (refer-bib-files): New special value `auto', for looking up all files in directories pointed to by refer-bib-directory. I have the feeling that this isn't really my code but came from the net (copylefted). However, I cannot trace this down any more. If it isn't mine, it's probably Ashwin's. (refer-get-bib-files): Support `auto' value of refer-bib-files. Support `texinputs', `bibinputs' value of refer-bib-directory. (refer-saved-state, refer-previous-keywords, refer-saved-pos, refer-same-file): Properly declared (defvar) these variables. (refer-yank-key): New function. (refer-find-entry-internal): Find bibliography entries in other window, with minimal reconfiguration of windows. (refer-expand-files): New function.
author Richard M. Stallman <rms@gnu.org>
date Sat, 26 Oct 1996 18:15:32 +0000
parents 83f275dcd93a
children 9b831f34ff7d
comparison
equal deleted inserted replaced
16472:dbfab9e8b6d8 16473:4ef76e689d69
1 ;;; refer.el --- look up references in bibliography files. 1 ;;; refer.el --- look up references in bibliography files.
2 2
3 ;; Copyright (C) 1992 Free Software Foundation, Inc. 3 ;; Copyright (C) 1992, 1996 Free Software Foundation, Inc.
4 4
5 ;; Author: Ashwin Ram <Ram-Ashwin@cs.yale.edu> 5 ;; Author: Ashwin Ram <ashwin@cc.gatech.edu>
6 ;; Maintainer: Gernot Heiser <gernot@jungfrau.disy.cse.unsw.EDU.AU>
6 ;; Adapted-By: ESR 7 ;; Adapted-By: ESR
7 ;; Keywords: bib 8 ;; Keywords: bib
8 9
9 ;; This file is part of GNU Emacs. 10 ;; This file is part of GNU Emacs.
10 11
40 ;; as search strings). 41 ;; as search strings).
41 ;; 42 ;;
42 ;; To continue the previous search, i.e., to search for the next occurrence 43 ;; To continue the previous search, i.e., to search for the next occurrence
43 ;; of the keywords, use refer-find-next-entry, or invoke refer-find-entry 44 ;; of the keywords, use refer-find-next-entry, or invoke refer-find-entry
44 ;; with a prefix argument. 45 ;; with a prefix argument.
46 ;;
47 ;; Once you've found the entry you want to reference, invoke
48 ;; refer-yank-key to insert it at point in the current buffer
49 ;; (typically as the argument of a \cite{} command).
50 ;;
51 ;; I use (define-key tex-mode-map "\C-c\C-y" 'refer-yank-key)
52 ;; to bind this often-used function to a key in (la)tex-mode.
45 ;; 53 ;;
46 ;; If the list of bibliography files changes, reinitialize the variable 54 ;; If the list of bibliography files changes, reinitialize the variable
47 ;; refer-bib-files. 55 ;; refer-bib-files.
48 ;; 56 ;;
49 ;; To customize: 57 ;; To customize:
58 ;; specified. So you should be able to use pretty much any bib file with 66 ;; specified. So you should be able to use pretty much any bib file with
59 ;; this code. If your bib file does not use paragraphs to separate 67 ;; this code. If your bib file does not use paragraphs to separate
60 ;; entries, try setting the paragraph-start/separate variables, or changing 68 ;; entries, try setting the paragraph-start/separate variables, or changing
61 ;; the (forward-paragraph 1) call in refer-find-entry-in-file. 69 ;; the (forward-paragraph 1) call in refer-find-entry-in-file.
62 70
63 ;;; ChangeLog:
64
65 ;; 01/08/89 Ashwin Ram <Ram-Ashwin@cs.yale.edu>
66 ;; Initial release.
67 ;;
68
69 ;;; Code: 71 ;;; Code:
70 72
71 (provide 'refer) 73 (provide 'refer)
74
75 (defvar refer-bib-directory nil
76 "Directory, or list of directories, to search for \\.bib files. Can
77 be set to 'bibinputs or 'texinputs, in which case the environment
78 variable BIBINPUTS or TEXINPUTS, respectively, is used to obtain a
79 list of directories. Useful only if refer-bib-files is set to 'dir or
80 a list of file names (without directory). A value of nil indicates the
81 current working directory.
82
83 If refer-bib-directory is 'bibinputs or 'texinputs, it is setq'd to
84 the appropriate list of directories when it is first used.
85
86 Note that an empty directory is interpreted by BibTeX as indicating
87 the default search path. Since Refer does not know that default path,
88 it cannot search it. Include that path explicitly in your BIBINPUTS
89 environment if you really want it searched (which is not likely to
90 happen anyway).")
72 91
73 (defvar refer-bib-files 'dir 92 (defvar refer-bib-files 'dir
74 "*List of \\.bib files to search for references, 93 "*List of \\.bib files to search for references,
75 or one of the following special values: 94 or one of the following special values:
76 nil = prompt for \\.bib file (if visiting a \\.bib file, use it as default) 95 nil = prompt for \\.bib file (if visiting a \\.bib file, use it as default)
77 auto = read \\.bib file names from appropriate command in buffer (see refer-bib-files-regexp) 96 auto = read \\.bib file names from appropriate command in buffer (see
78 dir = use all \\.bib files in current directory. 97 refer-bib-files-regexp) unless the buffer's mode is bibtex-mode,
98 in which case only the buffer is searched
99 dir = use all \\.bib files in directories referenced by refer-bib-directory.
79 100
80 If a specified file doesn't exist and has no extension, a \\.bib extension 101 If a specified file doesn't exist and has no extension, a \\.bib extension
81 is automatically tried. 102 is automatically tried.
82 103
83 If refer-bib-files is nil, auto or dir, it is setq'd to the appropriate 104 If refer-bib-files is nil, auto or dir, it is setq'd to the appropriate
94 (defvar refer-bib-files-regexp "\\\\bibliography" 115 (defvar refer-bib-files-regexp "\\\\bibliography"
95 "*Regexp matching a bibliography file declaration. 116 "*Regexp matching a bibliography file declaration.
96 The current buffer is expected to contain a line such as 117 The current buffer is expected to contain a line such as
97 \\bibliography{file1,file2,file3} 118 \\bibliography{file1,file2,file3}
98 which is read to set up refer-bib-files. The regexp must specify the command 119 which is read to set up refer-bib-files. The regexp must specify the command
99 \(such as \\bibliography) that is used to specify the list of bib files. The 120 (such as \\bibliography) that is used to specify the list of bib files. The
100 command is expected to specify a file name, or a list of comma-separated file 121 command is expected to specify a file name, or a list of comma-separated file
101 names, within curly braces. 122 names, within curly braces.
102 If a specified file doesn't exist and has no extension, a \\.bib extension 123 If a specified file doesn't exist and has no extension, a \\.bib extension
103 is automatically tried.") 124 is automatically tried.")
104 125
105 (make-variable-buffer-local 'refer-bib-files) 126 (make-variable-buffer-local 'refer-bib-files)
106 (make-variable-buffer-local 'refer-cache-bib-files) 127 (make-variable-buffer-local 'refer-cache-bib-files)
128 (make-variable-buffer-local 'refer-bib-directory)
129
130 ;;; Internal variables
131 (defvar refer-saved-state nil)
132 (defvar refer-previous-keywords nil)
133 (defvar refer-saved-pos nil)
134 (defvar refer-same-file nil)
107 135
108 (defun refer-find-entry (keywords &optional continue) 136 (defun refer-find-entry (keywords &optional continue)
109 "Find entry in refer-bib-files containing KEYWORDS. 137 "Find entry in refer-bib-files containing KEYWORDS.
110 If KEYWORDS is nil, prompt user for blank-separated list of keywords. 138 If KEYWORDS is nil, prompt user for blank-separated list of keywords.
111 If CONTINUE is t, or if called interactively with a prefix arg, look for next 139 If CONTINUE is t, or if called interactively with a prefix arg, look for next
112 entry by continuing search from previous point." 140 entry by continuing search from previous point."
113 (interactive (list nil current-prefix-arg)) 141 (interactive (list nil current-prefix-arg))
114 (or keywords (setq keywords (if continue 142 (or keywords (setq keywords (if continue
115 refer-previous-keywords 143 refer-previous-keywords
116 (read-string "Keywords: ")))) 144 (read-string "Keywords: "))))
117 (setq refer-previous-keywords keywords) 145 (setq refer-previous-keywords keywords)
118 (refer-find-entry-internal keywords continue)) 146 (refer-find-entry-internal keywords continue))
119 147
120 (defun refer-find-next-entry () 148 (defun refer-find-next-entry ()
121 "Find next occurrence of entry in refer-bib-files. See refer-find-entry." 149 "Find next occurrence of entry in refer-bib-files. See refer-find-entry."
122 (interactive) 150 (interactive)
123 (refer-find-entry-internal refer-previous-keywords t)) 151 (refer-find-entry-internal refer-previous-keywords t))
124 152
153 (defun refer-yank-key ()
154 "Inserts at point in current buffer the \"key\" field of the entry
155 found on the last refer-find-entry or refer-find-next-entry."
156 (interactive)
157 (let ((old-point (point)))
158 (insert
159 (save-window-excursion
160 (save-excursion
161 (find-file (car refer-saved-state))
162 (if (looking-at
163 "[ \t\n]*@\\s-*[a-zA-Z][a-zA-Z0-9]*\\s-*{\\s-*\\([^ \t\n,]+\\)\\s-*,")
164 (buffer-substring (match-beginning 1) (match-end 1))
165 (error "Cannot find key for entry in file %s."
166 (car refer-saved-state))))))
167 (if (not (= (point) old-point))
168 (set-mark old-point))))
169
125 (defun refer-find-entry-internal (keywords continue) 170 (defun refer-find-entry-internal (keywords continue)
126 (let ((keywords-list (refer-convert-string-to-list-of-strings keywords)) 171 (let ((keywords-list (refer-convert-string-to-list-of-strings keywords))
172 (old-buffer (current-buffer))
173 (old-window (selected-window))
174 (new-window (selected-window))
127 (files (if continue 175 (files (if continue
128 refer-saved-state 176 refer-saved-state
129 (refer-get-bib-files)))) 177 (setq refer-saved-pos nil)
130 (catch 'found 178 (refer-get-bib-files)))
131 (while files 179 (n 0)
132 (let ((file (cond ((file-exists-p (car files)) (car files)) 180 (found nil)
133 ((file-exists-p (concat (car files) ".bib")) (concat (car files) ".bib"))))) 181 (file nil))
134 (setq refer-saved-state files) 182 ;; find window in which to display bibliography file.
135 (if file 183 ;; if a bibliography file is already displayed in a window, use
136 (if (refer-find-entry-in-file keywords-list file continue) 184 ;; that one, otherwise use any window other than the current one
137 (throw 'found (find-file file)) 185 (while (not found)
138 (setq files (cdr files))) 186 (while (and (not (null (setq file (nth n files))))
139 (progn (message "Scanning %s... No such file" (car files) (ding)) 187 (setq n (1+ n))
140 (sit-for 1) 188 (not (string-equal file
141 (setq files (cdr files)))))) 189 (buffer-file-name
142 (message "Keywords \"%s\" not found in any \.bib file" keywords (ding))))) 190 (window-buffer new-window))))))
143 191 (setq found
144 (defun refer-find-entry-in-file (keywords-list file &optional continue) 192 (if (null file)
145 (message "Scanning %s..." file) ; (expand-file-name file) 193 (eq (setq new-window (next-window new-window 'nomini))
194 old-window)
195 't)))
196 (if (null file) ; didn't find bib file in any window:
197 (progn (if (one-window-p 'nomini)
198 (setq old-window (split-window)))
199 (setq new-window (next-window old-window 'nomini))))
200 (select-window (if refer-same-file
201 old-window
202 new-window)) ; the window in which to show the bib file
203 (catch 'found
204 (while files
205 (let ((file (cond ((file-exists-p (car files)) (car files))
206 ((file-exists-p (concat (car files) ".bib"))
207 (concat (car files) ".bib")))))
208 (setq refer-saved-state files)
209 (if file
210 (if (refer-find-entry-in-file keywords-list file refer-saved-pos)
211 (progn
212 (setq refer-saved-pos (point))
213 (recenter 0)
214 (throw 'found (find-file file)))
215 (setq refer-saved-pos nil
216 files (cdr files)))
217 (progn (message "Scanning %s... No such file" (car files) (ding))
218 (sit-for 1)
219 (setq files (cdr files))))))
220 (message "Keywords \"%s\" not found in any \.bib file" keywords (ding)))
221 (select-window old-window)))
222
223 (defun refer-find-entry-in-file (keywords-list file &optional old-pos)
224 (message "Scanning %s..." file)
225 (expand-file-name file)
146 (set-buffer (find-file-noselect file)) 226 (set-buffer (find-file-noselect file))
147 (if continue 227 (find-file file)
148 (forward-paragraph 1) 228 (if (not old-pos)
149 (goto-char (point-min))) 229 (goto-char (point-min))
230 (goto-char old-pos)
231 (forward-paragraph 1))
150 (let ((begin (point)) 232 (let ((begin (point))
151 (end 0) 233 (end 0)
152 (found nil)) 234 (found nil))
153 (while (and (not found) 235 (while (and (not found)
154 (not (eobp))) 236 (not (eobp)))
155 (forward-paragraph 1) 237 (forward-paragraph 1)
156 (setq end (point)) 238 (setq end (point))
157 (setq found 239 (setq found
158 (refer-every (function (lambda (keyword) 240 (refer-every (function (lambda (keyword)
159 (goto-char begin) 241 (goto-char begin)
160 (re-search-forward keyword end t))) 242 (re-search-forward keyword end t)))
161 keywords-list)) 243 keywords-list))
162 (if (not found) 244 (if (not found)
163 (progn 245 (progn
164 (setq begin end) 246 (setq begin end)
165 (goto-char begin)))) 247 (goto-char begin))))
166 (if found 248 (if found
167 (progn (goto-char begin) 249 (progn (goto-char begin)
168 (re-search-forward "\\W" nil t) 250 (re-search-forward "\\W" nil t)
169 (message "Scanning %s... found" file)) 251 (message "Scanning %s... found" file))
170 (progn (message "Scanning %s... not found" file) 252 (progn (message "Scanning %s... not found" file)
171 nil)))) 253 nil))))
172 254
173 (defun refer-every (pred l) 255 (defun refer-every (pred l)
174 (cond ((null l) nil) 256 (cond ((null l) nil)
175 ((funcall pred (car l)) 257 ((funcall pred (car l))
176 (or (null (cdr l)) 258 (or (null (cdr l))
177 (refer-every pred (cdr l)))))) 259 (refer-every pred (cdr l))))))
178 260
179 (defun refer-convert-string-to-list-of-strings (s) 261 (defun refer-convert-string-to-list-of-strings (s)
180 (let ((current (current-buffer)) 262 (let ((current (current-buffer))
181 (temp-buffer (get-buffer-create "*refer-temp*"))) 263 (temp-buffer (get-buffer-create "*refer-temp*")))
182 (set-buffer temp-buffer) 264 (set-buffer temp-buffer)
190 (insert "\")") 272 (insert "\")")
191 (goto-char (point-min)) 273 (goto-char (point-min))
192 (prog1 (read temp-buffer) 274 (prog1 (read temp-buffer)
193 (set-buffer current)))) 275 (set-buffer current))))
194 276
277 (defun refer-expand-files (file-list dir-list)
278 (let (file files dir dirs)
279 (while (setq file (car file-list))
280 (setq dirs (copy-alist dir-list))
281 (while (setq dir (car dirs))
282 (if (file-exists-p (expand-file-name file dir))
283 (setq files (append files (list (expand-file-name file dir)))
284 dirs nil)
285 (if (file-exists-p (expand-file-name (concat file ".bib") dir))
286 (setq files (append files (list (expand-file-name (concat file ".bib")
287 dir)))
288 dirs nil)
289 (setq dirs (cdr dirs)))))
290 (setq file-list (cdr file-list)))
291 files))
292
195 (defun refer-get-bib-files () 293 (defun refer-get-bib-files ()
196 (let ((files 294 (let* ((dir-list
197 (cond ((null refer-bib-files) 295 (cond
198 (list (expand-file-name 296 ((null refer-bib-directory)
199 (if (eq major-mode 'bibtex-mode) 297 '("."))
200 (read-file-name (format ".bib file: (default %s) " (file-name-nondirectory (buffer-file-name))) 298 ((or (eq refer-bib-directory 'texinputs)
201 (file-name-directory (buffer-file-name)) 299 (eq refer-bib-directory 'bibinputs))
202 (file-name-nondirectory (buffer-file-name)) 300 (let ((envvar (getenv (if (eq refer-bib-directory 'texinputs)
203 t) 301 "TEXINPUTS"
204 (read-file-name ".bib file: " nil nil t))))) 302 "BIBINPUTS")))
205 ((listp refer-bib-files) refer-bib-files) 303 (dirs nil))
206 ((eq refer-bib-files 'auto) 304 (if (null envvar)
207 (save-excursion 305 (setq envvar "."))
208 (if (progn (goto-char (point-min)) 306 (while (string-match ":" envvar)
209 (re-search-forward (concat refer-bib-files-regexp "\{") nil t)) 307 (let ((dir (substring envvar 0 (match-beginning 0))))
210 (let ((files (list (buffer-substring (point) 308 (if (and (not (string-equal "" dir))
211 (progn (re-search-forward "[,\}]" nil t) 309 (file-directory-p dir))
212 (backward-char 1) 310 (setq dirs (append (list (expand-file-name dir nil))
213 (point)))))) 311 dirs))))
214 (while (not (looking-at "\}")) 312 (setq envvar (substring envvar (match-end 0))))
215 (setq files (append files 313 (if (and (not (string-equal "" envvar))
216 (list (buffer-substring (progn (forward-char 1) 314 (file-directory-p envvar))
217 (point)) 315 (setq dirs (append (list envvar) dirs)))
218 (progn (re-search-forward "[,\}]" nil t) 316 (setq dirs (nreverse dirs))))
219 (backward-char 1) 317 ((listp refer-bib-directory)
220 (point))))))) 318 refer-bib-directory)
221 files) 319 (t
222 (error "No \\\\bibliography command in this buffer, can't read refer-bib-files")))) 320 (list refer-bib-directory))))
223 ((eq refer-bib-files 'dir) 321 (files
224 (directory-files "." t "\\.bib$")) 322 (cond
225 (t (error "Illegal value for refer-bib-files: %s" refer-bib-files))))) 323 ((null refer-bib-files)
226 (if refer-cache-bib-files 324 (list (expand-file-name
227 (setq refer-bib-files files)) 325 (if (eq major-mode 'bibtex-mode)
228 files)) 326 (read-file-name
327 (format ".bib file: (default %s) "
328 (file-name-nondirectory
329 (buffer-file-name)))
330 (file-name-directory (buffer-file-name))
331 (file-name-nondirectory (buffer-file-name))
332 t)
333 (read-file-name ".bib file: " nil nil t)))))
334 ((eq refer-bib-files 'auto)
335 (let ((files
336 (save-excursion
337 (if (setq refer-same-file (eq major-mode 'bibtex-mode))
338 (list buffer-file-name)
339 (if (progn
340 (goto-char (point-min))
341 (re-search-forward (concat refer-bib-files-regexp
342 "\\s-*\{") nil t))
343 (let ((files (list (buffer-substring
344 (point)
345 (progn
346 (re-search-forward "[,\}]"
347 nil t)
348 (backward-char 1)
349 (point))))))
350 (while (not (looking-at "\}"))
351 (setq files (append files
352 (list (buffer-substring
353 (progn (forward-char 1)
354 (point))
355 (progn (re-search-forward
356 "[,\}]" nil t)
357 (backward-char 1)
358 (point)))))))
359 files)
360 (error (concat "No \\\\bibliography command in this "
361 "buffer, can't read refer-bib-files")))))))
362 (refer-expand-files files dir-list)))
363 ((eq refer-bib-files 'dir)
364 (let ((dirs (nreverse dir-list))
365 dir files)
366 (while (setq dir (car dirs))
367 (setq files
368 (append (directory-files dir t "\\.bib$")
369 files))
370 (setq dirs (cdr dirs)))
371 files))
372 ((and (listp refer-bib-files)
373 (or (eq refer-bib-directory 'texinputs)
374 (eq refer-bib-directory 'bibinputs)))
375 (refer-expand-files refer-bib-files dir-list))
376 ((listp refer-bib-files) refer-bib-files)
377 (t (error "Illegal value for refer-bib-files: %s"
378 refer-bib-files)))))
379 (if (or (eq refer-bib-directory 'texinputs)
380 (eq refer-bib-directory 'bibinputs))
381 (setq refer-bib-directory dir-list))
382 (if refer-cache-bib-files
383 (setq refer-bib-files files))
384 files))
229 385
230 ;;; refer.el ends here 386 ;;; refer.el ends here
387