+ (let ((node (assistant-find-node node-name))
+ (inhibit-read-only t)
+ (previous assistant-current-node)
+ (buffer-read-only nil))
+ (unless node
+ (gnus-error 5 "The node for %s could not be found" node-name))
+ (set (make-local-variable 'assistant-widgets) nil)
+ (assistant-set-defaults node)
+ (if (equal (assistant-get node "type") "interstitial")
+ (assistant-render-node (nth 0 (assistant-find-next-nodes node-name)))
+ (setq assistant-current-node node-name)
+ (when previous
+ (push previous assistant-previous-nodes))
+ (erase-buffer)
+ (insert (cadar assistant-data) "\n\n")
+ (insert node-name "\n\n")
+ (assistant-render-text (assistant-get node "text") node)
+ (insert "\n\n")
+ (when assistant-previous-nodes
+ (assistant-node-button 'previous (car assistant-previous-nodes)))
+ (widget-create
+ 'push-button
+ :assistant-node node-name
+ :notify (lambda (widget &rest ignore)
+ (let* ((node (widget-get widget :assistant-node)))
+ (assistant-set-defaults (assistant-find-node node) 'force)
+ (assistant-render-node node)))
+ "Reset")
+ (insert "\n")
+ (dolist (nnode (assistant-find-next-nodes))
+ (assistant-node-button 'next nnode)
+ (insert "\n"))
+
+ (goto-char (point-min))
+ (assistant-make-read-only))))
+
+(defun assistant-make-read-only ()
+ (let ((start (point-min))
+ end)
+ (while (setq end (text-property-any start (point-max) 'not-read-only t))
+ (put-text-property start end 'read-only t)
+ (put-text-property start end 'rear-nonsticky t)
+ (while (get-text-property end 'not-read-only)
+ (incf end))
+ (setq start end))
+ (put-text-property start (point-max) 'read-only t)))
+
+(defun assistant-node-button (type node)
+ (let ((text (if (eq type 'next)
+ (assistant-next-node-text node)
+ (assistant-previous-node-text node))))
+ (widget-create
+ 'push-button
+ :assistant-node node
+ :assistant-type type
+ :notify (lambda (widget &rest ignore)
+ (let* ((node (widget-get widget :assistant-node))
+ (type (widget-get widget :assistant-type)))
+ (if (eq type 'previous)
+ (progn
+ (setq assistant-current-node nil)
+ (pop assistant-previous-nodes))
+ (assistant-get-widget-values)
+ (assistant-validate))
+ (if (null node)
+ (assistant-finish)
+ (assistant-render-node node))))
+ text)
+ (use-local-map widget-keymap)))
+
+(defun assistant-validate-types (node)
+ (dolist (variable (assistant-get-list node "variable"))
+ (setq variable (cadr variable))
+ (let ((type (nth 1 variable))
+ (value (nth 3 variable)))
+ (when
+ (cond
+ ((eq type :number)
+ (string-match "[^0-9]" value))
+ (t
+ nil))
+ (error "%s is not of type %s: %s"
+ (car variable) type value)))))
+
+(defun assistant-get-widget-values ()
+ (let ((node (assistant-find-node assistant-current-node)))
+ (dolist (widget assistant-widgets)
+ (assistant-set-variable
+ node (widget-get widget :assistant-variable)
+ (widget-value widget)))))
+
+(defun assistant-validate ()
+ (let* ((node (assistant-find-node assistant-current-node))
+ (validation (assistant-get node "validate"))
+ result)
+ (assistant-validate-types node)
+ (when validation
+ (when (setq result (assistant-eval validation))
+ (unless (y-or-n-p (format "Error: %s. Continue? " result))
+ (error "%s" result))))
+ (assistant-set node "save" t)))
+
+;; (defun assistant-find-next-node (&optional node)
+;; (let* ((node (assistant-find-node (or node assistant-current-node)))
+;; (node-name (assistant-node-name node))
+;; (nexts (assistant-get-list node "next"))
+;; next elem applicable)
+
+;; (while (setq elem (pop nexts))
+;; (when (assistant-eval (car (cadr elem)))
+;; (setq applicable (cons elem applicable))))
+
+;; ;; return the first thing we can
+;; (cadr (cadr (pop applicable)))))
+
+(defun assistant-find-next-nodes (&optional node)
+ (let* ((node (assistant-find-node (or node assistant-current-node)))