From 70645e0d3a7d9f5ca88ace6a49aa9695610c0846 Mon Sep 17 00:00:00 2001 From: "Jose A. Ortega Ruiz" Date: Sat, 22 Nov 2008 04:22:38 +0100 Subject: [PATCH] Emacs Factor listener: new help mode; better run-factor/switch-to-factor behaviour. --- misc/factor.el | 196 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 162 insertions(+), 34 deletions(-) diff --git a/misc/factor.el b/misc/factor.el index 170da980be..351b0e97d1 100644 --- a/misc/factor.el +++ b/misc/factor.el @@ -35,6 +35,7 @@ (require 'font-lock) (require 'comint) +(require 'view) ;;; Customization: @@ -64,6 +65,30 @@ value from the existing code in the buffer." :type '(file :must-match t) :group 'factor) +(defcustom factor-use-doc-window t + "When on, use a separate window to display help information. +Disable to see that information in the factor-listener comint +window." + :type 'boolean + :group 'factor) + +(defcustom factor-listener-use-other-window t + "Use a window other than the current buffer's when switching to +the factor-listener buffer." + :type 'boolean + :group 'factor) + +(defcustom factor-listener-window-allow-split t + "Allow window splitting when switching to the factor-listener +buffer." + :type 'boolean + :group 'factor) + +(defcustom factor-help-always-ask t + "When enabled, always ask for confirmation in help prompts." + :type 'boolean + :group 'factor) + (defcustom factor-display-compilation-output t "Display the REPL buffer before compiling files." :type 'boolean @@ -74,6 +99,11 @@ value from the existing code in the buffer." :type 'hook :group 'factor) +(defcustom factor-help-mode-hook nil + "Hook run by `factor-help-mode'." + :type 'hook + :group 'factor) + (defgroup factor-faces nil "Faces used in Factor mode" :group 'factor @@ -125,6 +155,10 @@ value from the existing code in the buffer." "Face for parsing words." :group 'factor-faces) +(defface factor-font-lock-help-mode-headlines '((t (:bold t :weight bold))) + "Face for headlines in help buffers." + :group 'factor-faces) + ;;; Factor mode font lock: @@ -429,18 +463,6 @@ value from the existing code in the buffer." (factor-send-region (search-backward ":") (search-forward ";"))) -(defun factor-see () - (interactive) - (comint-send-string "*factor*" "\\ ") - (comint-send-string "*factor*" (thing-at-point 'sexp)) - (comint-send-string "*factor*" " see\n")) - -(defun factor-help () - (interactive) - (comint-send-string "*factor*" "\\ ") - (comint-send-string "*factor*" (thing-at-point 'sexp)) - (comint-send-string "*factor*" " help\n")) - (defun factor-edit () (interactive) (comint-send-string "*factor*" "\\ ") @@ -459,17 +481,6 @@ value from the existing code in the buffer." (defvar factor-mode-map (make-sparse-keymap) "Key map used by Factor mode.") -(define-key factor-mode-map "\C-c\C-f" 'factor-run-file) -(define-key factor-mode-map "\C-c\C-r" 'factor-send-region) -(define-key factor-mode-map "\C-c\C-d" 'factor-send-definition) -(define-key factor-mode-map "\C-c\C-s" 'factor-see) -(define-key factor-mode-map "\C-ce" 'factor-edit) -(define-key factor-mode-map "\C-c\C-h" 'factor-help) -(define-key factor-mode-map "\C-cc" 'comment-region) -(define-key factor-mode-map [return] 'newline-and-indent) -(define-key factor-mode-map [tab] 'indent-for-tab-command) - - ;; Factor mode: @@ -494,23 +505,118 @@ value from the existing code in the buffer." (add-to-list 'auto-mode-alist '("\\.factor\\'" . factor-mode)) -;;; Factor listener mode +;;; Factor listener mode: ;;;###autoload -(define-derived-mode factor-listener-mode comint-mode "Factor Listener") +(define-derived-mode factor-listener-mode comint-mode "Factor Listener" + "Major mode for interacting with an inferior Factor listener process. +\\{factor-listener-mode-map}" + (set (make-local-variable 'comint-prompt-regexp) "^( [^)]+ ) ")) -(define-key factor-listener-mode-map [f8] 'factor-refresh-all) +(defvar factor--listener-buffer nil + "The buffer in which the Factor listener is running.") + +(defun factor--listener-start-process () + "Start an inferior Factor listener process, using +`factor-binary' and `factor-image'." + (setq factor--listener-buffer + (apply 'make-comint "factor" (expand-file-name factor-binary) nil + `("-run=listener" ,(format "-i=%s" (expand-file-name factor-image))))) + (with-current-buffer factor--listener-buffer + (factor-listener-mode))) + +(defun factor--listener-process () + (or (and (buffer-live-p factor--listener-buffer) + (get-buffer-process factor--listener-buffer)) + (progn (factor--listener-start-process) + (factor--listener-process)))) ;;;###autoload -(defun run-factor () - "Start a factor listener inside emacs, or switch to it if it -already exists." +(defalias 'switch-to-factor 'run-factor) +;;;###autoload +(defun run-factor (&optional arg) + "Show the factor-listener buffer, starting the process if needed." (interactive) - (switch-to-buffer - (make-comint-in-buffer "factor" nil (expand-file-name factor-binary) nil - (concat "-i=" (expand-file-name factor-image)) - "-run=listener")) - (factor-listener-mode)) + (let ((buf (process-buffer (factor--listener-process))) + (pop-up-windows factor-listener-window-allow-split)) + (if factor-listener-use-other-window + (pop-to-buffer buf) + (switch-to-buffer buf)))) + + +;;;; Factor help mode: + +(defvar factor-help-mode-map (make-sparse-keymap) + "Keymap for Factor help mode.") + +(defconst factor--help-headlines + (regexp-opt '("Parent topics:" + "Inputs and outputs" + "Word description" + "Generic word contract" + "Vocabulary" + "Definition") + t)) + +(defconst factor--help-headlines-regexp (format "^%s" factor--help-headlines)) + +(defconst factor--help-font-lock-keywords + `((,factor--help-headlines-regexp . 'factor-font-lock-help-mode-headlines) + ,@factor-font-lock-keywords)) + +(defun factor-help-mode () + "Major mode for displaying Factor help messages. +\\{factor-help-mode-map}" + (interactive) + (kill-all-local-variables) + (use-local-map factor-help-mode-map) + (setq mode-name "Factor Help") + (setq major-mode 'factor-help-mode) + (set (make-local-variable 'font-lock-defaults) + '(factor--help-font-lock-keywords t nil nil nil)) + (set (make-local-variable 'comint-redirect-subvert-readonly) t) + (set (make-local-variable 'view-no-disable-on-exit) t) + (view-mode) + (setq view-exit-action + (lambda (buffer) + ;; Use `with-current-buffer' to make sure that `bury-buffer' + ;; also removes BUFFER from the selected window. + (with-current-buffer buffer + (bury-buffer)))) + (run-mode-hooks 'factor-help-mode-hook)) + +(defun factor--listener-help-buffer () + (set-buffer (get-buffer-create "*factor-help*")) + (let ((inhibit-read-only t)) + (delete-region (point-min) (point-max))) + (factor-help-mode) + (current-buffer)) + +(defvar factor--help-history nil) + +(defun factor--listener-show-help (&optional see) + (let* ((def (thing-at-point 'sexp)) + (prompt (format "%s (%s): " (if see "See" "Help") def)) + (ask (or (not (eq major-mode 'factor-mode)) + (not def) + factor-help-always-ask)) + (cmd (format "\\ %s %s" + (if ask (read-string prompt nil 'factor--help-history def) def) + (if see "see" "help"))) + (hb (factor--listener-help-buffer)) + (proc (factor--listener-process))) + (comint-redirect-send-command-to-process cmd hb proc nil) + (pop-to-buffer hb))) + +(defun factor-see () + (interactive) + (factor--listener-show-help t)) + +(defun factor-help () + (interactive) + (factor--listener-show-help)) + + (defun factor-refresh-all () "Reload source files and documentation for all loaded @@ -519,6 +625,28 @@ vocabularies which have been modified on disk." (comint-send-string "*factor*" "refresh-all\n")) +;;; Key bindings: +(defmacro factor--define-key (key cmd) + `(progn + (define-key factor-mode-map [(control ?c) ,key] ,cmd) + (define-key factor-mode-map [(control ?c) (control ,key)] ,cmd))) + +(factor--define-key ?f 'factor-run-file) +(factor--define-key ?r 'factor-send-region) +(factor--define-key ?d 'factor-send-definition) +(factor--define-key ?s 'factor-see) +(factor--define-key ?e 'factor-edit) +(factor--define-key ?z 'switch-to-factor) +(factor--define-key ?c 'comment-region) + +(define-key factor-mode-map "\C-ch" 'factor-help) +(define-key factor-mode-map "\C-m" 'newline-and-indent) +(define-key factor-mode-map [tab] 'indent-for-tab-command) + +(define-key factor-listener-mode-map [f8] 'factor-refresh-all) + + + (provide 'factor) ;;; factor.el ends here