home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / elisp / misc / info-bookmark.el < prev    next >
Encoding:
Text File  |  1993-04-07  |  13.8 KB  |  356 lines

  1. ;;; -*- Mode: Emacs-Lisp -*-
  2. ;;; File: info-bookmark.el
  3. ;;; 
  4. ;;; Bookmarks for use in the Info Documentation reader
  5. ;;; Karl Fogel and Ken Olstad
  6. ;;; (kfogel@cs.oberlin.edu and olstad@msc.edu)
  7. ;;;
  8. ;;; LCD Archive Entry:
  9. ;;; info-bookmark|Karl Fogel, Ken Olstad|kfogel@cs.oberlin.edu, olstad@msc.edu|
  10. ;;; Setting bookmarks in Info that can be jumped to later.|
  11. ;;; 08-Apr-1993|0.0|~/misc/info-bookmark.el.Z|
  12. ;;;
  13. ;;; This code is distributed under the terms of the GNU General Public
  14. ;;; license. If you are not sure what that means, contact either of the
  15. ;;; authors. If you do not have electronic mail access, write to me at
  16. ;;;
  17. ;;; Karl Fogel
  18. ;;; 1123 N. Oak Park Ave.
  19. ;;; Oak Park, ILL
  20. ;;; USA      60302
  21. ;;;
  22. ;;; for more information.
  23. ;;;
  24. ;;; Please let us know what you think of it... we like messages with
  25. ;;; complaints almost as much as ones without complaints! :-)
  26. ;;;
  27. ;;; TODO: 
  28. ;;;
  29. ;;; Better support for multiple bookmark files.  Suggestions welcome!
  30. ;;; 
  31. ;;; 
  32. ;;; INSTALLATION:
  33. ;;; 
  34. ;;; Put this file in a directory that is in your load-path, and in
  35. ;;; your .emacs, set Info-mode-hook (or Info-load-hook instead if your
  36. ;;; info has it) something like this (remember to take out the semicolons!):
  37. ;;; 
  38. ;;; (setq Info-mode-hook
  39. ;;;       (function (lambda ()
  40. ;;;                   (require 'info-bookmark))))
  41. ;;; 
  42. ;;; Set your kill-emacs-hook something like this:
  43. ;;; 
  44. ;;; (setq kill-emacs-hook
  45. ;;;       (function (lambda ()
  46. ;;;                   (and (featurep 'info-bookmark)
  47. ;;;                        Info-bookmark-alist
  48. ;;;                        (y-or-n-p "Save info-bookmarks? ")
  49. ;;;                        (Info-bookmark-write nil)))))
  50. ;;; 
  51. ;;; You may make minor customizations by setting Info-bookmark-file,
  52. ;;; Info-bookmark-completion-ignore-case, and/or
  53. ;;; Info-bookmark-always-write-file in your .emacs file (see the
  54. ;;; defvars below).
  55. ;;;
  56. ;;; If your Info does not have a mode-hook or a load-hook (as seems to
  57. ;;; be the case with some), then put the following into your .emacs:
  58. ;;;
  59. ;;; (load "info-bookmark.el")
  60. ;;;
  61. ;;; and don't worry about doing anything fancier.
  62. ;;; 
  63. ;;; USAGE:
  64. ;;; 
  65. ;;; Simple:
  66. ;;; When you've finally found that elusive info node that contains the
  67. ;;; answer you keep forgetting, type "x" to mark the spot, and give it
  68. ;;; a name you'll remember.  Later on, rather than navigating to that
  69. ;;; spot again, type "j" and type your name for the spot you marked
  70. ;;; (type TAB for completion help if you don't remember the name).
  71. ;;;
  72. ;;; Verbose:
  73. ;;; Assuming that info-bookmark.el has been loaded correctly, typing "x"
  74. ;;; while in Info will set a bookmark (you will be prompted for a name to
  75. ;;; give the bookmark, with the name defaulting to the name of the Info
  76. ;;; node that you are at). Later on you can type "j" while in Info ("j" 
  77. ;;; for "jump to bookmark"), and you can return to any place that you have
  78. ;;; a bookmark for. Completion is available on bookmark names; hit SPACE or
  79. ;;; TAB while you are being prompted for a bookmark.
  80. ;;; 
  81. ;;; Bookmarks are saved automatically in the file ~/.info-bkmarks and 
  82. ;;; reloaded so that they will not be lost between different Emacs sessions. 
  83. ;;; (The reloading takes place at the very end of info-bookmark.el, in fact).
  84. ;;; If you have turned off automatic saving of new bookmarks by setting
  85. ;;; the value of Info-bookmark-always-write-file to nil, you can cause
  86. ;;; all bookmarks currently in effect to be saved by pressing "w". "C-u w"
  87. ;;; ("w" with a prefix argument) will save them in a file of your choice.
  88. ;;;
  89. ;;; At any time, you can revert to the bookmarks in ~/.info-bkmarks with
  90. ;;; "R". You can also load in bookmarks from another file (perhaps someone
  91. ;;; else's bookmark file) with "L". If you wish to delete a bookmark (rare),
  92. ;;; use "D". You will be prompted for a bookmark to remove, and completion
  93. ;;; will aid you in the arduous task of typing in its name.
  94. ;;; 
  95. ;;; Functions you might want to do describe-function on, for more details:
  96. ;;; Info-bookmark-set
  97. ;;; Info-bookmark-jump
  98. ;;; Info-bookmark-revert
  99. ;;; Info-bookmark-delete
  100. ;;; Info-bookmark-load
  101. ;;; Info-bookmark-write
  102. ;;;
  103. ;;;
  104. ;;; NOTE (IMPENDING OBSOLESCENCE?):
  105. ;;;
  106. ;;; Later versions of Info will have bookmarks incorporated into them, with
  107. ;;; some minor changes (bookmarks would be dependent on "annotations", a
  108. ;;; feature in info.el by David Gillespie). So sometime in the (near) 
  109. ;;; future, you may discover that your Info already has all this stuff in
  110. ;;; it already, at which point you can cheerfully junk info-bookmark.el.
  111. ;;; Until then, though, we hope you find this a handy tool when using
  112. ;;; Info. Again, feel free to let us know what you think! You don't need to
  113. ;;; have found a bug to report; we'd be tickled pink just to know that 
  114. ;;; you're using it :-)
  115.  
  116. (require 'info)
  117. (provide 'info-bookmark)
  118.  
  119. ;; Read the help on all of these functions for details...
  120. (define-key Info-mode-map "x" 'Info-bookmark-set)    ; "x" marks the spot!
  121. (define-key Info-mode-map "M" 'Info-bookmark-set)
  122. (define-key Info-mode-map "j" 'Info-bookmark-jump)
  123. (define-key Info-mode-map "R" 'Info-bookmark-revert) ; resets bookmark list
  124. (define-key Info-mode-map "D" 'Info-bookmark-delete) ; removes bookmarks
  125. (define-key Info-mode-map "L" 'Info-bookmark-load)   ; loads new ones from file
  126. (define-key Info-mode-map "w" 'Info-bookmark-write)  ; saves them in a file
  127. (define-key Info-mode-map "S" 'Info-bookmark-write)
  128.  
  129.  
  130. (defvar Info-bookmark-file "~/.info-bkmarks" 
  131.   "*File in which to save info bookmarks by default.")
  132.  
  133.  
  134. (defvar Info-bookmark-completion-ignore-case t
  135.   "*Non-nil means that the various Info bookmark functions that
  136. do completion will be case-insensitive in completion.")
  137.  
  138.  
  139. (defvar Info-bookmark-always-write-file t
  140.   "*If non-nil, save Info-bookmark-file every time a bookmark is made
  141. or discarded.  Unless saving is slow for you, you should probably
  142. have this set to t.")
  143.  
  144.  
  145. (defvar Info-bookmark-alist ()
  146.   "*Association list of Info bookmarks.
  147. You probably don't want to change the value of this alist yourself;
  148. instead, let the various Info-bookmark functions do it for you.")
  149.  
  150.  
  151. (defun Info-bookmark-set (parg)
  152.   "Set a bookmark named NAME at an Info node.  With prefix arg, will not
  153. overwrite a bookmark that has the same name as NAME if such a bookmark
  154. already exists, but instead will \"push\" the new bookmark onto the
  155. bookmark alist.  Thus the most recently set bookmark with name NAME would
  156. be the one in effect at any given time, but the others are still there,
  157. should you decide to delete the most recent one.
  158.  
  159. Use \\[Info-bookmark-delete] to remove bookmarks \(you give it a name,
  160. and it removes only the first instance of a bookmark with that name from
  161. the list of bookmarks.\)"
  162.   (interactive "P")
  163.   (if (not (equal mode-name "Info"))
  164.       (error "Must be in Info mode to set Info bookmarks.")
  165.     (Info-bookmark-make
  166.      parg
  167.      (read-from-minibuffer
  168.       "Pleased to enter a name for new bookmark: "
  169.       (if (equal mode-name "Info") ; checking twice, but that's okay
  170.       Info-current-node
  171.     nil)))))
  172.  
  173.  
  174. (defun Info-bookmark-make (parg str)
  175.   (if (and (assoc str Info-bookmark-alist) (not parg))
  176.       ;; already existing boookmark under that name and
  177.       ;; no prefix arg means just overwrite old bookmark
  178.       (setcdr (assoc str Info-bookmark-alist)
  179.           (list (list Info-current-file Info-current-node (point))))
  180.     ;; otherwise just cons it onto the front (either the bookmark does
  181.     ;; exist already, or there is no prefix arg.  In either case, we
  182.     ;; want the new bookmark consed onto the alist...)
  183.     (setq Info-bookmark-alist
  184.       (cons
  185.        (list str (list Info-current-file Info-current-node (point)))
  186.        Info-bookmark-alist)))
  187.   (if Info-bookmark-always-write-file
  188.       (Info-bookmark-write nil)))
  189.  
  190.  
  191. (defun Info-bookmark-jump (str)
  192.   "Go to the place in Info saved in the bookmark BOOKMARK.  Starts up Info
  193. or switches to an Info buffer if necessary.  You may have a problem using
  194. this function if the value of variable Info-bookmark-alist is nil.  If
  195. that happens, you need to load in some bookmarks.  See help on function
  196. Info-bookmark-load for more about this."
  197.   (interactive (let ((completion-ignore-case
  198.               Info-bookmark-completion-ignore-case))
  199.          (list (completing-read
  200.             "Pleased to enter name of bookmark to jump to: "
  201.             Info-bookmark-alist
  202.             nil
  203.             0))))
  204.   (if (not (equal mode-name "Info"))
  205.       (info)) ; start up or switch to Info if we are not in it already
  206.   (let ((whereto-list (car (cdr (assoc str Info-bookmark-alist)))))
  207.     (let ((file (car whereto-list))
  208.       (node (car (cdr whereto-list)))
  209.       (place (car (cdr (cdr whereto-list)))))
  210.       (Info-find-node file node)
  211.       (goto-char place))))
  212.  
  213.  
  214. (defun Info-bookmark-delete (str)
  215.   "Delete the bookmark named NAME from the bookmark list.  Removes only
  216. the first instance of a bookmark with that name.  If there is another
  217. bookmark with the same name, it will become \"current\" as soon as the
  218. old one is removed from the bookmark list."
  219.     (interactive (let ((completion-ignore-case
  220.             Info-bookmark-completion-ignore-case))
  221.            (list (completing-read
  222.               "Pleased to enter name of bookmark to delete: "
  223.               Info-bookmark-alist
  224.               nil
  225.               0))))
  226.     (let ((will-go (assoc str Info-bookmark-alist)))
  227.       (if (string-equal str (car (car Info-bookmark-alist)))
  228.       (setq Info-bookmark-alist
  229.         (delq will-go Info-bookmark-alist))
  230.     (delq will-go Info-bookmark-alist)))
  231.     (if Info-bookmark-always-write-file
  232.     (Info-bookmark-write nil)))
  233.  
  234.  
  235. (defun Info-bookmark-write (parg &optional file)
  236.   "Saves currently defined Info bookmarks in the file defined by
  237. the variable Info-bookmark-file.  With a prefix arg, save it in file
  238. FILE.
  239.  
  240. If you are calling this from Lisp, the two arguments are PREFIX-ARG
  241. and FILE, and if you just want it to write to the default file,
  242. then pass in nil as the only argument.  Or pass in nil and FILE, and
  243. it will save in FILE instead.  If you pass in one argument, and it is
  244. non-nil, then the user will be interactively queried for a file to
  245. save in.
  246.  
  247. When you want to load in the bookmarks from a file, use Info-bookmark-load,
  248. \\[Info-bookmark-load].  With a prefix arg, that function will prompt you
  249. for a file, otherwise, it uses the file defined by the variable
  250. Info-bookmark-file."
  251.   (interactive "P")
  252.   (cond
  253.    ((and (null parg) (null file))
  254.     ;;whether interactive or not, write to default file
  255.     (Info-bookmark-write-file Info-bookmark-file))
  256.    ((and (null parg) file)
  257.     ;;whether interactive or not, write to given file
  258.     (Info-bookmark-write-file file))
  259.    ((and parg (not file))
  260.     ;;have been called interactively w/ prefix arg
  261.     (let ((file (read-file-name "File to save bookmarks in: ")))
  262.       (Info-bookmark-write-file file)))
  263.    (t ; someone called us with prefix-arg *and* a file, so just write to file
  264.     (Info-bookmark-write-file file))))
  265.  
  266.  
  267. (defun Info-bookmark-write-file (file)
  268.   (save-excursion
  269.     (message (format "Saving bookmarks to file %s." file))
  270.     (set-buffer (find-file-noselect file))
  271.     (goto-char (point-min))
  272.     (delete-region (point-min) (point-max))
  273.     (print Info-bookmark-alist (current-buffer))
  274.     (write-file file)
  275.     (kill-buffer (current-buffer))))
  276.  
  277.  
  278. (defun Info-bookmark-load (file &optional revert)
  279.   "Loads bookmarks from FILE, appending loaded bookmarks to the front
  280. of the list of bookmarks.  If optional second argument REVERT is
  281. non-nil, existing bookmarks are destroyed.
  282.  
  283. If you load a file that doesn't contain a proper bookmark alist, you
  284. will corrupt Emacs\' bookmark list.  Generally, you should only load
  285. in files that were created with the Info-bookmark functions in the
  286. first place."
  287.   (interactive
  288.    (list (read-file-name
  289.       (format "Load bookmarks from: (%s) "
  290.           Info-bookmark-file)    ;Default might not be used often,
  291.                     ;but there's no better default, and
  292.                     ;I guess it's better than none at all.
  293.       "~/" Info-bookmark-file 'confirm)))
  294.   (setq file (expand-file-name file))
  295.   (if (file-readable-p file)
  296.       (save-excursion
  297.     (message (format "Loading bookmarks from %s..." file))
  298.     (set-buffer (find-file-noselect file))
  299.     (goto-char (point-min))
  300.     (let ((blist (car (read-from-string
  301.                (buffer-substring (point-min) (point-max))))))
  302.       (if (listp blist)
  303.           (setq Info-bookmark-alist
  304.             (append blist (if (not revert) Info-bookmark-alist)))
  305.         (error (format "Invalid bookmark list in %s." file))))
  306.     (kill-buffer (current-buffer))
  307.     (message (format "Loading bookmarks from %s...done" file)))
  308.     (error (format "Bookmark file %s is not readable." file))))
  309.  
  310.  
  311. (defun Info-bookmark-revert (&optional not-really)
  312.  
  313.   "Resets the bookmark list, using bookmarks stored in the default
  314. bookmark file.  This will have the effect of deleting any bookmarks
  315. that are not saved in the file.  Asks for confirmation first.
  316.  
  317. This is desirable when you want to get rid of a whole bunch of bookmarks
  318. that you set yourself or loaded in from somewhere else, without you
  319. having to delete them one by one.
  320.  
  321. Use Info-bookmark-load (\\[Info-bookmark-load]) to load bookmarks from
  322. a file without destroying your current bookmarks."
  323.  
  324.   (interactive
  325.    (list (not (y-or-n-p
  326.            (format "Revert to bookmarks from %s? " Info-bookmark-file)))))
  327.   (if not-really
  328.       (message "Bookmark list not reverted.")
  329.     (Info-bookmark-load Info-bookmark-file t)))
  330.  
  331.  
  332. ;; this revert is for when we have real multi-file support.  Ignore it 
  333. ;; for now...
  334. ;;
  335. ;;(defun Info-bookmark-revert ()
  336. ;;  "Delete all existing bookmarks and optionally load some in from a file.
  337. ;;The user is prompted for a file to load bookmarks from, with the default 
  338. ;;bookmark file appearing at the prompt.
  339. ;;
  340. ;;Don't call this from non-interactive Lisp programs, because it always
  341. ;;queries the user for a file."
  342. ;;  (interactive)
  343. ;;  (setq Info-bookmark-alist ())
  344. ;;  (Info-bookmark-load-file
  345. ;;   (expand-file-name
  346. ;;    (read-file-name
  347. ;;     "Bookmark list now empty.  Load bookmarks from file: "
  348. ;;     (if (file-exists-p Info-bookmark-file)
  349. ;;     Info-bookmark-file
  350. ;;       nil)))))
  351.     
  352.  
  353. ;; load the default bookmark file, if it exists.
  354. (if (file-exists-p Info-bookmark-file)
  355.     (Info-bookmark-load Info-bookmark-file))
  356.