aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorLeo Liu2013-04-25 22:51:08 +0800
committerLeo Liu2013-04-25 22:51:08 +0800
commitbe64c05d81d6191397fa96e050b8b3ad8134b62b (patch)
tree1b12d49580def0407fc08735fabf3bad0a4b5c71 /lisp
parentd79d37bd136542193dc61ac2e0163245058c4a13 (diff)
downloademacs-be64c05d81d6191397fa96e050b8b3ad8134b62b.tar.gz
emacs-be64c05d81d6191397fa96e050b8b3ad8134b62b.zip
Merge octave-mod.el and octave-inf.el into octave.el with some
cleanups. * progmodes/octave.el: New file renamed from octave-mod.el. * progmodes/octave-inf.el: Merged into octave.el. * progmodes/octave-mod.el: Renamed to octave.el.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog8
-rw-r--r--lisp/progmodes/octave-inf.el387
-rw-r--r--lisp/progmodes/octave.el (renamed from lisp/progmodes/octave-mod.el)392
3 files changed, 371 insertions, 416 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index e8933ee7c83..c3a97b7003e 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,11 @@
12013-04-25 Leo Liu <sdl.web@gmail.com>
2
3 Merge octave-mod.el and octave-inf.el into octave.el with some
4 cleanups.
5 * progmodes/octave.el: New file renamed from octave-mod.el.
6 * progmodes/octave-inf.el: Merged into octave.el.
7 * progmodes/octave-mod.el: Renamed to octave.el.
8
12013-04-25 Tassilo Horn <tsdh@gnu.org> 92013-04-25 Tassilo Horn <tsdh@gnu.org>
2 10
3 * textmodes/reftex-vars.el 11 * textmodes/reftex-vars.el
diff --git a/lisp/progmodes/octave-inf.el b/lisp/progmodes/octave-inf.el
deleted file mode 100644
index 4a227db7164..00000000000
--- a/lisp/progmodes/octave-inf.el
+++ /dev/null
@@ -1,387 +0,0 @@
1;;; octave-inf.el --- running Octave as an inferior Emacs process
2
3;; Copyright (C) 1997, 2001-2013 Free Software Foundation, Inc.
4
5;; Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
6;; John Eaton <jwe@bevo.che.wisc.edu>
7;; Maintainer: FSF
8;; Keywords: languages
9;; Package: octave-mod
10
11;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software: you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
25
26;;; Commentary:
27
28;;; Code:
29
30(require 'octave-mod)
31(require 'comint)
32
33(defgroup octave-inferior nil
34 "Running Octave as an inferior Emacs process."
35 :group 'octave)
36
37(defcustom inferior-octave-program "octave"
38 "Program invoked by `inferior-octave'."
39 :type 'string
40 :group 'octave-inferior)
41
42(defcustom inferior-octave-prompt
43 "\\(^octave\\(\\|.bin\\|.exe\\)\\(-[.0-9]+\\)?\\(:[0-9]+\\)?\\|^debug\\|^\\)>+ "
44 "Regexp to match prompts for the inferior Octave process."
45 :type 'regexp
46 :group 'octave-inferior)
47
48(defcustom inferior-octave-startup-file nil
49 "Name of the inferior Octave startup file.
50The contents of this file are sent to the inferior Octave process on
51startup."
52 :type '(choice (const :tag "None" nil)
53 file)
54 :group 'octave-inferior)
55
56(defcustom inferior-octave-startup-args nil
57 "List of command line arguments for the inferior Octave process.
58For example, for suppressing the startup message and using `traditional'
59mode, set this to (\"-q\" \"--traditional\")."
60 :type '(repeat string)
61 :group 'octave-inferior)
62
63(defvar inferior-octave-mode-map
64 (let ((map (make-sparse-keymap)))
65 (set-keymap-parent map comint-mode-map)
66 (define-key map "\t" 'comint-dynamic-complete)
67 (define-key map "\M-?" 'comint-dynamic-list-filename-completions)
68 (define-key map "\C-c\C-l" 'inferior-octave-dynamic-list-input-ring)
69 (define-key map [menu-bar inout list-history]
70 '("List Input History" . inferior-octave-dynamic-list-input-ring))
71 ;; FIXME: free C-h so it can do the describe-prefix-bindings.
72 (define-key map "\C-c\C-h" 'info-lookup-symbol)
73 map)
74 "Keymap used in Inferior Octave mode.")
75
76(defvar inferior-octave-mode-syntax-table
77 (let ((table (make-syntax-table octave-mode-syntax-table)))
78 table)
79 "Syntax table in use in inferior-octave-mode buffers.")
80
81(defcustom inferior-octave-mode-hook nil
82 "Hook to be run when Inferior Octave mode is started."
83 :type 'hook
84 :group 'octave-inferior)
85
86(defvar inferior-octave-font-lock-keywords
87 (list
88 (cons inferior-octave-prompt 'font-lock-type-face))
89 ;; Could certainly do more font locking in inferior Octave ...
90 "Additional expressions to highlight in Inferior Octave mode.")
91
92
93;;; Compatibility functions
94(if (not (fboundp 'comint-line-beginning-position))
95 ;; comint-line-beginning-position is defined in Emacs 21
96 (defun comint-line-beginning-position ()
97 "Returns the buffer position of the beginning of the line, after any prompt.
98The prompt is assumed to be any text at the beginning of the line matching
99the regular expression `comint-prompt-regexp', a buffer local variable."
100 (save-excursion (comint-bol nil) (point))))
101
102
103(defvar inferior-octave-output-list nil)
104(defvar inferior-octave-output-string nil)
105(defvar inferior-octave-receive-in-progress nil)
106
107(defvar inferior-octave-startup-hook nil)
108
109(defvar inferior-octave-complete-impossible nil
110 "Non-nil means that `inferior-octave-complete' is impossible.")
111
112(defvar inferior-octave-has-built-in-variables nil
113 "Non-nil means that Octave has built-in variables.")
114
115(defvar inferior-octave-dynamic-complete-functions
116 '(inferior-octave-completion-at-point comint-filename-completion)
117 "List of functions called to perform completion for inferior Octave.
118This variable is used to initialize `comint-dynamic-complete-functions'
119in the Inferior Octave buffer.")
120
121(defvar info-lookup-mode)
122
123(define-derived-mode inferior-octave-mode comint-mode "Inferior Octave"
124 "Major mode for interacting with an inferior Octave process.
125Runs Octave as a subprocess of Emacs, with Octave I/O through an Emacs
126buffer.
127
128Entry to this mode successively runs the hooks `comint-mode-hook' and
129`inferior-octave-mode-hook'."
130 (setq comint-prompt-regexp inferior-octave-prompt
131 mode-line-process '(":%s")
132 local-abbrev-table octave-abbrev-table)
133
134 (set (make-local-variable 'comment-start) octave-comment-start)
135 (set (make-local-variable 'comment-end) "")
136 (set (make-local-variable 'comment-column) 32)
137 (set (make-local-variable 'comment-start-skip) octave-comment-start-skip)
138
139 (set (make-local-variable 'font-lock-defaults)
140 '(inferior-octave-font-lock-keywords nil nil))
141
142 (set (make-local-variable 'info-lookup-mode) 'octave-mode)
143
144 (setq comint-input-ring-file-name
145 (or (getenv "OCTAVE_HISTFILE") "~/.octave_hist")
146 comint-input-ring-size (or (getenv "OCTAVE_HISTSIZE") 1024))
147 (set (make-local-variable 'comint-dynamic-complete-functions)
148 inferior-octave-dynamic-complete-functions)
149 (add-hook 'comint-input-filter-functions
150 'inferior-octave-directory-tracker nil t)
151 (comint-read-input-ring t))
152
153;;;###autoload
154(defun inferior-octave (&optional arg)
155 "Run an inferior Octave process, I/O via `inferior-octave-buffer'.
156This buffer is put in Inferior Octave mode. See `inferior-octave-mode'.
157
158Unless ARG is non-nil, switches to this buffer.
159
160The elements of the list `inferior-octave-startup-args' are sent as
161command line arguments to the inferior Octave process on startup.
162
163Additional commands to be executed on startup can be provided either in
164the file specified by `inferior-octave-startup-file' or by the default
165startup file, `~/.emacs-octave'."
166 (interactive "P")
167 (let ((buffer inferior-octave-buffer))
168 (get-buffer-create buffer)
169 (if (comint-check-proc buffer)
170 ()
171 (with-current-buffer buffer
172 (comint-mode)
173 (inferior-octave-startup)
174 (inferior-octave-mode)))
175 (if (not arg)
176 (pop-to-buffer buffer))))
177
178;;;###autoload
179(defalias 'run-octave 'inferior-octave)
180
181(defun inferior-octave-startup ()
182 "Start an inferior Octave process."
183 (let ((proc (comint-exec-1
184 (substring inferior-octave-buffer 1 -1)
185 inferior-octave-buffer
186 inferior-octave-program
187 (append (list "-i" "--no-line-editing")
188 inferior-octave-startup-args))))
189 (set-process-filter proc 'inferior-octave-output-digest)
190 (setq comint-ptyp process-connection-type
191 inferior-octave-process proc
192 inferior-octave-output-list nil
193 inferior-octave-output-string nil
194 inferior-octave-receive-in-progress t)
195
196 ;; This may look complicated ... However, we need to make sure that
197 ;; we additional startup code only AFTER Octave is ready (otherwise,
198 ;; output may be mixed up). Hence, we need to digest the Octave
199 ;; output to see when it issues a prompt.
200 (while inferior-octave-receive-in-progress
201 (accept-process-output inferior-octave-process))
202 (goto-char (point-max))
203 (set-marker (process-mark proc) (point))
204 (insert-before-markers
205 (concat
206 (if (not (bobp)) " \n")
207 (if inferior-octave-output-list
208 (concat (mapconcat
209 'identity inferior-octave-output-list "\n")
210 "\n"))))
211
212 ;; Find out whether Octave has built-in variables.
213 (inferior-octave-send-list-and-digest
214 (list "exist \"LOADPATH\"\n"))
215 (setq inferior-octave-has-built-in-variables
216 (string-match "101$" (car inferior-octave-output-list)))
217
218 ;; An empty secondary prompt, as e.g. obtained by '--braindead',
219 ;; means trouble.
220 (inferior-octave-send-list-and-digest (list "PS2\n"))
221 (if (string-match "\\(PS2\\|ans\\) = *$" (car inferior-octave-output-list))
222 (inferior-octave-send-list-and-digest
223 (list (if inferior-octave-has-built-in-variables
224 "PS2 = \"> \"\n"
225 "PS2 (\"> \");\n"))))
226
227 ;; O.k., now we are ready for the Inferior Octave startup commands.
228 (let* (commands
229 (program (file-name-nondirectory inferior-octave-program))
230 (file (or inferior-octave-startup-file
231 (concat "~/.emacs-" program))))
232 (setq commands
233 (list "more off;\n"
234 (if (not (string-equal
235 inferior-octave-output-string ">> "))
236 (if inferior-octave-has-built-in-variables
237 "PS1=\"\\\\s> \";\n"
238 "PS1 (\"\\\\s> \");\n"))
239 (if (file-exists-p file)
240 (format "source (\"%s\");\n" file))))
241 (inferior-octave-send-list-and-digest commands))
242 (insert-before-markers
243 (concat
244 (if inferior-octave-output-list
245 (concat (mapconcat
246 'identity inferior-octave-output-list "\n")
247 "\n"))
248 inferior-octave-output-string))
249 ;; Next, we check whether Octave supports `completion_matches' ...
250 (inferior-octave-send-list-and-digest
251 (list "exist \"completion_matches\"\n"))
252 (setq inferior-octave-complete-impossible
253 (not (string-match "5$" (car inferior-octave-output-list))))
254
255 ;; And finally, everything is back to normal.
256 (set-process-filter proc 'inferior-octave-output-filter)
257 (run-hooks 'inferior-octave-startup-hook)
258 (run-hooks 'inferior-octave-startup-hook)
259 ;; Just in case, to be sure a cd in the startup file
260 ;; won't have detrimental effects.
261 (inferior-octave-resync-dirs)))
262
263
264(defun inferior-octave-completion-at-point ()
265 "Return the data to complete the Octave symbol at point."
266 (let* ((end (point))
267 (start
268 (save-excursion
269 (skip-syntax-backward "w_" (comint-line-beginning-position))
270 (point))))
271 (cond ((eq start end) nil)
272 (inferior-octave-complete-impossible
273 (message (concat
274 "Your Octave does not have `completion_matches'. "
275 "Please upgrade to version 2.X."))
276 nil)
277 (t
278 (list
279 start end
280 (completion-table-dynamic
281 (lambda (command)
282 (inferior-octave-send-list-and-digest
283 (list (concat "completion_matches (\"" command "\");\n")))
284 (sort (delete-dups inferior-octave-output-list)
285 'string-lessp))))))))
286
287(define-obsolete-function-alias 'inferior-octave-complete
288 'completion-at-point "24.1")
289
290(defun inferior-octave-dynamic-list-input-ring ()
291 "List the buffer's input history in a help buffer."
292 ;; We cannot use `comint-dynamic-list-input-ring', because it replaces
293 ;; "completion" by "history reference" ...
294 (interactive)
295 (if (or (not (ring-p comint-input-ring))
296 (ring-empty-p comint-input-ring))
297 (message "No history")
298 (let ((history nil)
299 (history-buffer " *Input History*")
300 (index (1- (ring-length comint-input-ring)))
301 (conf (current-window-configuration)))
302 ;; We have to build up a list ourselves from the ring vector.
303 (while (>= index 0)
304 (setq history (cons (ring-ref comint-input-ring index) history)
305 index (1- index)))
306 ;; Change "completion" to "history reference"
307 ;; to make the display accurate.
308 (with-output-to-temp-buffer history-buffer
309 (display-completion-list history)
310 (set-buffer history-buffer))
311 (message "Hit space to flush")
312 (let ((ch (read-event)))
313 (if (eq ch ?\ )
314 (set-window-configuration conf)
315 (setq unread-command-events (list ch)))))))
316
317(defun inferior-octave-strip-ctrl-g (string)
318 "Strip leading `^G' character.
319If STRING starts with a `^G', ring the bell and strip it."
320 (if (string-match "^\a" string)
321 (progn
322 (ding)
323 (setq string (substring string 1))))
324 string)
325
326(defun inferior-octave-output-filter (proc string)
327 "Standard output filter for the inferior Octave process.
328Ring Emacs bell if process output starts with an ASCII bell, and pass
329the rest to `comint-output-filter'."
330 (comint-output-filter proc (inferior-octave-strip-ctrl-g string)))
331
332(defun inferior-octave-output-digest (_proc string)
333 "Special output filter for the inferior Octave process.
334Save all output between newlines into `inferior-octave-output-list', and
335the rest to `inferior-octave-output-string'."
336 (setq string (concat inferior-octave-output-string string))
337 (while (string-match "\n" string)
338 (setq inferior-octave-output-list
339 (append inferior-octave-output-list
340 (list (substring string 0 (match-beginning 0))))
341 string (substring string (match-end 0))))
342 (if (string-match inferior-octave-prompt string)
343 (setq inferior-octave-receive-in-progress nil))
344 (setq inferior-octave-output-string string))
345
346(defun inferior-octave-send-list-and-digest (list)
347 "Send LIST to the inferior Octave process and digest the output.
348The elements of LIST have to be strings and are sent one by one. All
349output is passed to the filter `inferior-octave-output-digest'."
350 (let* ((proc inferior-octave-process)
351 string)
352 (add-function :override (process-filter proc)
353 #'inferior-octave-output-digest)
354 (setq inferior-octave-output-list nil)
355 (unwind-protect
356 (while (setq string (car list))
357 (setq inferior-octave-output-string nil
358 inferior-octave-receive-in-progress t)
359 (comint-send-string proc string)
360 (while inferior-octave-receive-in-progress
361 (accept-process-output proc))
362 (setq list (cdr list)))
363 (remove-function (process-filter proc)
364 #'inferior-octave-output-digest))))
365
366(defun inferior-octave-directory-tracker (string)
367 "Tracks `cd' commands issued to the inferior Octave process.
368Use \\[inferior-octave-resync-dirs] to resync if Emacs gets confused."
369 (cond
370 ((string-match "^[ \t]*cd[ \t;]*$" string)
371 (cd "~"))
372 ((string-match "^[ \t]*cd[ \t]+\\([^ \t\n;]*\\)[ \t\n;]*" string)
373 (cd (substring string (match-beginning 1) (match-end 1))))))
374
375(defun inferior-octave-resync-dirs ()
376 "Resync the buffer's idea of the current directory.
377This command queries the inferior Octave process about its current
378directory and makes this the current buffer's default directory."
379 (interactive)
380 (inferior-octave-send-list-and-digest '("disp (pwd ())\n"))
381 (cd (car inferior-octave-output-list)))
382
383;;; provide ourself
384
385(provide 'octave-inf)
386
387;;; octave-inf.el ends here
diff --git a/lisp/progmodes/octave-mod.el b/lisp/progmodes/octave.el
index d161754cad9..c652822bf47 100644
--- a/lisp/progmodes/octave-mod.el
+++ b/lisp/progmodes/octave.el
@@ -1,4 +1,4 @@
1;;; octave-mod.el --- editing Octave source files under Emacs 1;;; octave.el --- editing octave source files under emacs
2 2
3;; Copyright (C) 1997, 2001-2013 Free Software Foundation, Inc. 3;; Copyright (C) 1997, 2001-2013 Free Software Foundation, Inc.
4 4
@@ -24,30 +24,21 @@
24 24
25;;; Commentary: 25;;; Commentary:
26 26
27;; This package provides Emacs support for Octave. 27;; This package provides emacs support for octave. It defines a major
28;; It defines Octave mode, a major mode for editing 28;; mode for editing octave code and contains code for interacting with
29;; Octave code. 29;; an inferior octave process using comint.
30 30
31;; The file octave-inf.el contains code for interacting with an inferior 31;; See the documentation of `octave-mode' and `run-octave' for further
32;; Octave process using comint. 32;; information on usage and customization.
33
34;; See the documentation of `octave-mode' and
35;; `run-octave' for further information on usage and customization.
36 33
37;;; Code: 34;;; Code:
38(require 'custom) 35(require 'comint)
39 36
40(defgroup octave nil 37(defgroup octave nil
41 "Major mode for editing Octave source files." 38 "Editing Octave code."
42 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) 39 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
43 :group 'languages) 40 :group 'languages)
44 41
45(defvar inferior-octave-output-list nil)
46(defvar inferior-octave-output-string nil)
47(defvar inferior-octave-receive-in-progress nil)
48
49(declare-function inferior-octave-send-list-and-digest "octave-inf" (list))
50
51(defconst octave-maintainer-address 42(defconst octave-maintainer-address
52 "Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>, bug-gnu-emacs@gnu.org" 43 "Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>, bug-gnu-emacs@gnu.org"
53 "Current maintainer of the Emacs Octave package.") 44 "Current maintainer of the Emacs Octave package.")
@@ -84,7 +75,7 @@
84 ("`upc" "unwind_protect_cleanup") 75 ("`upc" "unwind_protect_cleanup")
85 ("`w" "while ()"))) 76 ("`w" "while ()")))
86 "Abbrev table for Octave's reserved words. 77 "Abbrev table for Octave's reserved words.
87Used in `octave-mode' and inferior-octave-mode buffers. 78Used in `octave-mode' and `inferior-octave-mode' buffers.
88All Octave abbrevs start with a grave accent (`)." 79All Octave abbrevs start with a grave accent (`)."
89 :regexp "\\(?:[^`]\\|^\\)\\(\\(?:\\<\\|`\\)\\w+\\)\\W*") 80 :regexp "\\(?:[^`]\\|^\\)\\(\\(?:\\<\\|`\\)\\w+\\)\\W*")
90 81
@@ -156,6 +147,7 @@ All Octave abbrevs start with a grave accent (`)."
156The string `function' and its name are given by the first and third 147The string `function' and its name are given by the first and third
157parenthetical grouping.") 148parenthetical grouping.")
158 149
150
159(defvar octave-font-lock-keywords 151(defvar octave-font-lock-keywords
160 (list 152 (list
161 ;; Fontify all builtin keywords. 153 ;; Fontify all builtin keywords.
@@ -201,12 +193,6 @@ parenthetical grouping.")
201 (put-text-property (match-beginning 1) (match-end 1) 193 (put-text-property (match-beginning 1) (match-end 1)
202 'syntax-table (string-to-syntax "\"'"))))) 194 'syntax-table (string-to-syntax "\"'")))))
203 195
204(defcustom inferior-octave-buffer "*Inferior Octave*"
205 "Name of buffer for running an inferior Octave process."
206 :type 'string
207 :group 'octave-inferior)
208
209(defvar inferior-octave-process nil)
210 196
211(defvar octave-mode-map 197(defvar octave-mode-map
212 (let ((map (make-sparse-keymap))) 198 (let ((map (make-sparse-keymap)))
@@ -655,6 +641,357 @@ including a reproducible test case and send the message."
655 641
656 (easy-menu-add octave-mode-menu) 642 (easy-menu-add octave-mode-menu)
657 (octave-initialize-completions)) 643 (octave-initialize-completions))
644
645
646(defcustom inferior-octave-program "octave"
647 "Program invoked by `inferior-octave'."
648 :type 'string
649 :group 'octave)
650
651(defcustom inferior-octave-buffer "*Inferior Octave*"
652 "Name of buffer for running an inferior Octave process."
653 :type 'string
654 :group 'octave)
655
656(defcustom inferior-octave-prompt
657 "\\(^octave\\(\\|.bin\\|.exe\\)\\(-[.0-9]+\\)?\\(:[0-9]+\\)?\\|^debug\\|^\\)>+ "
658 "Regexp to match prompts for the inferior Octave process."
659 :type 'regexp
660 :group 'octave)
661
662(defcustom inferior-octave-startup-file nil
663 "Name of the inferior Octave startup file.
664The contents of this file are sent to the inferior Octave process on
665startup."
666 :type '(choice (const :tag "None" nil)
667 file)
668 :group 'octave)
669
670(defcustom inferior-octave-startup-args nil
671 "List of command line arguments for the inferior Octave process.
672For example, for suppressing the startup message and using `traditional'
673mode, set this to (\"-q\" \"--traditional\")."
674 :type '(repeat string)
675 :group 'octave)
676
677(defcustom inferior-octave-mode-hook nil
678 "Hook to be run when Inferior Octave mode is started."
679 :type 'hook
680 :group 'octave)
681
682(defvar inferior-octave-process nil)
683
684(defvar inferior-octave-mode-map
685 (let ((map (make-sparse-keymap)))
686 (set-keymap-parent map comint-mode-map)
687 (define-key map "\t" 'comint-dynamic-complete)
688 (define-key map "\M-?" 'comint-dynamic-list-filename-completions)
689 (define-key map "\C-c\C-l" 'inferior-octave-dynamic-list-input-ring)
690 (define-key map [menu-bar inout list-history]
691 '("List Input History" . inferior-octave-dynamic-list-input-ring))
692 map)
693 "Keymap used in Inferior Octave mode.")
694
695(defvar inferior-octave-mode-syntax-table
696 (let ((table (make-syntax-table octave-mode-syntax-table)))
697 table)
698 "Syntax table in use in inferior-octave-mode buffers.")
699
700(defvar inferior-octave-font-lock-keywords
701 (list
702 (cons inferior-octave-prompt 'font-lock-type-face))
703 ;; Could certainly do more font locking in inferior Octave ...
704 "Additional expressions to highlight in Inferior Octave mode.")
705
706
707;;; Compatibility functions
708(if (not (fboundp 'comint-line-beginning-position))
709 ;; comint-line-beginning-position is defined in Emacs 21
710 (defun comint-line-beginning-position ()
711 "Returns the buffer position of the beginning of the line, after any prompt.
712The prompt is assumed to be any text at the beginning of the line matching
713the regular expression `comint-prompt-regexp', a buffer local variable."
714 (save-excursion (comint-bol nil) (point))))
715
716
717(defvar inferior-octave-output-list nil)
718(defvar inferior-octave-output-string nil)
719(defvar inferior-octave-receive-in-progress nil)
720
721(defvar inferior-octave-startup-hook nil)
722
723(defvar inferior-octave-complete-impossible nil
724 "Non-nil means that `inferior-octave-complete' is impossible.")
725
726(defvar inferior-octave-has-built-in-variables nil
727 "Non-nil means that Octave has built-in variables.")
728
729(defvar inferior-octave-dynamic-complete-functions
730 '(inferior-octave-completion-at-point comint-filename-completion)
731 "List of functions called to perform completion for inferior Octave.
732This variable is used to initialize `comint-dynamic-complete-functions'
733in the Inferior Octave buffer.")
734
735(defvar info-lookup-mode)
736
737(define-derived-mode inferior-octave-mode comint-mode "Inferior Octave"
738 "Major mode for interacting with an inferior Octave process.
739Runs Octave as a subprocess of Emacs, with Octave I/O through an Emacs
740buffer.
741
742Entry to this mode successively runs the hooks `comint-mode-hook' and
743`inferior-octave-mode-hook'."
744 (setq comint-prompt-regexp inferior-octave-prompt
745 mode-line-process '(":%s")
746 local-abbrev-table octave-abbrev-table)
747
748 (set (make-local-variable 'comment-start) octave-comment-start)
749 (set (make-local-variable 'comment-end) "")
750 (set (make-local-variable 'comment-column) 32)
751 (set (make-local-variable 'comment-start-skip) octave-comment-start-skip)
752
753 (set (make-local-variable 'font-lock-defaults)
754 '(inferior-octave-font-lock-keywords nil nil))
755
756 (set (make-local-variable 'info-lookup-mode) 'octave-mode)
757
758 (setq comint-input-ring-file-name
759 (or (getenv "OCTAVE_HISTFILE") "~/.octave_hist")
760 comint-input-ring-size (or (getenv "OCTAVE_HISTSIZE") 1024))
761 (set (make-local-variable 'comint-dynamic-complete-functions)
762 inferior-octave-dynamic-complete-functions)
763 (add-hook 'comint-input-filter-functions
764 'inferior-octave-directory-tracker nil t)
765 (comint-read-input-ring t))
766
767;;;###autoload
768(defun inferior-octave (&optional arg)
769 "Run an inferior Octave process, I/O via `inferior-octave-buffer'.
770This buffer is put in Inferior Octave mode. See `inferior-octave-mode'.
771
772Unless ARG is non-nil, switches to this buffer.
773
774The elements of the list `inferior-octave-startup-args' are sent as
775command line arguments to the inferior Octave process on startup.
776
777Additional commands to be executed on startup can be provided either in
778the file specified by `inferior-octave-startup-file' or by the default
779startup file, `~/.emacs-octave'."
780 (interactive "P")
781 (let ((buffer inferior-octave-buffer))
782 (get-buffer-create buffer)
783 (if (comint-check-proc buffer)
784 ()
785 (with-current-buffer buffer
786 (comint-mode)
787 (inferior-octave-startup)
788 (inferior-octave-mode)))
789 (if (not arg)
790 (pop-to-buffer buffer))))
791
792;;;###autoload
793(defalias 'run-octave 'inferior-octave)
794
795(defun inferior-octave-startup ()
796 "Start an inferior Octave process."
797 (let ((proc (comint-exec-1
798 (substring inferior-octave-buffer 1 -1)
799 inferior-octave-buffer
800 inferior-octave-program
801 (append (list "-i" "--no-line-editing")
802 inferior-octave-startup-args))))
803 (set-process-filter proc 'inferior-octave-output-digest)
804 (setq comint-ptyp process-connection-type
805 inferior-octave-process proc
806 inferior-octave-output-list nil
807 inferior-octave-output-string nil
808 inferior-octave-receive-in-progress t)
809
810 ;; This may look complicated ... However, we need to make sure that
811 ;; we additional startup code only AFTER Octave is ready (otherwise,
812 ;; output may be mixed up). Hence, we need to digest the Octave
813 ;; output to see when it issues a prompt.
814 (while inferior-octave-receive-in-progress
815 (accept-process-output inferior-octave-process))
816 (goto-char (point-max))
817 (set-marker (process-mark proc) (point))
818 (insert-before-markers
819 (concat
820 (if (not (bobp)) " \n")
821 (if inferior-octave-output-list
822 (concat (mapconcat
823 'identity inferior-octave-output-list "\n")
824 "\n"))))
825
826 ;; Find out whether Octave has built-in variables.
827 (inferior-octave-send-list-and-digest
828 (list "exist \"LOADPATH\"\n"))
829 (setq inferior-octave-has-built-in-variables
830 (string-match "101$" (car inferior-octave-output-list)))
831
832 ;; An empty secondary prompt, as e.g. obtained by '--braindead',
833 ;; means trouble.
834 (inferior-octave-send-list-and-digest (list "PS2\n"))
835 (if (string-match "\\(PS2\\|ans\\) = *$" (car inferior-octave-output-list))
836 (inferior-octave-send-list-and-digest
837 (list (if inferior-octave-has-built-in-variables
838 "PS2 = \"> \"\n"
839 "PS2 (\"> \");\n"))))
840
841 ;; O.k., now we are ready for the Inferior Octave startup commands.
842 (let* (commands
843 (program (file-name-nondirectory inferior-octave-program))
844 (file (or inferior-octave-startup-file
845 (concat "~/.emacs-" program))))
846 (setq commands
847 (list "more off;\n"
848 (if (not (string-equal
849 inferior-octave-output-string ">> "))
850 (if inferior-octave-has-built-in-variables
851 "PS1=\"\\\\s> \";\n"
852 "PS1 (\"\\\\s> \");\n"))
853 (if (file-exists-p file)
854 (format "source (\"%s\");\n" file))))
855 (inferior-octave-send-list-and-digest commands))
856 (insert-before-markers
857 (concat
858 (if inferior-octave-output-list
859 (concat (mapconcat
860 'identity inferior-octave-output-list "\n")
861 "\n"))
862 inferior-octave-output-string))
863 ;; Next, we check whether Octave supports `completion_matches' ...
864 (inferior-octave-send-list-and-digest
865 (list "exist \"completion_matches\"\n"))
866 (setq inferior-octave-complete-impossible
867 (not (string-match "5$" (car inferior-octave-output-list))))
868
869 ;; And finally, everything is back to normal.
870 (set-process-filter proc 'inferior-octave-output-filter)
871 (run-hooks 'inferior-octave-startup-hook)
872 (run-hooks 'inferior-octave-startup-hook)
873 ;; Just in case, to be sure a cd in the startup file
874 ;; won't have detrimental effects.
875 (inferior-octave-resync-dirs)))
876
877(defun inferior-octave-completion-at-point ()
878 "Return the data to complete the Octave symbol at point."
879 (let* ((end (point))
880 (start
881 (save-excursion
882 (skip-syntax-backward "w_" (comint-line-beginning-position))
883 (point))))
884 (cond ((eq start end) nil)
885 (inferior-octave-complete-impossible
886 (message (concat
887 "Your Octave does not have `completion_matches'. "
888 "Please upgrade to version 2.X."))
889 nil)
890 (t
891 (list
892 start end
893 (completion-table-dynamic
894 (lambda (command)
895 (inferior-octave-send-list-and-digest
896 (list (concat "completion_matches (\"" command "\");\n")))
897 (sort (delete-dups inferior-octave-output-list)
898 'string-lessp))))))))
899
900(define-obsolete-function-alias 'inferior-octave-complete
901 'completion-at-point "24.1")
902
903(defun inferior-octave-dynamic-list-input-ring ()
904 "List the buffer's input history in a help buffer."
905 ;; We cannot use `comint-dynamic-list-input-ring', because it replaces
906 ;; "completion" by "history reference" ...
907 (interactive)
908 (if (or (not (ring-p comint-input-ring))
909 (ring-empty-p comint-input-ring))
910 (message "No history")
911 (let ((history nil)
912 (history-buffer " *Input History*")
913 (index (1- (ring-length comint-input-ring)))
914 (conf (current-window-configuration)))
915 ;; We have to build up a list ourselves from the ring vector.
916 (while (>= index 0)
917 (setq history (cons (ring-ref comint-input-ring index) history)
918 index (1- index)))
919 ;; Change "completion" to "history reference"
920 ;; to make the display accurate.
921 (with-output-to-temp-buffer history-buffer
922 (display-completion-list history)
923 (set-buffer history-buffer))
924 (message "Hit space to flush")
925 (let ((ch (read-event)))
926 (if (eq ch ?\ )
927 (set-window-configuration conf)
928 (setq unread-command-events (list ch)))))))
929
930(defun inferior-octave-strip-ctrl-g (string)
931 "Strip leading `^G' character.
932If STRING starts with a `^G', ring the bell and strip it."
933 (if (string-match "^\a" string)
934 (progn
935 (ding)
936 (setq string (substring string 1))))
937 string)
938
939(defun inferior-octave-output-filter (proc string)
940 "Standard output filter for the inferior Octave process.
941Ring Emacs bell if process output starts with an ASCII bell, and pass
942the rest to `comint-output-filter'."
943 (comint-output-filter proc (inferior-octave-strip-ctrl-g string)))
944
945(defun inferior-octave-output-digest (_proc string)
946 "Special output filter for the inferior Octave process.
947Save all output between newlines into `inferior-octave-output-list', and
948the rest to `inferior-octave-output-string'."
949 (setq string (concat inferior-octave-output-string string))
950 (while (string-match "\n" string)
951 (setq inferior-octave-output-list
952 (append inferior-octave-output-list
953 (list (substring string 0 (match-beginning 0))))
954 string (substring string (match-end 0))))
955 (if (string-match inferior-octave-prompt string)
956 (setq inferior-octave-receive-in-progress nil))
957 (setq inferior-octave-output-string string))
958
959(defun inferior-octave-send-list-and-digest (list)
960 "Send LIST to the inferior Octave process and digest the output.
961The elements of LIST have to be strings and are sent one by one. All
962output is passed to the filter `inferior-octave-output-digest'."
963 (let* ((proc inferior-octave-process)
964 (filter (process-filter proc))
965 string)
966 (set-process-filter proc 'inferior-octave-output-digest)
967 (setq inferior-octave-output-list nil)
968 (unwind-protect
969 (while (setq string (car list))
970 (setq inferior-octave-output-string nil
971 inferior-octave-receive-in-progress t)
972 (comint-send-string proc string)
973 (while inferior-octave-receive-in-progress
974 (accept-process-output proc))
975 (setq list (cdr list)))
976 (set-process-filter proc filter))))
977
978(defun inferior-octave-directory-tracker (string)
979 "Tracks `cd' commands issued to the inferior Octave process.
980Use \\[inferior-octave-resync-dirs] to resync if Emacs gets confused."
981 (cond
982 ((string-match "^[ \t]*cd[ \t;]*$" string)
983 (cd "~"))
984 ((string-match "^[ \t]*cd[ \t]+\\([^ \t\n;]*\\)[ \t\n;]*" string)
985 (cd (substring string (match-beginning 1) (match-end 1))))))
986
987(defun inferior-octave-resync-dirs ()
988 "Resync the buffer's idea of the current directory.
989This command queries the inferior Octave process about its current
990directory and makes this the current buffer's default directory."
991 (interactive)
992 (inferior-octave-send-list-and-digest '("disp (pwd ())\n"))
993 (cd (car inferior-octave-output-list)))
994
658 995
659;;; Miscellaneous useful functions 996;;; Miscellaneous useful functions
660 997
@@ -1143,8 +1480,5 @@ code line."
1143 'octave-send-line-auto-forward 1480 'octave-send-line-auto-forward
1144 'octave-send-show-buffer)))) 1481 'octave-send-show-buffer))))
1145 1482
1146;; provide ourself 1483(provide 'octave)
1147 1484;;; octave.el ends here
1148(provide 'octave-mod)
1149
1150;;; octave-mod.el ends here