1 ;;; assistant.el --- guiding users through Emacs setup
2 ;; Copyright (C) 2004 Free Software Foundation, Inc.
4 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
31 (defvar assistant-readers
32 '(("variable" assistant-variable-reader)
33 ("validate" assistant-sexp-reader)
34 ("result" assistant-list-reader)
35 ("next" assistant-list-reader)))
37 ;;; Internal variables
39 (defvar assistant-data nil)
40 (defvar assistant-current-node nil)
42 (defun assistant-parse-buffer ()
43 (let (results command value)
44 (goto-char (point-min))
45 (while (search-forward "@" nil t)
46 (if (not (looking-at "[^ \t\n]+"))
48 (setq command (downcase (match-string 0)))
49 (goto-char (match-end 0)))
51 (if (looking-at "[ \t]*\n")
55 (unless (re-search-forward (concat "^@end " command) nil t)
56 (error "No @end %s found" command))
59 (buffer-substring start (point))
61 (skip-chars-forward " \t")
63 (buffer-substring (point) (line-end-position))
65 (push (list command (assistant-reader command value))
67 (assistant-segment (nreverse results))))
69 ;; Segment the raw assistant data into a list of nodes.
70 (defun assistant-segment (list)
75 (when (and (equal (car elem) "node")
77 (push (nreverse node) ast)
81 (push (nreverse node) ast))
82 (cons title (nreverse ast))))
84 (defun assistant-reader (command value)
85 (let ((formatter (cadr (assoc command assistant-readers))))
88 (funcall formatter value))))
90 (defun assistant-list-reader (value)
91 (car (read-from-string (concat "(" value ")"))))
93 (defun assistant-variable-reader (value)
94 (let ((section (car (read-from-string (concat "(" value ")")))))
95 (append section (list (nth 2 section)))))
97 (defun assistant-sexp-reader (value)
98 (if (zerop (length value))
100 (car (read-from-string value))))
102 (defun assistant-buffer-name (title)
103 (format "*Assistant %s*" title))
105 (defun assistant-get (ast command)
106 (cadr (assoc command ast)))
108 (defun assistant-get-list (ast command)
111 (when (equal (car elem) command)
115 (defun assistant (file)
116 "Assist setting up Emacs based on FILE."
117 (interactive "fAssistant file name: ")
120 (insert-file-contents file)
121 (assistant-parse-buffer))))
122 (pop-to-buffer (assistant-buffer-name (assistant-get ast "title")))
123 (assistant-render ast)))
125 (defun assistant-render (ast)
126 (let ((first-node (assistant-get (nth 1 ast) "node")))
127 (set (make-local-variable 'assistant-data) ast)
128 (set (make-local-variable 'assistant-current-node) first-node)
129 (set (make-local-variable 'assistant-previous-node) nil)
130 (assistant-render-node first-node)))
132 (defun assistant-find-node (node-name)
133 (let ((ast (cdr assistant-data)))
135 (not (string= node-name (assistant-get (car ast) "node"))))
139 (defun assistant-insert-previous-node (node)
140 (insert (format "[ << Go back to %s ] " node)))
142 (defun assistant-insert-next-node (node)
144 (insert (format "[ Proceed to %s >> ]" node))
145 (insert "[ Finish ]")))
147 (defun assistant-render-node (node-name)
148 (let ((node (assistant-find-node node-name)))
149 (setq assistant-current-node node-name)
151 (insert (cadar assistant-data) "\n\n")
152 (insert node-name "\n\n")
153 (insert (assistant-get node "text") "\n\n")
154 (when assistant-previous-node
155 (assistant-insert-previous-node assistant-previous-node))
156 (assistant-insert-next-node (assistant-find-next-node))
159 (defun assistant-find-next-node ()
160 (let* ((node (assistant-find-node node-name))
161 (nexts (assistant-get-list node "next"))
163 (while (and (setq elem (pop nexts))
165 (when (assistant-eval (car elem) node)
166 (setq next (cadr elem))))
169 (defun assistant-eval (form node)
170 (let ((bindings nil))
171 (dolist (variable (assistant-get-list node "variable"))
172 (push (list (car variable) (nth 3 variable))