1 ;;; fuel-listener.el --- starting the fuel listener
3 ;; Copyright (C) 2008, 2009 Jose Antonio Ortega Ruiz
4 ;; See http://factorcode.org/license.txt for BSD license.
6 ;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
11 ;; Utilities to maintain and switch to a factor listener comint
12 ;; buffer, with an accompanying major fuel-listener-mode.
17 (require 'fuel-completion
)
20 (require 'fuel-connection
)
21 (require 'fuel-syntax
)
29 (defgroup fuel-listener nil
30 "Interacting with a Factor listener inside Emacs."
33 (defcustom fuel-listener-factor-binary
34 (expand-file-name (cond ((eq system-type
'windows-nt
)
36 ((eq system-type
'darwin
)
37 "Factor.app/Contents/MacOS/factor")
40 "Full path to the factor executable to use when starting a listener."
41 :type
'(file :must-match t
)
42 :group
'fuel-listener
)
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
)
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."
54 :group
'fuel-listener
)
56 (defcustom fuel-listener-window-allow-split t
57 "Allow window splitting when switching to the fuel listener
60 :group
'fuel-listener
)
63 ;;; Fuel listener buffer/process:
65 (defvar fuel-listener--buffer nil
66 "The buffer in which the Factor listener is running.")
68 (defun fuel-listener--buffer ()
69 (if (buffer-live-p fuel-listener--buffer
)
71 (with-current-buffer (get-buffer-create "*fuel listener*")
73 (setq fuel-listener--buffer
(current-buffer)))))
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))))
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)))))
101 (defun fuel-listener--process (&optional start
)
102 (or (and (buffer-live-p (fuel-listener--buffer))
103 (get-buffer-process (fuel-listener--buffer)))
105 (error "No running factor listener (try M-x run-factor)")
106 (fuel-listener--start-process)
107 (fuel-listener--process))))
109 (setq fuel-eval--default-proc-function
'fuel-listener--process
)
111 (defun fuel-listener--wait-for-prompt (timeout)
112 (let ((p (point)) (seen))
113 (while (and (not seen
) (> timeout
0))
115 (setq timeout
(- timeout
100))
117 (setq seen
(re-search-forward comint-prompt-regexp nil t
)))
118 (goto-char (point-max))
119 (unless seen
(error "No prompt found!"))))
123 ;;; Interface: starting and interacting with fuel listener:
125 (defalias 'switch-to-factor
'run-factor
)
126 (defalias 'switch-to-fuel-listener
'run-factor
)
128 (defun run-factor (&optional arg
)
129 "Show the fuel-listener buffer, starting the process if needed."
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
135 (switch-to-buffer buf
))))
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."
145 (let ((port (if (not arg
) 9000 (read-number "Port: "))))
146 (fuel-listener--connect-process port
)))
148 (defun fuel-listener-nuke ()
149 "Try this command if the listener becomes unresponsive."
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
))
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."
160 (let ((buf (process-buffer (fuel-listener--process))))
162 (comint-send-string nil
"\"Refreshing loaded vocabs...\" write nl flush")
163 (comint-send-string nil
" refresh-all \"Done!\" write nl flush\n")))
166 ;;; Completion support
168 (defsubst fuel-listener--current-vocab
() nil
)
169 (defsubst fuel-listener--usings
() nil
)
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
))
176 ;;; Stack mode support
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)))))
183 (defun fuel-listener--setup-stack-mode ()
184 (setq fuel-stack--region-function
'fuel-listener--stack-region
))
187 ;;; Fuel listener mode:
189 (defun fuel-listener--bol ()
191 (when (= (point) (comint-bol)) (beginning-of-line)))
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))
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
)
218 (provide 'fuel-listener
)
219 ;;; fuel-listener.el ends here