comparison lisp/utils/browse-cltl2.el @ 22:8fc7fe29b841 r19-15b94

Import from CVS: tag r19-15b94
author cvs
date Mon, 13 Aug 2007 08:50:29 +0200
parents
children 4103f0995bd7
comparison
equal deleted inserted replaced
21:b88636d63495 22:8fc7fe29b841
1 ; -*- Mode: Emacs-Lisp -*-
2 ;;; browse-cltl2.el --- browse the hypertext-version of
3 ;;; "Common Lisp the Language, 2nd. Edition"
4
5 ;; Revision 1.1.1
6 ;; last edited on 29.1.1997
7
8 ;; Copyright (C) 1997 Holger Schauer
9
10 ;; Author: Holger Schauer <Holger.Schauer@gmd.de>
11 ;; Keywords: utils lisp ilisp
12
13 ;; This file is not part of Emacs.
14
15 ;; Developed under XEmacs 19.14. Also tested on Emacs 19.32 and
16 ;; XEmacs 19.11. Should work with newer versions, too.
17 ;; Required: browse-url.el
18 ;; Recommended: url.el
19
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.
24 ;;
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.
29 ;;
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.
33
34 ;;; Commentary:
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.
41
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:
46 ;;
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)
52 ;;
53 ;; This should also add the needed hooks to lisp-mode (and ilisp-mode).
54
55 ;; Gnu Emacs:
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.
58 ;; No url.el:
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 (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.
69
70
71 ;;; Customization:
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.
77 ;;
78 ;;; TODO:
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.
85
86 ;;; Changes:
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
90 ;;
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*.
97 (defvar *cltl2-use-url* 'nil
98 "Enables or disables retrieval of the index-file via WWW (or more
99 exactly by the use of the function url-retrieve from url.el).
100 Default is 't.")
101
102 ;; needed things
103 (require 'cl)
104 (require 'browse-url)
105
106 (when (not *cltl2-use-url*)
107 (require 'url))
108
109 ;;; ******************************
110 ;;; Some variable and constant definitions
111 ;;; ******************************
112 (defvar *cltl2-fetch-method* 'local
113 "This sets the method by which the index-file will be fetched. Three
114 methods are possible: 'local assumes that all files are local.
115 'local-index-only assumes that just the index-file is locally but
116 all other files will be fetched via www. 'www means that the index-file
117 will be fetched via WWW, too. Don't change the value of this variable
118 after loading.")
119
120 (defvar *cltl2-url*
121 "http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/"
122 "The url where the hypertext-version of Common Lisp the Language
123 can be found. Note that this assumes to be the top-level of the
124 directory structure which should be the same as in the hypertext
125 version as provided by the CMU AI Repository. Defaults to
126 http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/html/cltl/
127 Note the / at the end.")
128
129 (defvar *cltl2-local-file-pos* "/usr/doc/html/cltl/"
130 "A directory where the CLtl2 can be found. Note that this assumes
131 to be the top-level of the directory structure which should be the
132 same as in the hypertext version as provided by the CMU AI Repository.
133 Defaults to /usr/doc/html/cltl/ Note the / at the end.")
134
135 (defconst *cltl2-index-file-name* "clm/index.html"
136 "The name of the index-file, typically with directory on front.
137 Defaults to clm/index.html, as this is the momentary position from
138 the top-level directory of the CLtL2-home. Defaults to clm/index.html.
139 Note that there is no leading /.")
140
141 (defvar *cltl2-index-home*
142 (concatenate 'string
143 (case *cltl2-fetch-method*
144 ('local *cltl2-local-file-pos*)
145 ('local-index-only *cltl2-local-file-pos*)
146 ('www *cltl2-url*))
147 *cltl2-index-file-name*)
148 "The absolute path which will be used to fetch the index.")
149
150 (defvar *cltl2-home*
151 (concatenate
152 'string
153 (case *cltl2-fetch-method*
154 ('local *cltl2-local-file-pos*)
155 ('local-index-only *cltl2-url*)
156 ('www *cltl2-url*))
157 "clm/")
158 "This specifies the home-position of the CLtL2. The value of this variable
159 will be concatenated with the name of the nodes of the CLtL2.")
160
161 (defvar *cltl2-index-buffer-name* "*cltl2-index*"
162 "The name of the buffer which holds the index for CLtL2.")
163
164 (defvar *cltl2-old-find-file-noselect* 'nil
165 "Older versions of Emacs (at least XEmacs 19.11) don't support the
166 option RAWFILE with the function FIND-FILE-NO-SELECT. Set this variable
167 to 't if you have such an old version. It will cause fontification and
168 other useless stuff on the buffer in which the index is fetched. If
169 you don't use a local copy (of the index) this won't bother you.")
170
171 (defvar *browse-cltl2-ht* (make-hash-table 0))
172 (defconst *cltl2-search-regexpr*
173 "<a href=\"\\(.+\\)\"><code>\\(.+\\)</code></a>"
174 "A regular expression how to check for entries in the index-file
175 of CLtL2. Note that you have to modify this and the
176 prepare-get-entry*-functions if you want to change the search.")
177
178 ;;; ******************************
179 ;;; First of all: Compatibility stuff
180 ;;; ******************************
181 ; no match-string in old versions
182 (if (not (fboundp (function match-string)))
183 (defun match-string (num &optional string)
184 "Return string of text matched by last search.
185 NUM specifies which parenthesized expression in the last regexp.
186 Value is nil if NUMth pair didn't match, or there were less than NUM pairs.
187 Zero means the entire text matched by the whole regexp or whole string.
188 STRING should be given if the last search was by `string-match' on STRING."
189 (if (match-beginning num)
190 (if string
191 (substring string (match-beginning num) (match-end num))
192 (buffer-substring
193 (match-beginning num) (match-end num))))))
194
195 ; no buffer-live-p in old versions
196 (if (not (fboundp (function buffer-live-p)))
197 (defun buffer-live-p (buf-or-name)
198 "Checks if BUF-OR-NAME is a live buffer. Returns non-nil
199 if BOF-OR-NAME is an editor buffer which has not been deleted.
200 Imitating a built-in function from newer Emacs versions."
201 (let ((object (if (bufferp buf-or-name)
202 buf-or-name
203 (get-buffer buf-or-name))))
204 (and (bufferp object) (buffer-name object)))))
205
206 ; no add-submenu in old versions of XEmacs
207 (if (and (string-match "XEmacs\\|Lucid" emacs-version)
208 (not (fboundp 'add-submenu)))
209 (defun add-submenu (menu-path submenu &optional before)
210 "Add a menu to the menubar or one of its submenus.
211 If the named menu exists already, it is changed.
212 MENU-PATH identifies the menu under which the new menu should be inserted.
213 It is a list of strings; for example, (\"File\") names the top-level \"File\"
214 menu. (\"File\" \"Foo\") names a hypothetical submenu of \"File\".
215 If MENU-PATH is nil, then the menu will be added to the menubar itself.
216 SUBMENU is the new menu to add.
217 See the documentation of `current-menubar' for the syntax.
218 BEFORE, if provided, is the name of a menu before which this menu should
219 be added, if this menu is not on its parent already. If the menu is already
220 present, it will not be moved."
221 (add-menu menu-path (car submenu) (cdr submenu) before)))
222
223 ; old find-file-noselect has no RAWFILE argument
224 (if *cltl2-old-find-file-noselect*
225 (unless (boundp 'cltl2-old-find-file-noselect-func)
226 (setf (symbol-value 'cltl2-old-find-file-noselect-func)
227 (symbol-function 'find-file-noselect))
228 (setf (symbol-function 'find-file-noselect)
229 #'(lambda (file &optional nowarn rawfile)
230 (funcall cltl2-old-find-file-noselect-func file nowarn)))))
231
232 ;;; ******************************
233 ;;; Functions for fetching the index file
234 ;;; ******************************
235 (defun cltl2-fetch-index ()
236 "Fetches the index page of the CLtl2 and puts it in its own
237 buffer called *cltl2-index*."
238 ;; if the index isn't here load it into a buffer
239 (when (or (not (get-buffer *cltl2-index-buffer-name*))
240 (not (buffer-live-p *cltl2-index-buffer-name*)))
241 (message "Fetching the CLtL2 index file ...")
242 (case *cltl2-fetch-method*
243 ('local
244 (cltl2-fetch-index-by-file))
245 ('local-index-only
246 (cltl2-fetch-index-by-file))
247 ('www
248 (cltl2-fetch-index-by-www))))
249
250 (cltl2-prepare-index)
251 )
252
253 ;; fetch methods
254 (defun cltl2-fetch-index-by-file ()
255 "Fetch the index from disk."
256 (setf *cltl2-index-buffer-name*
257 (find-file-noselect *cltl2-index-home* 'nil 't))
258 )
259
260 (defun cltl2-fetch-index-by-www ()
261 "Fetch the index via WWW."
262 (save-excursion
263 (let ((old-url-working-buffer url-working-buffer))
264 (setf url-working-buffer *cltl2-index-buffer-name*)
265 (url-retrieve *cltl2-index-home*)
266 (setf url-working-buffer old-url-working-buffer))))
267
268
269 ;;; ******************************
270 ;;; Main functions for viewing
271 ;;; ******************************
272 (defun cltl2-view-function-definition (entry)
273 "First checks if function can be found in the CLtL2-index-file.
274 If it can be found, uses the function browse-url to have a look
275 at the corresponding documentation from CLtL2."
276 (interactive "sCLtL2-Entry to lookup:")
277 (when (cltl2-index-unprepared-p)
278 (cltl2-fetch-index))
279
280 (let ((entry-url (cltl2-find-url-for-function (intern entry))))
281 (when entry-url
282 (message "Loading found entry for %s into browser.." entry)
283 (browse-url
284 (concatenate 'string *cltl2-home* entry-url)))))
285
286 (defun cltl2-find-url-for-function (entry)
287 "Checks if we can find a page for function ENTRY and
288 constructs an URL from it."
289 (let ((entry-url (gethash entry *browse-cltl2-ht*)))
290 (when (not entry-url)
291 (error "No entry in CLtL2 for %s" entry))
292 entry-url))
293
294 (defun cltl2-view-index ()
295 "Browse-urls the index file."
296 (interactive)
297 (browse-url *cltl2-index-home*))
298
299 ;;; ******************************
300 ;;; Preparing the index (the hashtable)
301 ;;; ******************************
302 (defun cltl2-prepare-index ()
303 "Jumps to the *cltl2-index* buffer and scans it, creating a hashtable
304 for all entries."
305 (message "Preparing CLtL2 index.")
306 (save-excursion
307 (set-buffer *cltl2-index-buffer-name*)
308 (goto-char (point-min))
309
310 ; search for entry
311 (do ((point (re-search-forward
312 *cltl2-search-regexpr*
313 nil t)
314 (re-search-forward
315 *cltl2-search-regexpr*
316 nil t)))
317 ; until we can't find anymore
318 ((null point)); (format "Index-preparation done."))
319 ; put found entry in hash-table
320 (cl-puthash
321 (cltl2-prepare-get-entry-name)
322 (cltl2-prepare-get-entry-url)
323 *browse-cltl2-ht*))))
324
325 (defun cltl2-prepare-get-entry-name ()
326 "Get the enrty name from the last match of regexp-search for entries."
327 (let ((name-string (intern (match-string 2))))
328 (format "%s" name-string)
329 name-string))
330
331 (defun cltl2-prepare-get-entry-url ()
332 "Get the enrty url from the last match of regexp-search for entries."
333 (let ((url (match-string 1)))
334 (format "%s" url)
335 url))
336
337 (defun cltl2-index-unprepared-p ()
338 "Check if the index is already prepared."
339 ; If the hashtable has entries the index is prepared.
340 (not (and (hash-table-p *browse-cltl2-ht*)
341 (>= (hash-table-count *browse-cltl2-ht*) 1))))
342
343 ;;; ******************************
344 ;;; Hooking into lisp mode and ilisp-mode
345 ;;; ******************************
346 (defun cltl2-lisp-mode-install ()
347 "Not to be called by the user - just for lisp-mode-hook and ilisp-mode-hook.
348
349 Adds browse-cltl2 to lisp-mode. If you use ilisp (installed via a hook
350 on lisp-mode) add browse-cltl2 to ilisp. Under Ilisp we use C-zb and C-zB
351 and without Ilisp we use C-cb and C-cB for calling the cltl2-view-functions.
352 Under XEmacs we will add ourself to the corresponding menus if there exists
353 one.."
354 ; set key bindings
355 (cond ((featurep 'ilisp)
356 (local-set-key "\C-zb" 'cltl2-view-function-definition)
357 (local-set-key "\C-zB" 'cltl2-view-index))
358 (t
359 (local-set-key "\C-cb" 'cltl2-view-function-definition)
360 (local-set-key "\C-cB" 'cltl2-view-index)))
361 ; under XEmacs hook ourself into the menu if there is one
362 (when (string-match "XEmacs\\|Lucid" emacs-version)
363 ; this is for the menu as provided by ilisp-easy-menu
364 (cond ((not (null (car (find-menu-item current-menubar '("ILisp")))))
365 (add-submenu
366 '("ILisp" "Documentation")
367 '("Browse CLtL2"
368 [ "View entry" cltl2-view-function-definition t]
369 [ "View index" cltl2-view-index t] )))
370 ((not (null (car (find-menu-item current-menubar '("Lisp")))))
371 (add-submenu
372 '("Lisp")
373 '("Browse CLtL2"
374 [ "View entry" cltl2-view-function-definition t]
375 [ "View index" cltl2-view-index t] )))))
376 )
377
378 (add-hook 'lisp-mode-hook 'cltl2-lisp-mode-install)
379 (add-hook 'ilisp-mode-hook 'cltl2-lisp-mode-install)
380
381 ;;; Providing ourself.
382 (provide 'ilisp-browse-cltl2)
383 ;;; browse-cltl2.el ends here.