Commit | Line | Data |
---|---|---|
b3bf02fa RS |
1 | ;;; bookmark.el --- set bookmarks, jump to them later. |
2 | ||
3 | ;; Copyright (C) 1993 Free Software Foundation, Inc. | |
4 | ||
5 | ;; Author: Karl Fogel <kfogel@cs.oberlin.edu> | |
8027e2ad | 6 | ;; Maintainer: Karl Fogel <kfogel@cs.oberlin.edu> |
b3bf02fa | 7 | ;; Created: July, 1993 |
11eb4275 | 8 | ;; Version: 1.7.3 (interim) |
b3bf02fa RS |
9 | ;; Keywords: bookmarks, placeholders |
10 | ||
11 | ;; This file is part of GNU Emacs. | |
12 | ||
13 | ;; GNU Emacs is free software; you can redistribute it and/or modify | |
14 | ;; it under the terms of the GNU General Public License as published by | |
15 | ;; the Free Software Foundation; either version 2, or (at your option) | |
16 | ;; any later version. | |
17 | ||
18 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | ;; GNU General Public License for more details. | |
22 | ||
23 | ;; You should have received a copy of the GNU General Public License | |
24 | ;; along with GNU Emacs; see the file COPYING. If not, write to | |
25 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
26 | ||
27 | ;; Thanks to David Bremner <bremner@cs.sfu.ca> for thinking of and | |
28 | ;; then implementing the bookmark-current-bookmark idea. He even | |
29 | ;; sent *patches*, bless his soul... | |
30 | ||
31 | ;; Thanks to Gregory M. Saunders <saunders@cis.ohio-state.edu> for | |
32 | ;; fixing and improving bookmark-time-to-save-p. | |
33 | ||
34 | ;; Based on info-bookmark.el, by Karl Fogel and Ken Olstad | |
35 | ;; <olstad@msc.edu>. | |
36 | ||
37 | ;; LCD Archive Entry: | |
38 | ;; bookmark|Karl Fogel|kfogel@cs.oberlin.edu| | |
39 | ;; Setting bookmarks in files or directories, jumping to them later.| | |
40 | ;; 16-July-93|Version: 1.7.2|~/misc/bookmark.el.Z| | |
41 | ||
42 | ;; FAVORITE CHINESE RESTAURANT: | |
43 | ;; Boy, that's a tough one. Probably Hong Min, or maybe Emperor's | |
44 | ;; Choice (both in Chicago's Chinatown). Well, both. How about you? | |
45 | ||
46 | ;;; Commentary on code: | |
47 | ||
48 | ;; bookmark alist format: | |
49 | ;; (... | |
50 | ;; (bookmark-name (filename | |
51 | ;; string-in-front | |
52 | ;; string-behind | |
53 | ;; point)) | |
54 | ;; ...) | |
55 | ;; | |
56 | ;; bookmark-name is the string the user gives the bookmark and | |
57 | ;; accesses it by from then on. filename is the location of the file | |
58 | ;; in which the bookmark is set. string-in-front is a string of | |
59 | ;; `bookmark-search-size' chars of context in front of the point the | |
60 | ;; bookmark is set at, string-behind is the same thing after the | |
61 | ;; point. bookmark-jump will search for string-behind and | |
62 | ;; string-in-front in case the file has changed since the bookmark was | |
63 | ;; set. It will attempt to place the user before the changes, if | |
64 | ;; there were any. | |
11eb4275 RS |
65 | ;; |
66 | ;; It is not advisable to sort the bookmark list when it is presented | |
67 | ;; to the user, because it is already sorted in what is probably the | |
68 | ;; most useful way: order of creation, with most recently created | |
69 | ;; bookmarks coming first and older ones toward the end (renaming does | |
70 | ;; not count as creating) -- which is what we want, most of the time. | |
b3bf02fa RS |
71 | |
72 | ;;; Code: | |
73 | ||
74 | ;; Added for lucid emacs compatibility, db | |
75 | (or (fboundp 'defalias) (fset 'defalias 'fset)) | |
76 | ||
77 | ;; these are the distribution keybindings suggested by RMS, everything | |
78 | ;; else will be done with M-x or the menubar: | |
79 | (define-key ctl-x-map "rb" 'bookmark-jump) | |
80 | (define-key ctl-x-map "rm" 'bookmark-set) | |
81 | (define-key ctl-x-map "rl" 'bookmark-locate) | |
82 | ||
83 | ;; define the map, so it can be bound by those who desire to do so: | |
84 | ||
9aef3b21 RS |
85 | (defvar bookmark-map nil |
86 | "Keymap containing bindings to bookmark functions. | |
87 | It is not bound to any key by default: to bind it | |
88 | so that you have a bookmark prefix, just use `global-set-key' and bind a | |
89 | key of your choice to `bookmark-map'. All interactive bookmark | |
b3bf02fa RS |
90 | functions have a binding in this keymap.") |
91 | ||
92 | (define-prefix-command 'bookmark-map) | |
93 | ||
94 | ;; Read the help on all of these functions for details... | |
95 | ;; "x" marks the spot! | |
96 | (define-key bookmark-map "x" 'bookmark-set) | |
97 | (define-key bookmark-map "j" 'bookmark-jump) | |
98 | (define-key bookmark-map "i" 'bookmark-insert) | |
99 | (define-key bookmark-map "f" 'bookmark-locate) ; "f" for "find" | |
9aef3b21 | 100 | (define-key bookmark-map "r" 'bookmark-rename) |
b3bf02fa RS |
101 | ;; deletes bookmarks |
102 | (define-key bookmark-map "d" 'bookmark-delete) | |
103 | ;; loads new file | |
104 | (define-key bookmark-map "l" 'bookmark-load) | |
105 | ;; saves them in file | |
106 | (define-key bookmark-map "w" 'bookmark-write) | |
107 | (define-key bookmark-map "s" 'bookmark-save) | |
108 | ||
109 | ;; just add the hook to make sure that people don't lose bookmarks | |
110 | ;; when they kill Emacs, unless they don't want to save them. | |
111 | ||
112 | (add-hook 'kill-emacs-hook | |
113 | (function | |
114 | (lambda () | |
115 | (and (featurep 'bookmark) | |
116 | bookmark-alist | |
117 | (bookmark-time-to-save-p t) | |
118 | (bookmark-save))))) | |
119 | ||
120 | ;; more stuff added by db. | |
121 | (defvar bookmark-current-bookmark nil | |
9aef3b21 RS |
122 | "Name of bookmark most recently used in the current file. |
123 | It is buffer local, used to make moving a bookmark forward | |
8027e2ad | 124 | through a file easier.") |
b3bf02fa RS |
125 | |
126 | (make-variable-buffer-local 'bookmark-current-bookmark) | |
127 | ||
128 | (defvar bookmark-save-flag t | |
9aef3b21 RS |
129 | "*Controls when Emacs saves bookmarks to a file. |
130 | --> Nil means never save bookmarks, except when `bookmark-save' is | |
131 | explicitly called \(\\[bookmark-save]\). | |
132 | --> t means save bookmarks when Emacs is killed. | |
133 | --> Otherise, it should be a number that is the frequency with which | |
134 | the bookmark list is saved \(i.e.: the number of times which | |
135 | Emacs' bookmark list may be modified before it is automatically | |
136 | saved.\). If it is a number, Emacs will also automatically save | |
137 | bookmarks when it is killed. | |
b3bf02fa RS |
138 | |
139 | Therefore, the way to get it to save every time you make or delete a | |
140 | bookmark is to set this variable to 1 \(or 0, which produces the same | |
141 | behavior.\) | |
142 | ||
143 | To specify the file in which to save them, modify the variable | |
9aef3b21 | 144 | bookmark-file, which is `~/.emacs-bkmrks' by default.") |
b3bf02fa RS |
145 | |
146 | (defvar bookmark-alist-modification-count 0 | |
9aef3b21 | 147 | "Number of modifications to bookmark list since it was last saved.") |
b3bf02fa RS |
148 | |
149 | (defvar bookmark-file "~/.emacs-bkmrks" | |
150 | "*File in which to save bookmarks by default.") | |
151 | ||
152 | (defvar bookmark-completion-ignore-case t | |
9aef3b21 | 153 | "*Non-nil means bookmark functions ignore case in completion.") |
b3bf02fa | 154 | |
9aef3b21 RS |
155 | (defvar bookmark-search-size 500 |
156 | "Length of the context strings recorded on either side of a bookmark.") | |
b3bf02fa RS |
157 | |
158 | (defvar bookmark-alist () | |
159 | "Association list of bookmarks. | |
160 | You probably don't want to change the value of this alist yourself; | |
161 | instead, let the various bookmark functions do it for you.") | |
162 | ||
163 | (defvar bookmark-current-point 0) | |
164 | (defvar bookmark-yank-point 0) | |
165 | (defvar bookmark-current-buffer nil) | |
166 | ||
167 | (defun bookmark-set (&optional parg) | |
9aef3b21 RS |
168 | |
169 | "Set a bookmark named NAME inside a file. | |
170 | With prefix arg, will not overwrite a bookmark that has the same name | |
171 | as NAME if such a bookmark already exists, but instead will \"push\" | |
172 | the new bookmark onto the bookmark alist. Thus the most recently set | |
173 | bookmark with name NAME would be the one in effect at any given time, | |
174 | but the others are still there, should you decide to delete the most | |
175 | recent one. | |
b3bf02fa RS |
176 | |
177 | To yank words from the text of the buffer and use them as part of the | |
9aef3b21 | 178 | bookmark name, type C-w while setting a bookmark. Successive C-w's |
b3bf02fa RS |
179 | yank successive words. |
180 | ||
181 | Typing C-v inserts the name of the current file being visited. Typing | |
182 | C-u inserts the name of the last bookmark used in the buffer \(as an | |
183 | aid in using a single bookmark name to track your progress through a | |
184 | large file\). If no bookmark was used, then C-u behaves like C-v and | |
185 | inserts the name of the file being visited. | |
186 | ||
187 | Use \\[bookmark-delete] to remove bookmarks \(you give it a name, | |
188 | and it removes only the first instance of a bookmark with that name from | |
189 | the list of bookmarks.\)" | |
190 | (interactive "P") | |
191 | (if (not (bookmark-buffer-file-name)) | |
192 | (error "Buffer not visiting a file or directory.")) | |
193 | (setq bookmark-current-point (point)) | |
194 | (setq bookmark-yank-point (point)) | |
195 | (setq bookmark-current-buffer (current-buffer)) | |
196 | (let ((str | |
197 | (read-from-minibuffer | |
198 | "Set bookmark: " | |
199 | nil | |
200 | (let ((now-map (copy-keymap minibuffer-local-map))) | |
201 | (progn (define-key now-map "\C-w" | |
202 | 'bookmark-yank-word) | |
203 | (define-key now-map "\C-v" | |
204 | 'bookmark-insert-current-file-name) | |
205 | (define-key now-map "\C-u" | |
206 | 'bookmark-insert-current-bookmark)) | |
207 | now-map)))) | |
208 | (progn | |
209 | (bookmark-make parg str) | |
210 | (setq bookmark-current-bookmark str) | |
211 | (goto-char bookmark-current-point)))) | |
212 | ||
213 | (defun bookmark-insert-current-bookmark () | |
214 | ;; insert this buffer's value of bookmark-current-bookmark, default | |
215 | ;; to file name if it's nil. | |
216 | (interactive) | |
217 | (let ((str | |
218 | (save-excursion | |
219 | (set-buffer bookmark-current-buffer) | |
220 | bookmark-current-bookmark))) | |
221 | (if str (insert str) (bookmark-insert-current-file-name)))) | |
222 | ||
223 | (defun bookmark-insert-current-file-name () | |
224 | ;; insert the name (sans path) of the current file into the bookmark | |
225 | ;; name that is being set. | |
226 | (interactive) | |
227 | (let ((str (save-excursion | |
228 | (set-buffer bookmark-current-buffer) | |
229 | (bookmark-buffer-file-name)))) | |
230 | (insert (substring | |
231 | str | |
232 | (1+ (string-match | |
233 | "\\(/[^/]*\\)/*$" | |
234 | str)))))) | |
235 | ||
236 | (defun bookmark-yank-word () | |
237 | (interactive) | |
238 | ;; get the next word from the buffer and append it to the name of | |
239 | ;; the bookmark currently being set. | |
240 | (let ((string (save-excursion | |
241 | (set-buffer bookmark-current-buffer) | |
242 | (goto-char bookmark-yank-point) | |
243 | (buffer-substring | |
244 | (point) | |
245 | (save-excursion | |
246 | (forward-word 1) | |
247 | (setq bookmark-yank-point (point))))))) | |
248 | (insert string))) | |
249 | ||
250 | (defun bookmark-make (parg str) | |
251 | (if (and (assoc str bookmark-alist) (not parg)) | |
252 | ;; already existing boookmark under that name and | |
253 | ;; no prefix arg means just overwrite old bookmark | |
254 | (setcdr (assoc str bookmark-alist) | |
255 | (list (bookmark-make-cell))) | |
256 | ||
257 | ;; otherwise just cons it onto the front (either the bookmark | |
258 | ;; doesn't exist already, or there is no prefix arg. In either | |
259 | ;; case, we want the new bookmark consed onto the alist...) | |
260 | ||
261 | (setq bookmark-alist | |
262 | (cons | |
263 | (list str | |
264 | (bookmark-make-cell)) | |
265 | bookmark-alist))) | |
266 | ;; Added by db | |
267 | (setq bookmark-current-bookmark str) | |
268 | (setq bookmark-alist-modification-count | |
269 | (1+ bookmark-alist-modification-count)) | |
270 | (if (bookmark-time-to-save-p) | |
271 | (bookmark-save))) | |
272 | ||
273 | (defun bookmark-make-cell () | |
274 | ;; make the cell that is the cdr of a bookmark alist element. It | |
275 | ;; looks like this: | |
276 | ;; (filename search-forward-str search-back-str point) | |
277 | (list | |
278 | (bookmark-buffer-file-name) | |
279 | (if (>= (- (point-max) (point)) bookmark-search-size) | |
280 | (buffer-substring | |
281 | (point) | |
282 | (+ (point) bookmark-search-size)) | |
283 | nil) | |
284 | (if (>= (- (point) (point-min)) bookmark-search-size) | |
285 | (buffer-substring | |
286 | (point) | |
287 | (- (point) bookmark-search-size)) | |
288 | nil) | |
289 | (point))) | |
290 | ||
291 | (defun bookmark-buffer-file-name () | |
292 | (or | |
293 | buffer-file-name | |
294 | (if (and (boundp 'dired-directory) dired-directory) | |
295 | (if (stringp dired-directory) | |
296 | dired-directory | |
297 | (car dired-directory))))) | |
298 | ||
299 | (defun bookmark-try-default-file () | |
300 | (if (and (null bookmark-alist) | |
301 | (file-readable-p (expand-file-name bookmark-file))) | |
302 | (bookmark-load bookmark-file))) | |
8027e2ad | 303 | |
b3bf02fa | 304 | (defun bookmark-jump (str) |
9aef3b21 RS |
305 | "Jump to bookmark BOOKMARK (a point in some file). |
306 | You may have a problem using this function if the value of variable | |
307 | `bookmark-alist' is nil. If that happens, you need to load in some | |
308 | bookmarks. See help on function `bookmark-load' for more about | |
8027e2ad | 309 | this." |
11eb4275 | 310 | (interactive (let ((completion-ignore-case |
b3bf02fa RS |
311 | bookmark-completion-ignore-case)) |
312 | (list (completing-read | |
313 | "Jump to bookmark: " | |
314 | bookmark-alist | |
315 | nil | |
11eb4275 RS |
316 | 0)))) |
317 | (let ((whereto-list (car (cdr (assoc str bookmark-alist))))) | |
318 | (let ((file (car whereto-list)) | |
319 | (forward-str (car (cdr whereto-list))) | |
320 | (behind-str (car (cdr (cdr whereto-list)))) | |
321 | (place (car (cdr (cdr (cdr whereto-list)))))) | |
322 | (if (file-exists-p (expand-file-name file)) | |
323 | (progn | |
324 | (find-file (expand-file-name file)) | |
325 | (goto-char place) | |
326 | ;; Go searching forward first. Then, if forward-str exists and | |
327 | ;; was found in the file, we can search backward for behind-str. | |
328 | ;; Rationale is that if text was inserted between the two in the | |
329 | ;; file, it's better to be put before it so you can read it, | |
330 | ;; rather than after and remain perhaps unaware of the changes. | |
331 | (if forward-str | |
332 | (if (search-forward forward-str (point-max) t) | |
333 | (backward-char bookmark-search-size))) | |
334 | (if behind-str | |
335 | (if (search-backward behind-str (point-min) t) | |
336 | (forward-char bookmark-search-size))) | |
337 | ;; added by db | |
338 | (setq bookmark-current-bookmark str)) | |
339 | (error | |
340 | (concat "File " | |
341 | file | |
342 | " does not exist. Suggest deleting bookmark \"" | |
343 | str | |
344 | "\"")))))) | |
b3bf02fa RS |
345 | |
346 | (defun bookmark-locate (str) | |
9aef3b21 RS |
347 | "Insert the name of the file associated with BOOKMARK. |
348 | \(This is not the same as the contents of that file\)." | |
11eb4275 RS |
349 | (interactive (let ((completion-ignore-case |
350 | bookmark-completion-ignore-case)) | |
351 | (list (completing-read | |
352 | "Insert bookmark location: " | |
353 | bookmark-alist | |
354 | nil | |
355 | 0)))) | |
b3bf02fa RS |
356 | (insert (car (car (cdr (assoc str bookmark-alist)))))) |
357 | ||
9aef3b21 RS |
358 | (defun bookmark-rename (old &optional new) |
359 | "Change the name of BOOKMARK to NEWNAME. | |
360 | If called from keyboard, prompts for OLD and NEWNAME. | |
361 | If called from menubar, prompts for NEWNAME. | |
362 | If called from Lisp, prompts for NEWNAME if only BOOKMARK was passed | |
363 | as an argument. If called with two strings, then no prompting is | |
364 | done. You must pass at least BOOKMARK when calling from Lisp. | |
365 | ||
366 | While you are entering the new name, consecutive C-w's insert | |
367 | consectutive words from the text of the buffer into the new bookmark | |
368 | name, and C-v inserts the name of the file." | |
369 | ||
11eb4275 RS |
370 | (interactive (let ((completion-ignore-case |
371 | bookmark-completion-ignore-case)) | |
372 | (list (completing-read "Old bookmark name: " | |
373 | bookmark-alist | |
374 | nil | |
375 | 0)))) | |
b3bf02fa RS |
376 | (progn |
377 | (setq bookmark-current-point (point)) | |
378 | (setq bookmark-yank-point (point)) | |
379 | (setq bookmark-current-buffer (current-buffer)) | |
380 | (let ((cell (assoc old bookmark-alist)) | |
381 | (str | |
9aef3b21 RS |
382 | (or new ; use second arg, if non-nil |
383 | (read-from-minibuffer | |
384 | "New name: " | |
385 | nil | |
386 | (let ((now-map (copy-keymap minibuffer-local-map))) | |
387 | (progn (define-key now-map "\C-w" | |
388 | 'bookmark-yank-word) | |
389 | (define-key now-map "\C-v" | |
390 | 'bookmark-insert-current-file-name)) | |
391 | now-map))))) | |
b3bf02fa RS |
392 | (progn |
393 | (setcar cell str) | |
394 | (setq bookmark-current-bookmark str) | |
395 | (setq bookmark-alist-modification-count | |
396 | (1+ bookmark-alist-modification-count)) | |
397 | (if (bookmark-time-to-save-p) | |
398 | (bookmark-save)))))) | |
399 | ||
400 | (defun bookmark-insert (str) | |
9aef3b21 RS |
401 | "Insert the text of the file pointed to by bookmark BOOKMARK. |
402 | You may have a problem using this function if the value of variable | |
403 | `bookmark-alist' is nil. If that happens, you need to load in some | |
404 | bookmarks. See help on function `bookmark-load' for more about | |
8027e2ad | 405 | this." |
11eb4275 RS |
406 | (interactive (let ((completion-ignore-case |
407 | bookmark-completion-ignore-case)) | |
408 | (list (completing-read | |
409 | "Insert bookmark contents: " | |
410 | bookmark-alist | |
411 | nil | |
412 | 0)))) | |
b3bf02fa RS |
413 | (let ((whereto-list (car (cdr (assoc str bookmark-alist))))) |
414 | (let ((file (car whereto-list))) | |
415 | (if (file-readable-p (expand-file-name file)) | |
416 | (let ((str-to-insert | |
417 | (save-excursion | |
418 | (find-file (expand-file-name file)) | |
419 | (prog1 | |
420 | (buffer-substring (point-min) (point-max)) | |
421 | (bury-buffer)))) | |
422 | (orig-point (point))) | |
423 | (insert str-to-insert) | |
424 | (push-mark) | |
425 | (goto-char orig-point)) | |
426 | (error | |
427 | (concat "File " | |
428 | file | |
429 | " does not exist. Suggest deleting bookmark \"" | |
430 | str | |
431 | "\"")))))) | |
432 | ||
433 | (defun bookmark-delete (str) | |
9aef3b21 RS |
434 | "Delete the bookmark named NAME from the bookmark list. |
435 | Removes only the first instance of a bookmark with that name. If | |
436 | there are one or more other bookmarks with the same name, they will | |
437 | not be deleted. Defaults to the \"current\" bookmark \(that is, the | |
438 | one most recently used in this file, if any\)." | |
439 | ||
b3bf02fa RS |
440 | (interactive (let ((completion-ignore-case |
441 | bookmark-completion-ignore-case)) | |
442 | (list | |
11eb4275 RS |
443 | (completing-read |
444 | "Delete bookmark: " | |
445 | bookmark-alist | |
446 | nil | |
447 | 0 | |
448 | bookmark-current-bookmark)))) | |
449 | (let ((will-go (assoc str bookmark-alist))) | |
450 | (setq bookmark-alist (delq will-go bookmark-alist)) | |
451 | ;; Added by db, nil bookmark-current-bookmark if the last | |
452 | ;; occurence has been deleted | |
b3bf02fa | 453 | (or (assoc bookmark-current-bookmark bookmark-alist) |
11eb4275 RS |
454 | (setq bookmark-current-bookmark nil))) |
455 | (setq bookmark-alist-modification-count | |
456 | (1+ bookmark-alist-modification-count)) | |
457 | (if (bookmark-time-to-save-p) | |
458 | (bookmark-save))) | |
b3bf02fa RS |
459 | |
460 | (defun bookmark-time-to-save-p (&optional last-time) | |
461 | ;; By Gregory M. Saunders <saunders@cis.ohio-state.edu> | |
462 | ;; finds out whether it's time to save bookmarks to a file, by | |
463 | ;; examining the value of variable bookmark-save-flag, and maybe | |
464 | ;; bookmark-alist-modification-count. Returns t if they should be | |
465 | ;; saved, nil otherwise. if last-time is non-nil, then this is | |
466 | ;; being called when emacs is killed. | |
467 | (cond (last-time | |
468 | (and (> bookmark-alist-modification-count 0) | |
469 | bookmark-save-flag)) | |
470 | ((numberp bookmark-save-flag) | |
471 | (>= bookmark-alist-modification-count bookmark-save-flag)) | |
472 | (t | |
473 | nil))) | |
474 | ||
475 | (defun bookmark-write () | |
476 | (interactive) | |
477 | (bookmark-save t)) | |
478 | ||
11eb4275 | 479 | (defun bookmark-save (&optional parg file) |
9aef3b21 RS |
480 | "Save currently defined bookmarks. |
481 | Saves by default in the file defined by the variable | |
482 | `bookmark-file'. With a prefix arg, save it in file FILE. | |
b3bf02fa RS |
483 | |
484 | If you are calling this from Lisp, the two arguments are PREFIX-ARG | |
485 | and FILE, and if you just want it to write to the default file, then | |
486 | pass no arguments. Or pass in nil and FILE, and it will save in FILE | |
487 | instead. If you pass in one argument, and it is non-nil, then the | |
488 | user will be interactively queried for a file to save in. | |
489 | ||
11eb4275 | 490 | When you want to load in the bookmarks from a file, use |
9aef3b21 | 491 | \`bookmark-load\', \\[bookmark-load]. That function will prompt you |
11eb4275 | 492 | for a file, defaulting to the file defined by variable |
9aef3b21 | 493 | `bookmark-file'." |
b3bf02fa RS |
494 | (interactive "P") |
495 | (cond | |
496 | ((and (null parg) (null file)) | |
497 | ;;whether interactive or not, write to default file | |
498 | (bookmark-write-file bookmark-file)) | |
499 | ((and (null parg) file) | |
500 | ;;whether interactive or not, write to given file | |
501 | (bookmark-write-file file)) | |
502 | ((and parg (not file)) | |
503 | ;;have been called interactively w/ prefix arg | |
504 | (let ((file (read-file-name "File to save bookmarks in: "))) | |
505 | (bookmark-write-file file))) | |
506 | (t ; someone called us with prefix-arg *and* a file, so just write to file | |
507 | (bookmark-write-file file))) | |
508 | ;; signal that we have synced the bookmark file by setting this to | |
509 | ;; 0. If there was an error at any point before, it will not get | |
510 | ;; set, which is what we want. | |
511 | (setq bookmark-alist-modification-count 0)) | |
512 | ||
513 | (defun bookmark-write-file (file) | |
514 | (save-excursion | |
515 | (message (format "Saving bookmarks to file %s." file)) | |
516 | (set-buffer (find-file-noselect file)) | |
517 | (goto-char (point-min)) | |
518 | (delete-region (point-min) (point-max)) | |
519 | (print bookmark-alist (current-buffer)) | |
520 | (write-file file) | |
521 | (kill-buffer (current-buffer)))) | |
522 | ||
523 | (defun bookmark-load (file &optional revert no-msg) | |
9aef3b21 RS |
524 | "Load bookmarks from FILE (which must be in bookmark format). |
525 | Appends loaded bookmarks to the front of the list of bookmarks. If | |
526 | optional second argument REVERT is non-nil, existing bookmarks are | |
527 | destroyed. Optional third arg NO-MSG means don't display any messages | |
528 | while loading. | |
b3bf02fa RS |
529 | |
530 | If you load a file that doesn't contain a proper bookmark alist, you | |
9aef3b21 | 531 | will corrupt Emacs's bookmark list. Generally, you should only load |
b3bf02fa | 532 | in files that were created with the bookmark functions in the first |
9aef3b21 | 533 | place. Your own personal bookmark file, `~/.emacs-bkmrks', is |
8027e2ad | 534 | maintained automatically by Emacs; you shouldn't need to load it |
11eb4275 | 535 | explicitly." |
b3bf02fa RS |
536 | (interactive |
537 | (list (read-file-name | |
538 | (format "Load bookmarks from: (%s) " | |
539 | bookmark-file) | |
540 | ;;Default might not be used often, | |
541 | ;;but there's no better default, and | |
542 | ;;I guess it's better than none at all. | |
543 | "~/" bookmark-file 'confirm))) | |
544 | (setq file (expand-file-name file)) | |
545 | (if (file-readable-p file) | |
546 | (save-excursion | |
547 | (if (null no-msg) | |
548 | (message (format "Loading bookmarks from %s..." file))) | |
549 | (set-buffer (find-file-noselect file)) | |
550 | (goto-char (point-min)) | |
551 | (let ((blist (car (read-from-string | |
552 | (buffer-substring (point-min) (point-max)))))) | |
553 | (if (listp blist) | |
554 | (progn | |
555 | (if (not revert) | |
556 | (setq bookmark-alist-modification-count | |
557 | (1+ bookmark-alist-modification-count)) | |
558 | (setq bookmark-alist-modification-count 0)) | |
559 | (setq bookmark-alist | |
560 | (append blist (if (not revert) bookmark-alist)))) | |
561 | (error (format "Invalid bookmark list in %s." file)))) | |
562 | (kill-buffer (current-buffer)) | |
563 | (if (null no-msg) | |
564 | (message (format "Loading bookmarks from %s... done" file)))) | |
565 | (error (format "Cannot read bookmark file %s." file)))) | |
566 | ||
11eb4275 RS |
567 | ;;;; bookmark menu bar stuff ;;;; |
568 | ||
9aef3b21 RS |
569 | (defvar bookmark-menu-bar-length 70 |
570 | "*Maximum length of a bookmark name displayed on a popup menu.") | |
b3bf02fa | 571 | |
11eb4275 | 572 | (defvar bookmark-enable-menu-bar t |
9aef3b21 RS |
573 | "*Non-nil means put a bookmark menu on the menu bar. |
574 | \(Assuming that you are running Emacs under a windowing system, such | |
575 | as X.\)") | |
b3bf02fa | 576 | |
11eb4275 | 577 | (defun bookmark-make-menu-bar-alist () |
b3bf02fa RS |
578 | (if (not bookmark-alist) |
579 | (if (file-readable-p bookmark-file) | |
580 | (bookmark-load bookmark-file))) | |
581 | (if bookmark-alist | |
582 | (mapcar (lambda (cell) | |
583 | (let ((str (car cell))) | |
584 | (cons | |
11eb4275 RS |
585 | (if (> (length str) bookmark-menu-bar-length) |
586 | (substring str 0 bookmark-menu-bar-length) | |
b3bf02fa RS |
587 | str) |
588 | str))) | |
589 | bookmark-alist) | |
590 | (error "No bookmarks currently set."))) | |
591 | ||
11eb4275 RS |
592 | (defun bookmark-make-menu-bar-with-function (func-sym |
593 | menu-label | |
594 | menu-str event) | |
b3bf02fa RS |
595 | ;; help function for making menus that need to apply a bookmark |
596 | ;; function to a string. | |
11eb4275 | 597 | (let* ((menu (bookmark-make-menu-bar-alist)) |
b3bf02fa RS |
598 | (str (x-popup-menu event |
599 | (list menu-label | |
600 | (cons menu-str | |
601 | menu))))) | |
602 | (if str | |
603 | (apply func-sym (list str))))) | |
604 | ||
11eb4275 | 605 | (defun bookmark-menu-bar-insert (event) |
9aef3b21 RS |
606 | "Insert the text of the file pointed to by bookmark BOOKMARK. |
607 | You may have a problem using this function if the value of variable | |
608 | `bookmark-alist' is nil. If that happens, you need to load in some | |
609 | bookmarks. See help on function `bookmark-load' for more about | |
610 | this." | |
b3bf02fa | 611 | (interactive "e") |
11eb4275 | 612 | (bookmark-make-menu-bar-with-function 'bookmark-insert |
b3bf02fa RS |
613 | "Bookmark Insert Menu" |
614 | "--- Insert Contents ---" | |
615 | event)) | |
616 | ||
11eb4275 | 617 | (defun bookmark-menu-bar-jump (event) |
9aef3b21 RS |
618 | "Jump to bookmark BOOKMARK (a point in some file). |
619 | You may have a problem using this function if the value of variable | |
620 | `bookmark-alist' is nil. If that happens, you need to load in some | |
621 | bookmarks. See help on function `bookmark-load' for more about | |
622 | this." | |
b3bf02fa | 623 | (interactive "e") |
11eb4275 | 624 | (bookmark-make-menu-bar-with-function 'bookmark-jump |
b3bf02fa RS |
625 | "Bookmark Jump Menu" |
626 | "--- Jump to Bookmark ---" | |
627 | event)) | |
628 | ||
11eb4275 | 629 | (defun bookmark-menu-bar-locate (event) |
9aef3b21 RS |
630 | "Insert the name of the file associated with BOOKMARK. |
631 | \(This is not the same as the contents of that file\)." | |
b3bf02fa | 632 | (interactive "e") |
11eb4275 | 633 | (bookmark-make-menu-bar-with-function 'bookmark-locate |
b3bf02fa RS |
634 | "Bookmark Locate Menu" |
635 | "--- Insert Location ---" | |
636 | event)) | |
637 | ||
11eb4275 | 638 | (defun bookmark-menu-bar-rename (event) |
9aef3b21 RS |
639 | "Change the name of BOOKMARK to NEWNAME. |
640 | If called from keyboard, prompts for OLD and NEWNAME. | |
641 | If called from menubar, prompts for NEWNAME. | |
642 | If called from Lisp, prompts for NEWNAME if only BOOKMARK was passed | |
643 | as an argument. If called with two strings, then no prompting is | |
644 | done. You must pass at least BOOKMARK when calling from Lisp. | |
645 | ||
646 | While you are entering the new name, consecutive C-w's insert | |
647 | consectutive words from the text of the buffer into the new bookmark | |
648 | name, and C-v inserts the name of the file." | |
b3bf02fa | 649 | (interactive "e") |
11eb4275 | 650 | (bookmark-make-menu-bar-with-function 'bookmark-rename |
b3bf02fa RS |
651 | "Bookmark Rename Menu" |
652 | "--- Rename Bookmark ---" | |
653 | event)) | |
654 | ||
11eb4275 | 655 | (defun bookmark-menu-bar-delete (event) |
9aef3b21 RS |
656 | "Delete the bookmark named NAME from the bookmark list. |
657 | Removes only the first instance of a bookmark with that name. If | |
658 | there are one or more other bookmarks with the same name, they will | |
659 | not be deleted. Defaults to the \"current\" bookmark \(that is, the | |
660 | one most recently used in this file, if any\)." | |
b3bf02fa | 661 | (interactive "e") |
11eb4275 | 662 | (bookmark-make-menu-bar-with-function 'bookmark-delete |
b3bf02fa RS |
663 | "Bookmark Delete Menu" |
664 | "--- Delete Bookmark ---" | |
665 | event)) | |
666 | ||
11eb4275 | 667 | (if (and bookmark-enable-menu-bar window-system) |
b3bf02fa RS |
668 | (progn |
669 | (defvar menu-bar-bookmark-map | |
670 | (make-sparse-keymap "Bookmark functions")) | |
671 | ||
672 | ;; make bookmarks appear toward the right side of the menu. | |
673 | (if (boundp 'menu-bar-final-items) | |
674 | (if menu-bar-final-items | |
675 | (setq menu-bar-final-items | |
676 | (cons 'bookmark menu-bar-final-items))) | |
677 | (setq menu-bar-final-items '(bookmark))) | |
678 | ||
679 | (define-key global-map [menu-bar bookmark] | |
680 | (cons "Bookmarks" menu-bar-bookmark-map)) | |
681 | ||
682 | (define-key menu-bar-bookmark-map [load] | |
683 | '(" Load a bookmark file" . bookmark-load)) | |
684 | ||
685 | (define-key menu-bar-bookmark-map [write] | |
686 | '("Write \(to another file\)" . bookmark-write)) | |
687 | ||
688 | (define-key menu-bar-bookmark-map [save] | |
11eb4275 | 689 | '("Save \(in default file\)" . bookmark-save)) |
b3bf02fa | 690 | |
b3bf02fa | 691 | (define-key menu-bar-bookmark-map [delete] |
11eb4275 | 692 | '(" Delete a bookmark" . bookmark-menu-bar-delete)) |
b3bf02fa RS |
693 | |
694 | (define-key menu-bar-bookmark-map [rename] | |
11eb4275 | 695 | '(" Rename bookmark" . bookmark-menu-bar-rename)) |
b3bf02fa RS |
696 | |
697 | (define-key menu-bar-bookmark-map [locate] | |
11eb4275 | 698 | '(" Insert location" . bookmark-menu-bar-locate)) |
b3bf02fa RS |
699 | |
700 | (define-key menu-bar-bookmark-map [insert] | |
11eb4275 | 701 | '(" Insert contents" . bookmark-menu-bar-insert)) |
b3bf02fa RS |
702 | |
703 | (define-key menu-bar-bookmark-map [set] | |
704 | '(" Set bookmark" . bookmark-set)) | |
705 | ||
706 | (define-key menu-bar-bookmark-map [jump] | |
11eb4275 | 707 | '(" Go to bookmark" . bookmark-menu-bar-jump)))) |
b3bf02fa RS |
708 | |
709 | ;; not using properties because they make the menu sluggish in coming | |
710 | ;; up -- too many tests to make. Instead, choosing a useless menu | |
711 | ;; item just gets you an error now (see | |
11eb4275 | 712 | ;; bookmark-make-menu-bar-with-function) |
b3bf02fa | 713 | ;; |
11eb4275 | 714 | ;; (put 'bookmark-menu-bar-jump 'menu-enable |
b3bf02fa RS |
715 | ;; '(or bookmark-alist |
716 | ;; (and (file-readable-p bookmark-file) | |
717 | ;; (progn (bookmark-load bookmark-file) | |
718 | ;; bookmark-alist)))) | |
719 | ;; | |
11eb4275 | 720 | ;; (put 'bookmark-menu-bar-insert 'menu-enable |
b3bf02fa RS |
721 | ;; '(or bookmark-alist |
722 | ;; (and (file-readable-p bookmark-file) | |
723 | ;; (progn (bookmark-load bookmark-file) | |
724 | ;; bookmark-alist)))) | |
725 | ;; | |
11eb4275 | 726 | ;; (put 'bookmark-menu-bar-locate 'menu-enable |
b3bf02fa RS |
727 | ;; '(or bookmark-alist |
728 | ;; (and (file-readable-p bookmark-file) | |
729 | ;; (progn (bookmark-load bookmark-file) | |
730 | ;; bookmark-alist)))) | |
731 | ;; | |
11eb4275 | 732 | ;; (put 'bookmark-menu-bar-rename 'menu-enable |
b3bf02fa RS |
733 | ;; '(or bookmark-alist |
734 | ;; (and (file-readable-p bookmark-file) | |
735 | ;; (progn (bookmark-load bookmark-file) | |
736 | ;; bookmark-alist)))) | |
737 | ;; | |
11eb4275 | 738 | ;; (put 'bookmark-menu-bar-delete 'menu-enable |
b3bf02fa RS |
739 | ;; '(or bookmark-alist |
740 | ;; (and (file-readable-p bookmark-file) | |
741 | ;; (progn (bookmark-load bookmark-file) | |
742 | ;; bookmark-alist)))) | |
743 | ;; | |
11eb4275 | 744 | ;; (put 'bookmark-menu-bar-save 'menu-enable |
b3bf02fa RS |
745 | ;; '(or bookmark-alist |
746 | ;; (and (file-readable-p bookmark-file) | |
747 | ;; (progn (bookmark-load bookmark-file) | |
748 | ;; bookmark-alist)))) | |
749 | ;; | |
11eb4275 | 750 | ;; (put 'bookmark-menu-bar-write 'menu-enable |
b3bf02fa RS |
751 | ;; '(or bookmark-alist |
752 | ;; (and (file-readable-p bookmark-file) | |
753 | ;; (progn (bookmark-load bookmark-file) | |
754 | ;; bookmark-alist)))) | |
755 | ||
11eb4275 | 756 | ;;;; end bookmark menu-bar stuff ;;;; |
b3bf02fa RS |
757 | |
758 | ;; load the default bookmark file, if it exists, and the | |
759 | ;; bookmark-alist is nil: | |
760 | (bookmark-try-default-file) | |
761 | ||
b3bf02fa RS |
762 | (provide 'bookmark) |
763 | ||
11eb4275 | 764 | ;;; bookmark.el ends here |