1 ;;; fuel-help.el -- accessing Factor's help system
3 ;; Copyright (C) 2008 Jose Antonio Ortega Ruiz
4 ;; See http://factorcode.org/license.txt for BSD license.
6 ;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
7 ;; Keywords: languages, fuel, factor
8 ;; Start date: Wed Dec 03, 2008 21:41
12 ;; Modes and functions interfacing Factor's 'see' and 'help'
13 ;; utilities, as well as an ElDoc-based autodoc mode.
18 (require 'fuel-completion)
19 (require 'fuel-font-lock)
25 (defgroup fuel-help nil
26 "Options controlling FUEL's help system"
29 (defcustom fuel-help-minibuffer-font-lock t
30 "Whether to use font lock for info messages in the minibuffer."
34 (defcustom fuel-help-always-ask t
35 "When enabled, always ask for confirmation in help prompts."
39 (defcustom fuel-help-use-minibuffer t
40 "When enabled, use the minibuffer for short help messages."
44 (defcustom fuel-help-mode-hook nil
45 "Hook run by `factor-help-mode'."
49 (defcustom fuel-help-history-cache-size 50
50 "Maximum number of pages to keep in the help browser cache."
54 (defface fuel-help-font-lock-headlines '((t (:bold t :weight bold)))
55 "Face for headlines in help buffers."
62 (defvar fuel-help--font-lock-buffer
63 (let ((buffer (get-buffer-create " *fuel help minibuffer messages*")))
65 (fuel-font-lock--font-lock-setup)
68 (defun fuel-help--font-lock-str (str)
69 (set-buffer fuel-help--font-lock-buffer)
72 (let ((font-lock-verbose nil)) (font-lock-fontify-buffer))
75 (defun fuel-help--word-synopsis (&optional word)
76 (let ((word (or word (fuel-syntax-symbol-at-point)))
77 (fuel-log--inhibit-p t))
79 (let* ((cmd (if (fuel-syntax--in-using)
80 `(:fuel* (,word fuel-vocab-summary) t t)
81 `(:fuel* (((:quote ,word) synopsis :get)) t)))
82 (ret (fuel-eval--send/wait cmd 20))
83 (res (fuel-eval--retort-result ret)))
84 (when (and ret (not (fuel-eval--retort-error ret)) (stringp res))
85 (if fuel-help-minibuffer-font-lock
86 (fuel-help--font-lock-str res)
89 (make-variable-buffer-local
90 (defvar fuel-autodoc-mode-string " A"
91 "Modeline indicator for fuel-autodoc-mode"))
93 (define-minor-mode fuel-autodoc-mode
94 "Toggle Fuel's Autodoc mode.
95 With no argument, this command toggles the mode.
96 Non-null prefix argument turns on the mode.
97 Null prefix argument turns off the mode.
99 When Autodoc mode is enabled, a synopsis of the word at point is
100 displayed in the minibuffer."
102 :lighter fuel-autodoc-mode-string
105 (set (make-local-variable 'eldoc-documentation-function)
106 (when fuel-autodoc-mode 'fuel-help--word-synopsis))
107 (set (make-local-variable 'eldoc-minor-mode-string) nil)
108 (eldoc-mode fuel-autodoc-mode)
109 (message "Fuel Autodoc %s" (if fuel-autodoc-mode "enabled" "disabled")))
112 ;;; Help browser history:
114 (defvar fuel-help--history
116 (make-ring fuel-help-history-cache-size) ; previous
117 (make-ring fuel-help-history-cache-size))) ; next
119 (defvar fuel-help--history-idx 0)
121 (defun fuel-help--history-push (term)
122 (when (and (car fuel-help--history)
123 (not (string= (caar fuel-help--history) (car term))))
124 (ring-insert (nth 1 fuel-help--history) (car fuel-help--history)))
125 (setcar fuel-help--history term))
127 (defun fuel-help--history-next ()
128 (when (not (ring-empty-p (nth 2 fuel-help--history)))
129 (when (car fuel-help--history)
130 (ring-insert (nth 1 fuel-help--history) (car fuel-help--history)))
131 (setcar fuel-help--history (ring-remove (nth 2 fuel-help--history) 0))))
133 (defun fuel-help--history-previous ()
134 (when (not (ring-empty-p (nth 1 fuel-help--history)))
135 (when (car fuel-help--history)
136 (ring-insert (nth 2 fuel-help--history) (car fuel-help--history)))
137 (setcar fuel-help--history (ring-remove (nth 1 fuel-help--history) 0))))
140 ;;; Fuel help buffer and internals:
142 (defun fuel-help--help-buffer ()
143 (with-current-buffer (get-buffer-create "*fuel help*")
147 (defvar fuel-help--prompt-history nil)
149 (defun fuel-help--show-help (&optional see word)
150 (let* ((def (or word (fuel-syntax-symbol-at-point)))
151 (prompt (format "See%s help on%s: " (if see " short" "")
152 (if def (format " (%s)" def) "")))
153 (ask (or (not (memq major-mode '(factor-mode fuel-help-mode)))
155 fuel-help-always-ask))
156 (def (if ask (fuel-completion--read-word prompt
158 'fuel-help--prompt-history
161 (cmd `(:fuel* ((:quote ,def) ,(if see 'see 'help)) t)))
162 (message "Looking up '%s' ..." def)
163 (fuel-eval--send cmd `(lambda (r) (fuel-help--show-help-cont ,def r)))))
165 (defun fuel-help--show-help-cont (def ret)
166 (let ((out (fuel-eval--retort-output ret)))
167 (if (or (fuel-eval--retort-error ret) (empty-string-p out))
168 (message "No help for '%s'" def)
169 (fuel-help--insert-contents def out))))
171 (defun fuel-help--insert-contents (def str &optional nopush)
172 (let ((hb (fuel-help--help-buffer))
173 (inhibit-read-only t)
174 (font-lock-verbose nil))
179 (goto-char (point-min))
180 (when (re-search-forward (format "^%s" def) nil t)
182 (kill-region (point-min) (point))
183 (fuel-help--history-push (cons def (buffer-string)))))
184 (set-buffer-modified-p nil)
186 (goto-char (point-min))
190 ;;; Help mode font lock:
192 (defconst fuel-help--headlines
193 (regexp-opt '("Class description"
197 "Generic word contract"
204 "Variable description"
211 (defconst fuel-help--headlines-regexp (format "^%s" fuel-help--headlines))
213 (defconst fuel-help--font-lock-keywords
214 `(,@fuel-font-lock--font-lock-keywords
215 (,fuel-help--headlines-regexp . 'fuel-help-font-lock-headlines)))
219 ;;; Interactive help commands:
221 (defun fuel-help-short (&optional arg)
222 "See a help summary of symbol at point.
223 By default, the information is shown in the minibuffer. When
224 called with a prefix argument, the information is displayed in a
225 separate help buffer."
227 (if (if fuel-help-use-minibuffer (not arg) arg)
228 (fuel-help--word-synopsis)
229 (fuel-help--show-help t)))
232 "Show extended help about the symbol at point, using a help
235 (fuel-help--show-help))
237 (defun fuel-help-next ()
238 "Go to next page in help browser."
240 (let ((item (fuel-help--history-next))
241 (fuel-help-always-ask nil))
243 (error "No next page"))
244 (fuel-help--insert-contents (car item) (cdr item) t)))
246 (defun fuel-help-previous ()
247 "Go to next page in help browser."
249 (let ((item (fuel-help--history-previous))
250 (fuel-help-always-ask nil))
252 (error "No previous page"))
253 (fuel-help--insert-contents (car item) (cdr item) t)))
255 (defun fuel-help-next-headline (&optional count)
258 (when (re-search-forward fuel-help--headlines-regexp nil t (or count 1))
259 (beginning-of-line)))
261 (defun fuel-help-previous-headline (&optional count)
263 (re-search-backward fuel-help--headlines-regexp nil t count))
268 (defvar fuel-help-mode-map
269 (let ((map (make-sparse-keymap)))
270 (define-key map "\C-m" 'fuel-help)
271 (define-key map "q" 'bury-buffer)
272 (define-key map "b" 'fuel-help-previous)
273 (define-key map "f" 'fuel-help-next)
274 (define-key map "l" 'fuel-help-previous)
275 (define-key map "p" 'fuel-help-previous)
276 (define-key map "n" 'fuel-help-next)
277 (define-key map (kbd "TAB") 'fuel-help-next-headline)
278 (define-key map (kbd "S-TAB") 'fuel-help-previous-headline)
279 (define-key map [(backtab)] 'fuel-help-previous-headline)
280 (define-key map (kbd "SPC") 'scroll-up)
281 (define-key map (kbd "S-SPC") 'scroll-down)
282 (define-key map "\C-cz" 'run-factor)
283 (define-key map "\C-c\C-z" 'run-factor)
287 ;;; Help mode definition:
289 (defun fuel-help-mode ()
290 "Major mode for browsing Factor documentation.
291 \\{fuel-help-mode-map}"
293 (kill-all-local-variables)
294 (buffer-disable-undo)
295 (use-local-map fuel-help-mode-map)
296 (setq mode-name "Factor Help")
297 (setq major-mode 'fuel-help-mode)
299 (fuel-font-lock--font-lock-setup fuel-help--font-lock-keywords t)
301 (setq fuel-autodoc-mode-string "")
304 (run-mode-hooks 'fuel-help-mode-hook)
305 (setq buffer-read-only t))
309 ;;; fuel-help.el ends here