Initial Commit
[packages] / xemacs-packages / speedbar / sb-info.el.upstream
1 ;;; sb-info --- Speedbar support for Info
2
3 ;; Copyright (C) 1997, 1998, 2000, 2001, 2002, 2005 Free Software Foundation
4 ;;
5 ;; Author: Eric M. Ludlam <zappo@gnu.ai.mit.edu>
6 ;; Version: 0.3
7 ;; Keywords: file, tags, tools
8 ;; X-RCS: $Id: sb-info.el.upstream,v 1.1 2007-12-02 07:28:59 michaels Exp $
9 ;;
10 ;; This file is patch of GNU Emacs.
11 ;;
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
16 ;;
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;; GNU General Public License for more details.
21 ;;
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with this program; if not, you can either send email to this
24 ;; program's author (see below) or write to:
25 ;;
26 ;;              The Free Software Foundation, Inc.
27 ;;              675 Mass Ave.
28 ;;              Cambridge, MA 02139, USA.
29 ;;
30 ;; Please send bug reports, etc. to zappo@gnu.org
31 ;;
32
33 ;;; Commentary:
34 ;;
35 ;;   Speedbar provides a frame in which files, and locations in
36 ;; files are displayed.  These functions provide Info specific support,
37 ;; showing links and addresses in the side-bar.
38 ;;
39 ;;   To enable in Emacs 20.2 or earlier, add this to your .emacs file.
40 ;;   (autoload 'Info-speedbar-buttons "sb-info"
41 ;;             "Info specific speedbar button generator.")
42 ;;
43 ;;   This file requires speedbar and Info.
44
45 ;;; Change log:
46 ;; 0.1   - first revision copied from speedbspec.el V 0.1.1
47 ;; 0.1.1 - No longer require speedbspec
48 ;; 0.2   - Added a speedbar major mode for displaying Info nodes, and modeled
49 ;;         the minor mode after it.  Completely replaced the old info display
50 ;;         with the major mode, and mixed them to move nicely from major to
51 ;;         minor mode effortlessly.
52 ;; 0.2.1   Added section adding major display mode at load time.
53
54 (require 'speedbar)
55 (require 'info)
56
57 ;;; Code:
58 (defvar Info-speedbar-key-map nil
59   "Keymap used when in the info display mode.")
60
61 (defun Info-install-speedbar-variables ()
62   "Install those variables used by speedbar to enhance Info."
63   (if Info-speedbar-key-map
64       nil
65     (setq Info-speedbar-key-map (speedbar-make-specialized-keymap))
66
67     ;; Basic tree features
68     (define-key Info-speedbar-key-map "e" 'speedbar-edit-line)
69     (define-key Info-speedbar-key-map "\C-m" 'speedbar-edit-line)
70     (define-key Info-speedbar-key-map "+" 'speedbar-expand-line)
71     (define-key Info-speedbar-key-map "=" 'speedbar-expand-line)
72     (define-key Info-speedbar-key-map "-" 'speedbar-contract-line)
73     (define-key Info-speedbar-key-map " " 'speedbar-toggle-line-expansion)
74     )
75
76   (speedbar-add-expansion-list '("Info" Info-speedbar-menu-items
77                                  Info-speedbar-key-map
78                                  Info-speedbar-hierarchy-buttons)))
79
80 (defvar Info-speedbar-menu-items
81   '(["Browse Node" speedbar-edit-line t]
82     ["Expand Node" speedbar-expand-line
83      (save-excursion (beginning-of-line)
84                      (looking-at "[0-9]+: *.\\+. "))]
85     ["Contract Node" speedbar-contract-line
86      (save-excursion (beginning-of-line)
87                      (looking-at "[0-9]+: *.-. "))]
88     )
89   "Additional menu-items to add to speedbar frame.")
90
91 ;; Make sure our special speedbar major mode is loaded
92 (if (featurep 'speedbar)
93     (Info-install-speedbar-variables)
94   (add-hook 'speedbar-load-hook 'Info-install-speedbar-variables))
95
96 ;;; Info hierarchy display method
97 ;;;###autoload
98 (defun Info-speedbar-browser ()
99   "Initialize speedbar to display an info node browser.
100 This will add a speedbar major display mode."
101   (interactive)
102   (require 'speedbar)
103   ;; Make sure that speedbar is active
104   (speedbar-frame-mode 1)
105   ;; Now, throw us into Info mode on speedbar.
106   (speedbar-change-initial-expansion-list "Info")
107   )
108
109 (defvar Info-speedbar-image-button-alist
110   '(("<+>" . ezimage-document-plus)
111     ("<->" . ezimage-document-minus)
112     ("[+]" . ezimage-page-plus)
113     ("[-]" . ezimage-page-minus)
114     ("[?]" . ezimage-page)
115     ("[ ]" . ezimage-page)
116     )
117   "Image buttons used for Info mode.")
118
119 (defun Info-speedbar-hierarchy-buttons (directory depth &optional node)
120   "Display an Info directory hierarchy in speedbar.
121 DIRECTORY is the current directory in the attached frame.
122 DEPTH is the current indentation depth.
123 NODE is an optional argument that is used to represent the
124 specific node to expand."
125   (if (and (not node)
126            (save-excursion (goto-char (point-min))
127                            (looking-at "Info Nodes:")))
128       ;; Update our "current node" maybe?
129       nil
130     ;; We cannot use the generic list code, that depends on all leaves
131     ;; being known at creation time.
132     (if (not node)
133         (speedbar-with-writable (insert "Info Nodes:\n")))
134     (let ((completions nil)
135           (speedbar-expand-image-button-alist
136            Info-speedbar-image-button-alist))
137       (dframe-select-attached-frame speedbar-frame)
138       (save-window-excursion
139         (setq completions
140               (Info-speedbar-fetch-file-nodes (or node '"(dir)top"))))
141       (select-frame speedbar-frame)
142       (if completions
143           (speedbar-with-writable
144            (while completions
145              (speedbar-make-tag-line (if (= depth 0)
146                                          'angle
147                                        'bracket)
148                                      ?+ 'Info-speedbar-expand-node
149                                      (cdr (car completions))
150                                      (car (car completions))
151                                      'Info-speedbar-goto-node
152                                      (cdr (car completions))
153                                      'info-xref depth)
154              (setq completions (cdr completions)))
155            t)
156         nil))))
157   
158 (defun Info-speedbar-goto-node (text node indent)
159   "When user clicks on TEXT, goto an info NODE.
160 The INDENT level is ignored."
161   (dframe-select-attached-frame speedbar-frame)
162   (let* ((buff (or (get-buffer "*info*")
163                    (progn (info) (get-buffer "*info*"))))
164          (bwin (get-buffer-window buff 0)))
165     (if bwin
166         (progn
167           (select-window bwin)
168           (raise-frame (window-frame bwin)))
169       (if dframe-power-click
170           (let ((pop-up-frames t)) (select-window (display-buffer buff)))
171         (dframe-select-attached-frame speedbar-frame)
172         (switch-to-buffer buff)))
173     (if (string-match "^(\\([^)]+\\))\\([^,:]+\\)$" node)
174         (let ((file (match-string 1 node))
175               (node (match-string 2 node)))
176           (Info-find-node file node)
177           ;; If we do a find-node, and we were in info mode, restore
178           ;; the old default method.  Once we are in info mode, it makes
179           ;; sense to return to whatever method the user was using before.
180           (if (string= speedbar-initial-expansion-list-name "Info")
181               (speedbar-change-initial-expansion-list
182                speedbar-previously-used-expansion-list-name))))))
183
184 (defun Info-speedbar-expand-node (text token indent)
185   "Expand the node the user clicked on.
186 TEXT is the text of the button we clicked on, a + or - item.
187 TOKEN is data related to this node (NAME . FILE).
188 INDENT is the current indentation depth."
189   (let ((speedbar-expand-image-button-alist Info-speedbar-image-button-alist))
190     (cond ((string-match "+" text)      ;we have to expand this file
191            (speedbar-change-expand-button-char ?-)
192            (if (speedbar-with-writable
193                  (save-excursion
194                    (end-of-line) (forward-char 1)
195                    (Info-speedbar-hierarchy-buttons nil (1+ indent) token)))
196                (speedbar-change-expand-button-char ?-)
197              (speedbar-change-expand-button-char ??)))
198           ((string-match "-" text)      ;we have to contract this node
199            (speedbar-change-expand-button-char ?+)
200            (speedbar-delete-subblock indent))
201           (t (error "Ooops... not sure what to do")))
202     (speedbar-center-buffer-smartly)))
203   
204 (defun Info-speedbar-fetch-file-nodes (nodespec)
205   "Fetch the subnodes from the info NODESPEC.
206 NODESPEC is a string of the form: (file)node.
207 Optional THISFILE represends the filename of"
208   (save-excursion
209     ;; Set up a buffer we can use to fake-out Info.
210     (set-buffer (get-buffer-create "*info-browse-tmp*"))
211     (if (not (equal major-mode 'Info-mode))
212         (Info-mode))
213     ;; Get the node into this buffer
214     (if (string-match "^(\\([^)]+\\))\\([^,:]+\\)$" nodespec)
215         (let ((file (match-string 1 nodespec))
216               (node (match-string 2 nodespec)))
217           (Info-find-node file node))
218       (error "Node %s not found!" nodespec))
219     ;; Scan the created buffer
220     (goto-char (point-min))
221     (let ((completions nil)
222           (thisfile (progn (string-match "^(\\([^)]+\\))" nodespec)
223                            (match-string 1 nodespec))))
224       ;; Always skip the first one...
225       (re-search-forward "\n\\* \\([^:\t\n]*\\):" nil t)
226       (while (re-search-forward "\n\\* \\([^:\t\n]*\\):" nil t)
227         (let ((name (match-string 1)))
228           (if (looking-at " *\\(([^)]+)[^.\n]+\\)\\.")
229               (setq name (cons name (match-string 1)))
230             (if (looking-at "[ \t]*\\(([^)]+)\\)\\.")
231                 (setq name (cons name (concat (match-string 1) "Top")))
232               (if (looking-at " \\([^.]+\\).")
233                   (setq name
234                         (cons name (concat "(" thisfile ")" (match-string 1))))
235                 (setq name (cons name (concat "(" thisfile ")" name))))))
236           (setq completions (cons name completions))))
237       (nreverse completions))))
238
239 ;;; Info mode node listing
240 ;;;###autoload
241 (defun Info-speedbar-buttons (buffer)
242   "Create a speedbar display to help navigation in an Info file.
243 BUFFER is the buffer speedbar is requesting buttons for."
244   (if (save-excursion (goto-char (point-min))
245                       (not (looking-at "Info Nodes:")))
246       (erase-buffer))
247   (Info-speedbar-hierarchy-buttons nil 0)
248   )
249
250 (provide 'sb-info)
251
252 ;;; Overriding preinstalled code.
253 ;;;###autoload
254 (eval-after-load "info" '(require 'sb-info))
255 ;;; sb-info.el ends here