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