1 ; -*- Mode: Emacs-Lisp -*-
2 ;;; browse-cltl2.el --- browse the hypertext-version of
3 ;;; "Common Lisp the Language, 2nd. Edition"
6 ;; last edited on 19.5.1998
8 ;; Copyright (C) 1997, 1998 Holger Schauer
10 ;; Author: Holger Schauer <Holger.Schauer@gmx.de>
11 ;; Keywords: utils lisp ilisp www
13 ;; This file is part of XEmacs.
15 ;; Developed under XEmacs 19.14. Also tested on Emacs 19.29, 19.32
16 ;; and XEmacs 19.11, 19.16, 20.3. Should work with newer versions, too.
17 ;; Required: browse-url.el
18 ;; Recommended: url.el
20 ;; This program is free software; you can redistribute it and/or modify
21 ;; it under the terms of the GNU General Public License as published by
22 ;; the Free Software Foundation; either version 2 of the License, or
23 ;; (at your option) any later version.
25 ;; This program is distributed in the hope that it will be useful,
26 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
27 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 ;; GNU General Public License for more details.
30 ;; You should have received a copy of the GNU General Public License
31 ;; along with this program; if not, write to the Free Software
32 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 ;; This gives you two top-level-functions useful when programming lisp:
36 ;; cltl2-view-function-definition and cltl2-view-index
37 ;; cltl2-view-function-definition asks you for a name of a lisp
38 ;; function (or variable) and will open up your favourite browser
39 ;; (as specified by `browse-url-browser-function') loading the page
40 ;; which documents it.
42 ;;; Installation: (as usual)
43 ;; Put browse-cltl2.el somewhere where emacs can find it.
44 ;; browse-cltl2.el requires a working browse-url, url and cl.
45 ;; Insert the following lines in your .emacs:
47 ;; (autoload 'cltl2-view-function-definition "browse-cltl2")
48 ;; (autoload 'cltl2-view-index "browse-cltl2")
49 ;; (autoload 'cltl2-lisp-mode-install "browse-cltl2")
50 ;; (add-hook 'lisp-mode-hook 'cltl2-lisp-mode-install)
51 ;; (add-hook 'ilisp-mode-hook 'cltl2-lisp-mode-install)
53 ;; This should also add the needed hooks to lisp-mode (and ilisp-mode).
56 ;; For Gnu Emacs there doesn't seem to be a lisp-mode-hook so you're
57 ;; on your own with the key-settings.
59 ;; If you don't have url.el set *cltl2-use-url* to nil
60 ;; and set *cltl2-fetch-method* to 'local or 'local-index-only.
61 ;; This implies that you need a local copy of the index page of
62 ;; CLtL2 (which you can get from the normal hypertext-version at CMU),
63 ;; so you need to point *cltl2-local-file-pos* and *cltl2-index-file-name*
64 ;; to the place where you put it.
65 ;; Old versions of Emacs (Emacs 19.29 and XEmacs 19.11 for example):
66 ;; When you want to use a local copy (or a local copy of the index file)
67 ;; check the documentation on find-file-noselect. If it doesn't mention
68 ;; an option called RAWFILE set *cltl2-old-find-file-noselect* to 't.
72 ;; By default, browse-cltl2 will use a local copy of CLtL2, looking
73 ;; for it in /usr/doc/html/cltl. This can be modified with the help
74 ;; of the following variables:
75 ;; *cltl2-fetch-method*, *cltl2-url*, *cltl-local-file-pos*
76 ;; See the documentation on this variables for more info.
79 ;; In this version we can't separate between functions, variables,
80 ;; constants and loop clauses. This is not that hard to change,
81 ;; but it is more difficult to distinguish what the user is
82 ;; looking for. Until I receive several requests for it, I won't
83 ;; implement it, because there are not that much constructs like * and +
84 ;; which have two (or more) semantics.
87 ;; 28-01-97: HS: now we're using cl-puthash all over the place because
88 ;; this is common on XEmacs 19.11 and upwards and Gnu Emacs.
89 ;; Added information on how to install without url.el
91 ;; 29-01-97 HS: included conditionalized versions of the required
92 ;; functions match-string and buffer-live-p.
93 ;; Suggested by Simon Marshall <Simon.Marshall@esrin.esa.it>.
94 ;; Included new variable *cltl2-use-url* with which one can
95 ;; specify if he has url.el or not. Introduced variable
96 ;; *cltl2-old-find-file-noselect*.
98 ;; 05-02-97 HS: added two variables for the key-bindings,
99 ;; *cltl2-vfd-key* *cltl2-vi-key*.
101 ;; 18-02-97 HS: use compatible keybindings that work on Gnu Emacs and XEmacs.
102 ;; Made cltl2-lisp-mode-install an interactive function.
104 ;; 28-02-98 HS: use symbol-near-point to obtain a default value to
105 ;; search for and added a history for already searched entries.
107 ;; 22-04-98 HS: added an error message if index-file does not exist.
109 ;; 27-04-98 HS: fixed a bug with the minibuffer history. Thanks to
110 ;; Sam Mikes <smikes@alumni.hmc.edu> for pointing out the
111 ;; existence of `minibuffer-history-minimum-string-length'
113 ;; 19-05-98 HS: changed #' to (function ... in order to make it work
114 ;; with older emacsen. `minibuffer-history-minimum-string-length'
115 ;; is also unknown to older emacsen. `read-string' had only
116 ;; two arguments in Emacs 19.29.
119 (defvar *cltl2-use-url* t
120 "Enables or disables retrieval of the index-file via WWW.
125 (require 'browse-url)
127 ;;; ******************************
128 ;;; Some variable and constant definitions
129 ;;; ******************************
130 (defvar *cltl2-fetch-method* 'www
131 "This sets the method by which the index-file will be fetched.
133 Three methods are possible: 'local assumes that all files are
134 local. 'local-index-only assumes that just the index-file is
135 locally but all other files will be fetched via www. 'www means
136 that the index-file will be fetched via WWW, too. Don't change
137 the value of this variable after loading.")
140 "http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/"
141 "The url where the HTML of Common Lisp the Language can be found.
143 Note that this assumes to be the top-level of the directory structure
144 which should be the same as in the hypertext version as provided by
145 the CMU AI Repository. Defaults to
146 http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/
147 Note the / at the end.")
149 (defvar *cltl2-local-file-pos* "/usr/doc/html/cltl/"
150 "A directory where the CLtl2 can be found.
152 Note that this assumes to be the top-level of the directory structure
153 which should be the same as in the hypertext version as provided by
154 the CMU AI Repository. Defaults to /usr/doc/html/cltl/ Note the / at
157 (defconst *cltl2-index-file-name* "clm/index.html"
158 "The name of the index-file, typically with directory on front.
160 Defaults to clm/index.html, as this is the momentary position from the
161 top-level directory of the CLtL2-home. Defaults to clm/index.html.
162 Note that there is no leading /.")
164 (defvar *cltl2-index-home*
166 (case *cltl2-fetch-method*
167 ('local *cltl2-local-file-pos*)
168 ('local-index-only *cltl2-local-file-pos*)
170 *cltl2-index-file-name*)
171 "The absolute path which will be used to fetch the index.")
176 (case *cltl2-fetch-method*
177 ('local *cltl2-local-file-pos*)
178 ('local-index-only *cltl2-url*)
181 "This specifies the home-position of the CLtL2.
183 The value of this variable will be concatenated with the name of the
184 nodes of the CLtL2.")
186 (defvar *cltl2-index-buffer-name* "*cltl2-index*"
187 "The name of the buffer which holds the index for CLtL2.")
189 (defvar *cltl2-vfd-key*
190 (if (featurep 'ilisp)
193 "Shortcut for accessing cltl2-view-function-definition.
194 Use meaningful setting with Ilisp.")
196 (defvar *cltl2-vi-key*
197 (if (featurep 'ilisp)
200 "Shortcut for accessing cltl2-view-index.
201 Use meaningful setting with Ilisp.")
203 (defvar *browse-cltl2-ht* (make-hash-table :size 25))
205 (defconst *cltl2-search-regexpr*
206 "<a href=\"\\(.+\\)\"><code>\\(.+\\)</code></a>"
207 "A regexp how to check for entries in the index-file of CLtL2.
209 Note that you have to modify this and the prepare-get-entry*-functions
210 if you want to change the search.")
212 (defvar *browse-cltl2-history* nil
213 "History of CLtL2-entries to lookup.")
215 ;;; ******************************
216 ;;; Functions for fetching the index file
217 ;;; ******************************
218 (defun cltl2-fetch-index ()
219 "Fetches the index page of the CLtl2 and puts it in its own
220 buffer called *cltl2-index*."
221 ;; if the index isn't here load it into a buffer
222 (unless (get-buffer *cltl2-index-buffer-name*)
223 (message "Fetching the CLtL2 index file ...")
224 (if (eq *cltl2-fetch-method* 'www)
225 (cltl2-fetch-index-by-www)
226 (cltl2-fetch-index-by-file)))
228 (cltl2-prepare-index)
232 (defun cltl2-fetch-index-by-file ()
233 "Fetch the index from disk."
234 (unless (file-readable-p *cltl2-index-home*)
235 (error "CLtL2 index file not readable: %s" *cltl2-index-home*))
237 (setf *cltl2-index-buffer-name*
238 (find-file-noselect *cltl2-index-home* nil t)))
241 (defvar url-working-buffer))
243 (autoload 'url-retrieve "url")
245 (defun cltl2-fetch-index-by-www ()
246 "Fetch the index via WWW."
248 (let ((url-working-buffer *cltl2-index-buffer-name*))
249 (url-retrieve *cltl2-index-home*))))
251 ;;; ******************************
252 ;;; Main functions for viewing
253 ;;; ******************************
254 (defun cltl2-view-function-definition (entry)
255 "First checks if function can be found in the CLtL2-index-file.
256 If it can be found, uses the function browse-url to have a look
257 at the corresponding documentation from CLtL2."
259 (let ((ol-hist-val (if (boundp 'minibuffer-history-minimum-string-length)
260 minibuffer-history-minimum-string-length
263 (setq minibuffer-history-minimum-string-length nil)
265 (list (read-from-minibuffer
267 "CLtL2-Entry to lookup (default "
268 (symbol-near-point) "):")
270 '*browse-cltl2-history*)))
271 (setq minibuffer-history-minimum-string-length ol-hist-val)
274 (cond ((equal "" entry)
275 (setf entry (symbol-near-point))
276 (setf *browse-cltl2-history*
277 (push entry *browse-cltl2-history*))))
279 (when (cltl2-index-unprepared-p)
282 (let ((entry-url (cltl2-find-url-for-function (intern entry))))
284 (message "Loading found entry for %s into browser.." entry)
286 (concatenate 'string *cltl2-home* entry-url)))))
288 (defun cltl2-find-url-for-function (entry)
289 "Checks if we can find a page for function ENTRY and
290 constructs an URL from it."
291 (let ((entry-url (gethash entry *browse-cltl2-ht*)))
292 (when (not entry-url)
293 (error "No entry in CLtL2 for %s" entry))
296 (defun cltl2-view-index ()
297 "Browse-urls the index file."
299 (browse-url *cltl2-index-home*))
301 ;;; ******************************
302 ;;; Preparing the index (the hashtable)
303 ;;; ******************************
304 (defun cltl2-prepare-index ()
305 "Jumps to the *cltl2-index* buffer and scans it, creating a hashtable
307 (message "Preparing CLtL2 index.")
309 (set-buffer *cltl2-index-buffer-name*)
310 (goto-char (point-min))
313 (do ((point (re-search-forward
314 *cltl2-search-regexpr*
317 *cltl2-search-regexpr*
319 ; until we can't find anymore
320 ((null point)); (format "Index-preparation done."))
321 ; put found entry in hash-table
323 (cltl2-prepare-get-entry-name)
324 (cltl2-prepare-get-entry-url)
325 *browse-cltl2-ht*))))
327 (defun cltl2-prepare-get-entry-name ()
328 "Get the enrty name from the last match of regexp-search for entries."
329 (let ((name-string (intern (match-string 2))))
330 (format "%s" name-string)
333 (defun cltl2-prepare-get-entry-url ()
334 "Get the enrty url from the last match of regexp-search for entries."
335 (let ((url (match-string 1)))
339 (defun cltl2-index-unprepared-p ()
340 "Check if the index is already prepared."
341 ; If the hashtable has entries the index is prepared.
342 (not (and (hash-table-p *browse-cltl2-ht*)
343 (>= (hash-table-count *browse-cltl2-ht*) 1))))
345 ;;; ******************************
346 ;;; Hooking into lisp mode and ilisp-mode
347 ;;; ******************************
348 (defun cltl2-lisp-mode-install ()
349 "Adds browse-cltl2 to lisp-mode. If you use ilisp (installed via a hook
350 on lisp-mode) add browse-cltl2 to ilisp. Check the variables *cltl2-vfd-key*
351 and *cltl2-vi-key* for the keybindings. Under XEmacs we will add ourself to
352 the corresponding menus if there exists one."
355 (local-set-key *cltl2-vfd-key* 'cltl2-view-function-definition)
356 (local-set-key *cltl2-vi-key* 'cltl2-view-index)
357 ; under XEmacs hook ourself into the menu if there is one
358 (when (string-match "XEmacs\\|Lucid" emacs-version)
359 (cond ((and (featurep 'ilisp-easy-menu)
360 ; this is for the menu as provided by ilisp-easy-menu
361 (not (null (car (find-menu-item current-menubar '("ILisp"))))))
363 '("ILisp" "Documentation")
365 [ "View entry" cltl2-view-function-definition t]
366 [ "View index" cltl2-view-index t] )))
367 ; perhaps an other Ilisp-Menu is there ?
368 ((not (null (car (find-menu-item current-menubar '("ILisp")))))
372 [ "View entry" cltl2-view-function-definition t]
373 [ "View index" cltl2-view-index t] )))
374 ; or at least a Lisp-Menu ?
375 ((not (null (car (find-menu-item current-menubar '("Lisp")))))
379 [ "View entry" cltl2-view-function-definition t]
380 [ "View index" cltl2-view-index t] )))))
383 (add-hook 'lisp-mode-hook 'cltl2-lisp-mode-install)
384 (add-hook 'ilisp-mode-hook 'cltl2-lisp-mode-install)
386 ;;; Providing ourself.
387 (provide 'ilisp-browse-cltl2)
388 ;;; browse-cltl2.el ends here.