]> gitweb.factorcode.org Git - factor.git/blob - misc/fuel/fuel-help.el
Merge commit 'origin/master'
[factor.git] / misc / fuel / fuel-help.el
1 ;;; fuel-help.el -- accessing Factor's help system
2
3 ;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
4 ;; See http://factorcode.org/license.txt for BSD license.
5
6 ;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
7 ;; Keywords: languages, fuel, factor
8 ;; Start date: Wed Dec 03, 2008 21:41
9
10 ;;; Comentary:
11
12 ;; Modes and functions interfacing Factor's 'see' and 'help'
13 ;; utilities, as well as an ElDoc-based autodoc mode.
14
15 ;;; Code:
16
17 (require 'fuel-eval)
18 (require 'fuel-completion)
19 (require 'fuel-font-lock)
20 (require 'fuel-base)
21
22 \f
23 ;;; Customization:
24
25 (defgroup fuel-help nil
26   "Options controlling FUEL's help system"
27   :group 'fuel)
28
29 (defcustom fuel-help-minibuffer-font-lock t
30   "Whether to use font lock for info messages in the minibuffer."
31   :group 'fuel-help
32   :type 'boolean)
33
34 (defcustom fuel-help-always-ask t
35   "When enabled, always ask for confirmation in help prompts."
36   :type 'boolean
37   :group 'fuel-help)
38
39 (defcustom fuel-help-use-minibuffer t
40   "When enabled, use the minibuffer for short help messages."
41   :type 'boolean
42   :group 'fuel-help)
43
44 (defcustom fuel-help-mode-hook nil
45   "Hook run by `factor-help-mode'."
46   :type 'hook
47   :group 'fuel-help)
48
49 (defcustom fuel-help-history-cache-size 50
50   "Maximum number of pages to keep in the help browser cache."
51   :type 'integer
52   :group 'fuel-help)
53
54 (defface fuel-help-font-lock-headlines '((t (:bold t :weight bold)))
55   "Face for headlines in help buffers."
56   :group 'fuel-help
57   :group 'faces)
58
59 \f
60 ;;; Autodoc mode:
61
62 (defvar fuel-help--font-lock-buffer
63   (let ((buffer (get-buffer-create " *fuel help minibuffer messages*")))
64     (set-buffer buffer)
65     (fuel-font-lock--font-lock-setup)
66     buffer))
67
68 (defun fuel-help--font-lock-str (str)
69   (set-buffer fuel-help--font-lock-buffer)
70   (erase-buffer)
71   (insert str)
72   (let ((font-lock-verbose nil)) (font-lock-fontify-buffer))
73   (buffer-string))
74
75 (defun fuel-help--word-synopsis (&optional word)
76   (let ((word (or word (fuel-syntax-symbol-at-point)))
77         (fuel-log--inhibit-p t))
78     (when word
79       (let* ((cmd `(:fuel* (((:quote ,word) synopsis :get)) t))
80              (ret (fuel-eval--send/wait cmd 20)))
81         (when (and ret (not (fuel-eval--retort-error ret)))
82           (if fuel-help-minibuffer-font-lock
83               (fuel-help--font-lock-str (fuel-eval--retort-result ret))
84             (fuel-eval--retort-result ret)))))))
85
86 (make-variable-buffer-local
87  (defvar fuel-autodoc-mode-string " A"
88    "Modeline indicator for fuel-autodoc-mode"))
89
90 (define-minor-mode fuel-autodoc-mode
91   "Toggle Fuel's Autodoc mode.
92 With no argument, this command toggles the mode.
93 Non-null prefix argument turns on the mode.
94 Null prefix argument turns off the mode.
95
96 When Autodoc mode is enabled, a synopsis of the word at point is
97 displayed in the minibuffer."
98   :init-value nil
99   :lighter fuel-autodoc-mode-string
100   :group 'fuel
101
102   (set (make-local-variable 'eldoc-documentation-function)
103        (when fuel-autodoc-mode 'fuel-help--word-synopsis))
104   (set (make-local-variable 'eldoc-minor-mode-string) nil)
105   (eldoc-mode fuel-autodoc-mode)
106   (message "Fuel Autodoc %s" (if fuel-autodoc-mode "enabled" "disabled")))
107
108 \f
109 ;;; Help browser history:
110
111 (defvar fuel-help--history
112   (list nil                                        ; current
113         (make-ring fuel-help-history-cache-size)   ; previous
114         (make-ring fuel-help-history-cache-size))) ; next
115
116 (defvar fuel-help--history-idx 0)
117
118 (defun fuel-help--history-push (term)
119   (when (and (car fuel-help--history)
120              (not (string= (caar fuel-help--history) (car term))))
121     (ring-insert (nth 1 fuel-help--history) (car fuel-help--history)))
122   (setcar fuel-help--history term))
123
124 (defun fuel-help--history-next ()
125   (when (not (ring-empty-p (nth 2 fuel-help--history)))
126     (when (car fuel-help--history)
127       (ring-insert (nth 1 fuel-help--history) (car fuel-help--history)))
128     (setcar fuel-help--history (ring-remove (nth 2 fuel-help--history) 0))))
129
130 (defun fuel-help--history-previous ()
131   (when (not (ring-empty-p (nth 1 fuel-help--history)))
132     (when (car fuel-help--history)
133       (ring-insert (nth 2 fuel-help--history) (car fuel-help--history)))
134     (setcar fuel-help--history (ring-remove (nth 1 fuel-help--history) 0))))
135
136 \f
137 ;;; Fuel help buffer and internals:
138
139 (defun fuel-help--help-buffer ()
140   (with-current-buffer (get-buffer-create "*fuel help*")
141     (fuel-help-mode)
142     (current-buffer)))
143
144 (defvar fuel-help--prompt-history nil)
145
146 (defun fuel-help--show-help (&optional see word)
147   (let* ((def (or word (fuel-syntax-symbol-at-point)))
148          (prompt (format "See%s help on%s: " (if see " short" "")
149                          (if def (format " (%s)" def) "")))
150          (ask (or (not (memq major-mode '(factor-mode fuel-help-mode)))
151                   (not def)
152                   fuel-help-always-ask))
153          (def (if ask (fuel-completion--read-word prompt
154                                                   def
155                                                   'fuel-help--prompt-history)
156                 def))
157          (cmd `(:fuel* ((:quote ,def) ,(if see 'see 'help)) t)))
158     (message "Looking up '%s' ..." def)
159     (fuel-eval--send cmd `(lambda (r) (fuel-help--show-help-cont ,def r)))))
160
161 (defun fuel-help--show-help-cont (def ret)
162   (let ((out (fuel-eval--retort-output ret)))
163     (if (or (fuel-eval--retort-error ret) (empty-string-p out))
164         (message "No help for '%s'" def)
165       (fuel-help--insert-contents def out))))
166
167 (defun fuel-help--insert-contents (def str &optional nopush)
168   (let ((hb (fuel-help--help-buffer))
169         (inhibit-read-only t)
170         (font-lock-verbose nil))
171     (set-buffer hb)
172     (erase-buffer)
173     (insert str)
174     (unless nopush
175       (goto-char (point-min))
176       (when (re-search-forward (format "^%s" def) nil t)
177         (beginning-of-line)
178         (kill-region (point-min) (point))
179         (next-line)
180         (open-line 1)
181         (fuel-help--history-push (cons def (buffer-string)))))
182     (set-buffer-modified-p nil)
183     (pop-to-buffer hb)
184     (goto-char (point-min))
185     (message "%s" def)))
186
187 \f
188 ;;; Interactive help commands:
189
190 (defun fuel-help-short (&optional arg)
191   "See a help summary of symbol at point.
192 By default, the information is shown in the minibuffer. When
193 called with a prefix argument, the information is displayed in a
194 separate help buffer."
195   (interactive "P")
196   (if (if fuel-help-use-minibuffer (not arg) arg)
197       (fuel-help--word-synopsis)
198     (fuel-help--show-help t)))
199
200 (defun fuel-help ()
201   "Show extended help about the symbol at point, using a help
202 buffer."
203   (interactive)
204   (fuel-help--show-help))
205
206 (defun fuel-help-next ()
207   "Go to next page in help browser."
208   (interactive)
209   (let ((item (fuel-help--history-next))
210         (fuel-help-always-ask nil))
211     (unless item
212       (error "No next page"))
213     (fuel-help--insert-contents (car item) (cdr item) t)))
214
215 (defun fuel-help-previous ()
216   "Go to next page in help browser."
217   (interactive)
218   (let ((item (fuel-help--history-previous))
219         (fuel-help-always-ask nil))
220     (unless item
221       (error "No previous page"))
222     (fuel-help--insert-contents (car item) (cdr item) t)))
223
224 \f
225 ;;;; Factor help mode:
226
227 (defvar fuel-help-mode-map
228   (let ((map (make-sparse-keymap)))
229     (define-key map "\C-m" 'fuel-help)
230     (define-key map "q" 'bury-buffer)
231     (define-key map "b" 'fuel-help-previous)
232     (define-key map "f" 'fuel-help-next)
233     (define-key map "l" 'fuel-help-previous)
234     (define-key map "n" 'fuel-help-next)
235     (define-key map (kbd "SPC")  'scroll-up)
236     (define-key map (kbd "S-SPC") 'scroll-down)
237     map))
238
239 (defconst fuel-help--headlines
240   (regexp-opt '("Class description"
241                 "Definition"
242                 "Errors"
243                 "Examples"
244                 "Generic word contract"
245                 "Inputs and outputs"
246                 "Methods"
247                 "Notes"
248                 "Parent topics:"
249                 "See also"
250                 "Syntax"
251                 "Variable description"
252                 "Variable value"
253                 "Vocabulary"
254                 "Warning"
255                 "Word description")
256               t))
257
258 (defconst fuel-help--headlines-regexp (format "^%s" fuel-help--headlines))
259
260 (defconst fuel-help--font-lock-keywords
261   `(,@fuel-font-lock--font-lock-keywords
262     (,fuel-help--headlines-regexp . 'fuel-help-font-lock-headlines)))
263
264 (defun fuel-help-mode ()
265   "Major mode for browsing Factor documentation.
266 \\{fuel-help-mode-map}"
267   (interactive)
268   (kill-all-local-variables)
269   (buffer-disable-undo)
270   (use-local-map fuel-help-mode-map)
271   (setq mode-name "Factor Help")
272   (setq major-mode 'fuel-help-mode)
273
274   (fuel-font-lock--font-lock-setup fuel-help--font-lock-keywords t)
275
276   (setq fuel-autodoc-mode-string "")
277   (fuel-autodoc-mode)
278
279   (run-mode-hooks 'fuel-help-mode-hook)
280   (setq buffer-read-only t))
281
282 \f
283 (provide 'fuel-help)
284 ;;; fuel-help.el ends here