]> gitweb.factorcode.org Git - factor.git/blob - misc/fuel/fuel-listener.el
Merge branch 'master' into fortran
[factor.git] / misc / fuel / fuel-listener.el
1 ;;; fuel-listener.el --- starting the fuel listener
2
3 ;; Copyright (C) 2008, 2009  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
8
9 ;;; Commentary:
10
11 ;; Utilities to maintain and switch to a factor listener comint
12 ;; buffer, with an accompanying major fuel-listener-mode.
13
14 ;;; Code:
15
16 (require 'fuel-stack)
17 (require 'fuel-completion)
18 (require 'fuel-xref)
19 (require 'fuel-eval)
20 (require 'fuel-connection)
21 (require 'fuel-syntax)
22 (require 'fuel-base)
23
24 (require 'comint)
25
26 \f
27 ;;; Customization:
28
29 (defgroup fuel-listener nil
30   "Interacting with a Factor listener inside Emacs."
31   :group 'fuel)
32
33 (defcustom fuel-listener-factor-binary
34   (expand-file-name (cond ((eq system-type 'windows-nt)
35                            "factor.com")
36                           ((eq system-type 'darwin)
37                            "Factor.app/Contents/MacOS/factor")
38                           (t "factor"))
39                     fuel-factor-root-dir)
40   "Full path to the factor executable to use when starting a listener."
41   :type '(file :must-match t)
42   :group 'fuel-listener)
43
44 (defcustom fuel-listener-factor-image
45   (expand-file-name "factor.image" fuel-factor-root-dir)
46   "Full path to the factor image to use when starting a listener."
47   :type '(file :must-match t)
48   :group 'fuel-listener)
49
50 (defcustom fuel-listener-use-other-window t
51   "Use a window other than the current buffer's when switching to
52 the factor-listener buffer."
53   :type 'boolean
54   :group 'fuel-listener)
55
56 (defcustom fuel-listener-window-allow-split t
57   "Allow window splitting when switching to the fuel listener
58 buffer."
59   :type 'boolean
60   :group 'fuel-listener)
61
62 \f
63 ;;; Fuel listener buffer/process:
64
65 (defvar fuel-listener--buffer nil
66   "The buffer in which the Factor listener is running.")
67
68 (defun fuel-listener--buffer ()
69   (if (buffer-live-p fuel-listener--buffer)
70       fuel-listener--buffer
71     (with-current-buffer (get-buffer-create "*fuel listener*")
72       (fuel-listener-mode)
73       (setq fuel-listener--buffer (current-buffer)))))
74
75 (defun fuel-listener--start-process ()
76   (let ((factor (expand-file-name fuel-listener-factor-binary))
77         (image (expand-file-name fuel-listener-factor-image))
78         (comint-redirect-perform-sanity-check nil))
79     (unless (file-executable-p factor)
80       (error "Could not run factor: %s is not executable" factor))
81     (unless (file-readable-p image)
82       (error "Could not run factor: image file %s not readable" image))
83     (message "Starting FUEL listener (this may take a while) ...")
84     (pop-to-buffer (fuel-listener--buffer))
85     (make-comint-in-buffer "fuel listener" (current-buffer) factor nil
86                            "-run=listener" (format "-i=%s" image))
87     (fuel-listener--wait-for-prompt 10000)
88     (fuel-con--setup-connection (current-buffer))))
89
90 (defun fuel-listener--connect-process (port)
91   (message "Connecting to remote listener ...")
92   (pop-to-buffer (fuel-listener--buffer))
93   (let ((process (get-buffer-process (current-buffer))))
94     (when (or (not process)
95               (y-or-n-p "Kill current listener? "))
96       (make-comint-in-buffer "fuel listener" (current-buffer)
97                              (cons "localhost" port))
98       (fuel-listener--wait-for-prompt 10000)
99       (fuel-con--setup-connection (current-buffer)))))
100
101 (defun fuel-listener--process (&optional start)
102   (or (and (buffer-live-p (fuel-listener--buffer))
103            (get-buffer-process (fuel-listener--buffer)))
104       (if (not start)
105           (error "No running factor listener (try M-x run-factor)")
106         (fuel-listener--start-process)
107         (fuel-listener--process))))
108
109 (setq fuel-eval--default-proc-function 'fuel-listener--process)
110
111 (defun fuel-listener--wait-for-prompt (timeout)
112   (let ((p (point)) (seen))
113     (while (and (not seen) (> timeout 0))
114       (sleep-for 0.1)
115       (setq timeout (- timeout 100))
116       (goto-char p)
117       (setq seen (re-search-forward comint-prompt-regexp nil t)))
118     (goto-char (point-max))
119     (unless seen (error "No prompt found!"))))
120
121
122 \f
123 ;;; Interface: starting and interacting with fuel listener:
124
125 (defalias 'switch-to-factor 'run-factor)
126 (defalias 'switch-to-fuel-listener 'run-factor)
127 ;;;###autoload
128 (defun run-factor (&optional arg)
129   "Show the fuel-listener buffer, starting the process if needed."
130   (interactive)
131   (let ((buf (process-buffer (fuel-listener--process t)))
132         (pop-up-windows fuel-listener-window-allow-split))
133     (if fuel-listener-use-other-window
134         (pop-to-buffer buf)
135       (switch-to-buffer buf))))
136
137 (defun connect-to-factor (&optional arg)
138   "Connects to a remote listener running in the same host.
139 Without prefix argument, the default port, 9000, is used.
140 Otherwise, you'll be prompted for it. To make this work, in the
141 remote listener you need to issue the words
142 'fuel-start-remote-listener*' or 'port
143 fuel-start-remote-listener', from the fuel vocabulary."
144   (interactive "P")
145   (let ((port (if (not arg) 9000 (read-number "Port: "))))
146     (fuel-listener--connect-process port)))
147
148 (defun fuel-listener-nuke ()
149   "Try this command if the listener becomes unresponsive."
150   (interactive)
151   (goto-char (point-max))
152   (comint-kill-region comint-last-input-start (point))
153   (comint-redirect-cleanup)
154   (fuel-con--setup-connection fuel-listener--buffer))
155
156 (defun fuel-refresh-all ()
157   "Switch to the listener buffer and invokes Factor's refresh-all.
158 With prefix, you're teletransported to the listener's buffer."
159   (interactive)
160   (let ((buf (process-buffer (fuel-listener--process))))
161     (pop-to-buffer buf)
162     (comint-send-string nil "\"Refreshing loaded vocabs...\" write nl flush")
163     (comint-send-string nil " refresh-all \"Done!\" write nl flush\n")))
164
165 \f
166 ;;; Completion support
167
168 (defsubst fuel-listener--current-vocab () nil)
169 (defsubst fuel-listener--usings () nil)
170
171 (defun fuel-listener--setup-completion ()
172   (setq fuel-syntax--current-vocab-function 'fuel-listener--current-vocab)
173   (setq fuel-syntax--usings-function 'fuel-listener--usings))
174
175 \f
176 ;;; Stack mode support
177
178 (defun fuel-listener--stack-region ()
179   (fuel--region-to-string (if (zerop (fuel-syntax--brackets-depth))
180                               (comint-line-beginning-position)
181                             (1+ (fuel-syntax--brackets-start)))))
182
183 (defun fuel-listener--setup-stack-mode ()
184   (setq fuel-stack--region-function 'fuel-listener--stack-region))
185
186 \f
187 ;;; Fuel listener mode:
188
189 (defun fuel-listener--bol ()
190   (interactive)
191   (when (= (point) (comint-bol)) (beginning-of-line)))
192
193 ;;;###autoload
194 (define-derived-mode fuel-listener-mode comint-mode "Fuel Listener"
195   "Major mode for interacting with an inferior Factor listener process.
196 \\{fuel-listener-mode-map}"
197   (set (make-local-variable 'comint-prompt-regexp) fuel-con--prompt-regex)
198   (set (make-local-variable 'comint-use-prompt-regexp) t)
199   (set (make-local-variable 'comint-prompt-read-only) t)
200   (fuel-listener--setup-completion)
201   (fuel-listener--setup-stack-mode))
202
203 (define-key fuel-listener-mode-map "\C-cz" 'run-factor)
204 (define-key fuel-listener-mode-map "\C-c\C-z" 'run-factor)
205 (define-key fuel-listener-mode-map "\C-a" 'fuel-listener--bol)
206 (define-key fuel-listener-mode-map "\C-ca" 'fuel-autodoc-mode)
207 (define-key fuel-listener-mode-map "\C-ch" 'fuel-help)
208 (define-key fuel-listener-mode-map "\C-cr" 'fuel-refresh-all)
209 (define-key fuel-listener-mode-map "\C-cs" 'fuel-stack-mode)
210 (define-key fuel-listener-mode-map "\C-cp" 'fuel-apropos)
211 (define-key fuel-listener-mode-map "\M-." 'fuel-edit-word-at-point)
212 (define-key fuel-listener-mode-map "\C-cv" 'fuel-edit-vocabulary)
213 (define-key fuel-listener-mode-map "\C-c\C-v" 'fuel-edit-vocabulary)
214 (define-key fuel-listener-mode-map "\C-ck" 'fuel-run-file)
215 (define-key fuel-listener-mode-map (kbd "TAB") 'fuel-completion--complete-symbol)
216
217 \f
218 (provide 'fuel-listener)
219 ;;; fuel-listener.el ends here