* lisp/electric.el (electric-layout-mode): New minor mode.
[bpt/emacs.git] / lisp / progmodes / octave-mod.el
CommitLineData
092af6d8 1;;; octave-mod.el --- editing Octave source files under Emacs
f2727dfb 2
6d2a1e35
GM
3;; Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
4;; 2009, 2010 Free Software Foundation, Inc.
f2727dfb 5
f7fba1a8 6;; Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
c82d5b11 7;; Author: John Eaton <jwe@octave.org>
f7fba1a8 8;; Maintainer: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
f2727dfb
RS
9;; Keywords: languages
10
11;; This file is part of GNU Emacs.
12
b1fc2b50 13;; GNU Emacs is free software: you can redistribute it and/or modify
f2727dfb 14;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
f2727dfb
RS
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
b1fc2b50 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
f2727dfb
RS
25
26;;; Commentary:
27
d1e49742
RS
28;; This package provides Emacs support for Octave.
29;; It defines Octave mode, a major mode for editing
30;; Octave code.
31
d1e49742
RS
32;; The file octave-inf.el contains code for interacting with an inferior
33;; Octave process using comint.
f2727dfb 34
5d8137ab 35;; See the documentation of `octave-mode' and
d1e49742 36;; `run-octave' for further information on usage and customization.
f2727dfb 37
d1e49742 38;;; Code:
2454554e 39(require 'custom)
f2727dfb 40
28d16ed3
AS
41(defgroup octave nil
42 "Major mode for editing Octave source files."
8ec3bce0 43 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
28d16ed3
AS
44 :group 'languages)
45
e09735aa
RS
46(defvar inferior-octave-output-list nil)
47(defvar inferior-octave-output-string nil)
48(defvar inferior-octave-receive-in-progress nil)
49
004a00f4
DN
50(declare-function inferior-octave-send-list-and-digest "octave-inf" (list))
51
e7017ef9 52(defconst octave-maintainer-address
f7fba1a8 53 "Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>, bug-gnu-emacs@gnu.org"
e7017ef9
RS
54 "Current maintainer of the Emacs Octave package.")
55
7210c33f
SM
56(define-abbrev-table 'octave-abbrev-table
57 (mapcar (lambda (e) (append e '(nil 0 t)))
58 '(("`a" "all_va_args")
59 ("`b" "break")
60 ("`cs" "case")
61 ("`ca" "catch")
62 ("`c" "continue")
63 ("`el" "else")
64 ("`eli" "elseif")
65 ("`et" "end_try_catch")
66 ("`eu" "end_unwind_protect")
67 ("`ef" "endfor")
68 ("`efu" "endfunction")
69 ("`ei" "endif")
70 ("`es" "endswitch")
71 ("`ew" "endwhile")
72 ("`f" "for")
73 ("`fu" "function")
74 ("`gl" "global")
75 ("`gp" "gplot")
76 ("`gs" "gsplot")
77 ("`if" "if ()")
78 ("`o" "otherwise")
79 ("`rp" "replot")
80 ("`r" "return")
81 ("`s" "switch")
82 ("`t" "try")
83 ("`u" "until ()")
84 ("`up" "unwind_protect")
85 ("`upc" "unwind_protect_cleanup")
86 ("`w" "while ()")))
e7017ef9 87 "Abbrev table for Octave's reserved words.
99158127 88Used in `octave-mode' and inferior-octave-mode buffers.
7210c33f
SM
89All Octave abbrevs start with a grave accent (`)."
90 :regexp "\\(?:[^`]\\|^\\)\\(\\(?:\\<\\|`\\)\\w+\\)\\W*")
e7017ef9
RS
91
92(defvar octave-comment-char ?#
93 "Character to start an Octave comment.")
94(defvar octave-comment-start
c82d5b11 95 (string octave-comment-char ?\s)
e7017ef9
RS
96 "String to insert to start a new Octave in-line comment.")
97(defvar octave-comment-start-skip "\\s<+\\s-*"
98 "Regexp to match the start of an Octave comment up to its body.")
99
100(defvar octave-begin-keywords
490a8abe 101 '("do" "for" "function" "if" "switch" "try" "unwind_protect" "while"))
e7017ef9 102(defvar octave-else-keywords
6e6d2764 103 '("case" "catch" "else" "elseif" "otherwise" "unwind_protect_cleanup"))
e7017ef9 104(defvar octave-end-keywords
490a8abe 105 '("endfor" "endfunction" "endif" "endswitch" "end_try_catch"
b2ad70b6 106 "end_unwind_protect" "endwhile" "until" "end"))
e7017ef9
RS
107
108(defvar octave-reserved-words
6e6d2764
KH
109 (append octave-begin-keywords
110 octave-else-keywords
111 octave-end-keywords
490a8abe 112 '("break" "continue" "end" "global" "persistent" "return"))
e7017ef9
RS
113 "Reserved words in Octave.")
114
115(defvar octave-text-functions
116 '("casesen" "cd" "chdir" "clear" "diary" "dir" "document" "echo"
490a8abe
GM
117 "edit_history" "format" "help" "history" "hold"
118 "load" "ls" "more" "run_history" "save" "type"
e7017ef9 119 "which" "who" "whos")
490a8abe 120 "Text functions in Octave.")
e7017ef9
RS
121
122(defvar octave-variables
490a8abe
GM
123 '("DEFAULT_EXEC_PATH" "DEFAULT_LOADPATH"
124 "EDITOR" "EXEC_PATH" "F_DUPFD" "F_GETFD" "F_GETFL" "F_SETFD"
125 "F_SETFL" "I" "IMAGE_PATH" "Inf" "J"
126 "NaN" "OCTAVE_VERSION" "O_APPEND" "O_CREAT" "O_EXCL"
e7017ef9
RS
127 "O_NONBLOCK" "O_RDONLY" "O_RDWR" "O_TRUNC" "O_WRONLY" "PAGER" "PS1"
128 "PS2" "PS4" "PWD" "SEEK_CUR" "SEEK_END" "SEEK_SET" "__F_DUPFD__"
129 "__F_GETFD__" "__F_GETFL__" "__F_SETFD__" "__F_SETFL__" "__I__"
130 "__Inf__" "__J__" "__NaN__" "__OCTAVE_VERSION__" "__O_APPEND__"
131 "__O_CREAT__" "__O_EXCL__" "__O_NONBLOCK__" "__O_RDONLY__"
132 "__O_RDWR__" "__O_TRUNC__" "__O_WRONLY__" "__PWD__" "__SEEK_CUR__"
133 "__SEEK_END__" "__SEEK_SET__" "__argv__" "__e__" "__eps__"
490a8abe 134 "__i__" "__inf__" "__j__" "__nan__" "__pi__"
e7017ef9
RS
135 "__program_invocation_name__" "__program_name__" "__realmax__"
136 "__realmin__" "__stderr__" "__stdin__" "__stdout__" "ans" "argv"
490a8abe
GM
137 "beep_on_error" "completion_append_char"
138 "crash_dumps_octave_core" "default_save_format"
139 "e" "echo_executing_commands" "eps"
140 "error_text" "gnuplot_binary" "history_file"
141 "history_size" "ignore_function_time_stamp"
142 "inf" "nan" "nargin" "output_max_field_width" "output_precision"
e7017ef9 143 "page_output_immediately" "page_screen_output" "pi"
e7017ef9 144 "print_answer_id_name" "print_empty_dimensions"
490a8abe
GM
145 "program_invocation_name" "program_name"
146 "realmax" "realmin" "return_last_computed_value" "save_precision"
147 "saving_history" "sighup_dumps_octave_core" "sigterm_dumps_octave_core"
e7017ef9
RS
148 "silent_functions" "split_long_rows" "stderr" "stdin" "stdout"
149 "string_fill_char" "struct_levels_to_print"
490a8abe 150 "suppress_verbose_help_message")
e7017ef9
RS
151 "Builtin variables in Octave.")
152
153(defvar octave-function-header-regexp
154 (concat "^\\s-*\\<\\(function\\)\\>"
155 "\\([^=;\n]*=[ \t]*\\|[ \t]*\\)\\(\\w+\\)\\>")
156 "Regexp to match an Octave function header.
157The string `function' and its name are given by the first and third
158parenthetical grouping.")
159
160(defvar octave-font-lock-keywords
161 (list
162 ;; Fontify all builtin keywords.
163 (cons (concat "\\<\\("
e17b68ed
SM
164 (regexp-opt (append octave-reserved-words
165 octave-text-functions))
e7017ef9
RS
166 "\\)\\>")
167 'font-lock-keyword-face)
168 ;; Fontify all builtin operators.
169 (cons "\\(&\\||\\|<=\\|>=\\|==\\|<\\|>\\|!=\\|!\\)"
cb41203e
GM
170 (if (boundp 'font-lock-builtin-face)
171 'font-lock-builtin-face
172 'font-lock-preprocessor-face))
e7017ef9 173 ;; Fontify all builtin variables.
ff80a446 174 (cons (concat "\\<" (regexp-opt octave-variables) "\\>")
e7017ef9
RS
175 'font-lock-variable-name-face)
176 ;; Fontify all function declarations.
177 (list octave-function-header-regexp
178 '(1 font-lock-keyword-face)
179 '(3 font-lock-function-name-face nil t)))
180 "Additional Octave expressions to highlight.")
181
cf38dd42
SM
182(defun octave-syntax-propertize-function (start end)
183 (goto-char start)
184 (octave-syntax-propertize-sqs end)
185 (funcall (syntax-propertize-rules
ff80a446 186 ;; Try to distinguish the string-quotes from the transpose-quotes.
cf38dd42
SM
187 ("[[({,; ]\\('\\)"
188 (1 (prog1 "\"'" (octave-syntax-propertize-sqs end)))))
189 (point) end))
190
191(defun octave-syntax-propertize-sqs (end)
192 "Propertize the content/end of single-quote strings."
193 (when (eq (nth 3 (syntax-ppss)) ?\')
ff80a446 194 ;; A '..' string.
cf38dd42
SM
195 (when (re-search-forward
196 "\\(?:\\=\\|[^']\\)\\(?:''\\)*\\('\\)\\($\\|[^']\\)" end 'move)
197 (goto-char (match-beginning 2))
89acf735
SM
198 (when (eq (char-before (match-beginning 1)) ?\\)
199 ;; Backslash cannot escape a single quote.
200 (put-text-property (1- (match-beginning 1)) (match-beginning 1)
201 'syntax-table (string-to-syntax ".")))
ff80a446 202 (put-text-property (match-beginning 1) (match-end 1)
cf38dd42 203 'syntax-table (string-to-syntax "\"'")))))
ff80a446 204
28d16ed3 205(defcustom inferior-octave-buffer "*Inferior Octave*"
e22bbd48 206 "Name of buffer for running an inferior Octave process."
28d16ed3
AS
207 :type 'string
208 :group 'octave-inferior)
e7017ef9
RS
209
210(defvar inferior-octave-process nil)
211\f
e22bbd48 212(defvar octave-mode-map
f2727dfb
RS
213 (let ((map (make-sparse-keymap)))
214 (define-key map "`" 'octave-abbrev-start)
215 (define-key map ";" 'octave-electric-semi)
216 (define-key map " " 'octave-electric-space)
217 (define-key map "\n" 'octave-reindent-then-newline-and-indent)
a1506d29 218 (define-key map "\e\n" 'octave-indent-new-comment-line)
a1506d29 219 (define-key map "\M-\C-q" 'octave-indent-defun)
f2727dfb
RS
220 (define-key map "\C-c\C-b" 'octave-submit-bug-report)
221 (define-key map "\C-c\C-p" 'octave-previous-code-line)
222 (define-key map "\C-c\C-n" 'octave-next-code-line)
223 (define-key map "\C-c\C-a" 'octave-beginning-of-line)
a1506d29 224 (define-key map "\C-c\C-e" 'octave-end-of-line)
ec5d3ff7 225 (define-key map [remap down-list] 'smie-down-list)
f2727dfb 226 (define-key map "\C-c\M-\C-h" 'octave-mark-block)
e17b68ed
SM
227 (define-key map "\C-c]" 'smie-close-block)
228 (define-key map "\C-c/" 'smie-close-block)
34a463f1 229 (define-key map "\C-c\C-f" 'octave-insert-defun)
f2727dfb 230 (define-key map "\C-c\C-h" 'octave-help)
34a463f1
RS
231 (define-key map "\C-c\C-il" 'octave-send-line)
232 (define-key map "\C-c\C-ib" 'octave-send-block)
233 (define-key map "\C-c\C-if" 'octave-send-defun)
a1506d29 234 (define-key map "\C-c\C-ir" 'octave-send-region)
34a463f1
RS
235 (define-key map "\C-c\C-is" 'octave-show-process-buffer)
236 (define-key map "\C-c\C-ih" 'octave-hide-process-buffer)
237 (define-key map "\C-c\C-ik" 'octave-kill-process)
238 (define-key map "\C-c\C-i\C-l" 'octave-send-line)
239 (define-key map "\C-c\C-i\C-b" 'octave-send-block)
240 (define-key map "\C-c\C-i\C-f" 'octave-send-defun)
a1506d29 241 (define-key map "\C-c\C-i\C-r" 'octave-send-region)
34a463f1
RS
242 (define-key map "\C-c\C-i\C-s" 'octave-show-process-buffer)
243 (define-key map "\C-c\C-i\C-h" 'octave-hide-process-buffer)
244 (define-key map "\C-c\C-i\C-k" 'octave-kill-process)
e22bbd48
SM
245 map)
246 "Keymap used in Octave mode.")
247
f2727dfb 248
ff80a446
SM
249
250(easy-menu-define octave-mode-menu octave-mode-map
251 "Menu for Octave mode."
e22bbd48 252 '("Octave"
67885e8c 253 ("Lines"
e22bbd48
SM
254 ["Previous Code Line" octave-previous-code-line t]
255 ["Next Code Line" octave-next-code-line t]
256 ["Begin of Continuation" octave-beginning-of-line t]
257 ["End of Continuation" octave-end-of-line t]
258 ["Split Line at Point" octave-indent-new-comment-line t])
67885e8c 259 ("Blocks"
e22bbd48 260 ["Mark Block" octave-mark-block t]
e17b68ed 261 ["Close Block" smie-close-block t])
67885e8c 262 ("Functions"
e22bbd48
SM
263 ["Indent Function" octave-indent-defun t]
264 ["Insert Function" octave-insert-defun t])
265 "-"
67885e8c 266 ("Debug"
e22bbd48
SM
267 ["Send Current Line" octave-send-line t]
268 ["Send Current Block" octave-send-block t]
269 ["Send Current Function" octave-send-defun t]
270 ["Send Region" octave-send-region t]
271 ["Show Process Buffer" octave-show-process-buffer t]
272 ["Hide Process Buffer" octave-hide-process-buffer t]
273 ["Kill Process" octave-kill-process t])
274 "-"
275 ["Indent Line" indent-according-to-mode t]
c82d5b11 276 ["Complete Symbol" completion-at-point t]
e22bbd48 277 "-"
b5ba2d6f
SM
278 ["Toggle Abbrev Mode" abbrev-mode
279 :style toggle :selected abbrev-mode]
280 ["Toggle Auto-Fill Mode" auto-fill-mode
281 :style toggle :selected auto-fill-function]
e22bbd48
SM
282 "-"
283 ["Submit Bug Report" octave-submit-bug-report t]
284 "-"
c82d5b11 285 ["Describe Octave Mode" describe-mode t]
ff80a446 286 ["Lookup Octave Index" info-lookup-symbol t]))
f2727dfb 287
cb3d3ec1 288(defvar octave-mode-syntax-table
f2727dfb
RS
289 (let ((table (make-syntax-table)))
290 (modify-syntax-entry ?\r " " table)
291 (modify-syntax-entry ?+ "." table)
292 (modify-syntax-entry ?- "." table)
293 (modify-syntax-entry ?= "." table)
294 (modify-syntax-entry ?* "." table)
295 (modify-syntax-entry ?/ "." table)
296 (modify-syntax-entry ?> "." table)
297 (modify-syntax-entry ?< "." table)
298 (modify-syntax-entry ?& "." table)
299 (modify-syntax-entry ?| "." table)
300 (modify-syntax-entry ?! "." table)
301 (modify-syntax-entry ?\\ "\\" table)
302 (modify-syntax-entry ?\' "." table)
7210c33f
SM
303 ;; Was "w" for abbrevs, but now that it's not necessary any more,
304 (modify-syntax-entry ?\` "." table)
f2727dfb
RS
305 (modify-syntax-entry ?\" "\"" table)
306 (modify-syntax-entry ?. "w" table)
307 (modify-syntax-entry ?_ "w" table)
c5683ceb 308 ;; The "b" flag only applies to the second letter of the comstart
7e82caa7
SM
309 ;; and the first letter of the comend, i.e. the "4b" below is ineffective.
310 ;; If we try to put `b' on the single-line comments, we get a similar
311 ;; problem where the % and # chars appear as first chars of the 2-char
312 ;; comend, so the multi-line ender is also turned into style-b.
c5683ceb 313 ;; So we need the new "c" comment style.
c82d5b11
SM
314 (modify-syntax-entry ?\% "< 13" table)
315 (modify-syntax-entry ?\# "< 13" table)
c5683ceb
SM
316 (modify-syntax-entry ?\{ "(} 2c" table)
317 (modify-syntax-entry ?\} "){ 4c" table)
f2727dfb 318 (modify-syntax-entry ?\n ">" table)
cb3d3ec1
SM
319 table)
320 "Syntax table in use in `octave-mode' buffers.")
f2727dfb 321
28d16ed3 322(defcustom octave-auto-indent nil
e22bbd48 323 "Non-nil means indent line after a semicolon or space in Octave mode."
28d16ed3 324 :type 'boolean
2454554e 325 :group 'octave)
d83ee578 326
28d16ed3 327(defcustom octave-auto-newline nil
e22bbd48 328 "Non-nil means automatically newline after a semicolon in Octave mode."
28d16ed3
AS
329 :type 'boolean
330 :group 'octave)
f2727dfb 331
28d16ed3 332(defcustom octave-blink-matching-block t
e22bbd48 333 "Control the blinking of matching Octave block keywords.
f2727dfb 334Non-nil means show matching begin of block when inserting a space,
28d16ed3
AS
335newline or semicolon after an else or end keyword."
336 :type 'boolean
337 :group 'octave)
ff80a446 338
28d16ed3 339(defcustom octave-block-offset 2
e22bbd48 340 "Extra indentation applied to statements in Octave block structures."
28d16ed3
AS
341 :type 'integer
342 :group 'octave)
f2727dfb 343
f2727dfb
RS
344(defvar octave-block-comment-start
345 (concat (make-string 2 octave-comment-char) " ")
346 "String to insert to start a new Octave comment on an empty line.")
347
28d16ed3 348(defcustom octave-continuation-offset 4
e22bbd48 349 "Extra indentation applied to Octave continuation lines."
28d16ed3
AS
350 :type 'integer
351 :group 'octave)
e17b68ed
SM
352(eval-and-compile
353 (defconst octave-continuation-marker-regexp "\\\\\\|\\.\\.\\."))
f2727dfb 354(defvar octave-continuation-regexp
e17b68ed
SM
355 (concat "[^#%\n]*\\(" octave-continuation-marker-regexp
356 "\\)\\s-*\\(\\s<.*\\)?$"))
28d16ed3 357(defcustom octave-continuation-string "\\"
e22bbd48 358 "Character string used for Octave continuation lines. Normally \\."
28d16ed3
AS
359 :type 'string
360 :group 'octave)
f2727dfb
RS
361
362(defvar octave-completion-alist nil
363 "Alist of Octave symbols for completion in Octave mode.
364Each element looks like (VAR . VAR), where the car and cdr are the same
365symbol (an Octave command or variable name).
a1506d29 366Currently, only builtin variables can be completed.")
f2727dfb
RS
367
368(defvar octave-mode-imenu-generic-expression
369 (list
370 ;; Functions
371 (list nil octave-function-header-regexp 3))
372 "Imenu expression for Octave mode. See `imenu-generic-expression'.")
373
28d16ed3 374(defcustom octave-mode-hook nil
e22bbd48 375 "Hook to be run when Octave mode is started."
28d16ed3
AS
376 :type 'hook
377 :group 'octave)
378
379(defcustom octave-send-show-buffer t
e22bbd48 380 "Non-nil means display `inferior-octave-buffer' after sending to it."
28d16ed3
AS
381 :type 'boolean
382 :group 'octave)
383(defcustom octave-send-line-auto-forward t
e22bbd48 384 "Control auto-forward after sending to the inferior Octave process.
28d16ed3
AS
385Non-nil means always go to the next Octave code line after sending."
386 :type 'boolean
387 :group 'octave)
388(defcustom octave-send-echo-input t
e22bbd48 389 "Non-nil means echo input sent to the inferior Octave process."
28d16ed3
AS
390 :type 'boolean
391 :group 'octave)
f2727dfb
RS
392
393\f
e17b68ed
SM
394;;; SMIE indentation
395
396(require 'smie)
397
398(defconst octave-operator-table
399 '((assoc ";" "\n") (assoc ",") ; The doc claims they have equal precedence!?
400 (right "=" "+=" "-=" "*=" "/=")
401 (assoc "&&") (assoc "||") ; The doc claims they have equal precedence!?
402 (assoc "&") (assoc "|") ; The doc claims they have equal precedence!?
403 (nonassoc "<" "<=" "==" ">=" ">" "!=" "~=")
404 (nonassoc ":") ;No idea what this is.
405 (assoc "+" "-")
406 (assoc "*" "/" "\\" ".\\" ".*" "./")
407 (nonassoc "'" ".'")
408 (nonassoc "++" "--" "!" "~") ;And unary "+" and "-".
409 (right "^" "**" ".^" ".**")
410 ;; It's not really an operator, but for indentation purposes it
411 ;; could be convenient to treat it as one.
412 (assoc "...")))
413
89acf735
SM
414(defconst octave-smie-bnf-table
415 '((atom)
416 ;; We can't distinguish the first element in a sequence with
417 ;; precedence grammars, so we can't distinguish the condition
418 ;; if the `if' from the subsequent body, for example.
419 ;; This has to be done later in the indentation rules.
420 (exp (exp "\n" exp)
421 ;; We need to mention at least one of the operators in this part
422 ;; of the grammar: if the BNF and the operator table have
423 ;; no overlap, SMIE can't know how they relate.
424 (exp ";" exp)
425 ("try" exp "catch" exp "end_try_catch")
426 ("try" exp "catch" exp "end")
427 ("unwind_protect" exp
428 "unwind_protect_cleanup" exp "end_unwind_protect")
429 ("unwind_protect" exp "unwind_protect_cleanup" exp "end")
430 ("for" exp "endfor")
431 ("for" exp "end")
432 ("do" exp "until" atom)
433 ("while" exp "endwhile")
434 ("while" exp "end")
435 ("if" exp "endif")
436 ("if" exp "else" exp "endif")
437 ("if" exp "elseif" exp "else" exp "endif")
438 ("if" exp "elseif" exp "elseif" exp "else" exp "endif")
439 ("if" exp "elseif" exp "elseif" exp "else" exp "end")
440 ("switch" exp "case" exp "endswitch")
441 ("switch" exp "case" exp "otherwise" exp "endswitch")
442 ("switch" exp "case" exp "case" exp "otherwise" exp "endswitch")
443 ("switch" exp "case" exp "case" exp "otherwise" exp "end")
444 ("function" exp "endfunction")
445 ("function" exp "end"))
446 ;; (fundesc (atom "=" atom))
447 ))
448
674728d4
SM
449(defconst octave-smie-grammar
450 (smie-prec2->grammar
e17b68ed 451 (smie-merge-prec2s
674728d4
SM
452 (smie-bnf->prec2 octave-smie-bnf-table
453 '((assoc "\n" ";")))
e17b68ed 454
674728d4 455 (smie-precs->prec2 octave-operator-table))))
e17b68ed
SM
456
457;; Tokenizing needs to be refined so that ";;" is treated as two
458;; tokens and also so as to recognize the \n separator (and
459;; corresponding continuation lines).
460
461(defconst octave-operator-regexp
462 (regexp-opt (apply 'append (mapcar 'cdr octave-operator-table))))
463
464(defun octave-smie-backward-token ()
465 (let ((pos (point)))
466 (forward-comment (- (point)))
467 (cond
468 ((and (not (eq (char-before) ?\;)) ;Coalesce ";" and "\n".
469 (> pos (line-end-position))
470 (if (looking-back octave-continuation-marker-regexp (- (point) 3))
471 (progn
472 (goto-char (match-beginning 0))
473 (forward-comment (- (point)))
474 nil)
475 t)
476 ;; Ignore it if it's within parentheses.
477 (let ((ppss (syntax-ppss)))
478 (not (and (nth 1 ppss)
479 (eq ?\( (char-after (nth 1 ppss)))))))
480 (skip-chars-forward " \t")
481 ;; Why bother distinguishing \n and ;?
482 ";") ;;"\n"
483 ((and (looking-back octave-operator-regexp (- (point) 3) 'greedy)
484 ;; Don't mistake a string quote for a transpose.
485 (not (looking-back "\\s\"" (1- (point)))))
486 (goto-char (match-beginning 0))
487 (match-string-no-properties 0))
488 (t
489 (smie-default-backward-token)))))
490
491(defun octave-smie-forward-token ()
492 (skip-chars-forward " \t")
493 (when (looking-at (eval-when-compile
494 (concat "\\(" octave-continuation-marker-regexp
495 "\\)[ \t]*\\($\\|[%#]\\)")))
496 (goto-char (match-end 1))
497 (forward-comment 1))
498 (cond
499 ((and (looking-at "$\\|[%#]")
500 ;; Ignore it if it's within parentheses.
501 (prog1 (let ((ppss (syntax-ppss)))
502 (not (and (nth 1 ppss)
503 (eq ?\( (char-after (nth 1 ppss))))))
504 (forward-comment (point-max))))
505 ;; Why bother distinguishing \n and ;?
506 ";") ;;"\n"
507 ((looking-at ";[ \t]*\\($\\|[%#]\\)")
508 ;; Combine the ; with the subsequent \n.
509 (goto-char (match-beginning 1))
510 (forward-comment 1)
511 ";")
512 ((and (looking-at octave-operator-regexp)
513 ;; Don't mistake a string quote for a transpose.
514 (not (looking-at "\\s\"")))
515 (goto-char (match-end 0))
516 (match-string-no-properties 0))
517 (t
518 (smie-default-forward-token))))
519
c4d17d50
SM
520(defun octave-smie-rules (kind token)
521 (pcase (cons kind token)
674728d4
SM
522 ;; We could set smie-indent-basic instead, but that would have two
523 ;; disadvantages:
524 ;; - changes to octave-block-offset wouldn't take effect immediately.
525 ;; - edebug wouldn't show the use of this variable.
c4d17d50 526 (`(:elem . basic) octave-block-offset)
674728d4
SM
527 ;; Since "case" is in the same BNF rules as switch..end, SMIE by default
528 ;; aligns it with "switch".
529 (`(:before . "case") (if (not (smie-rule-sibling-p)) octave-block-offset))
c4d17d50 530 (`(:after . ";")
674728d4
SM
531 (if (smie-rule-parent-p "function" "if" "while" "else" "elseif" "for"
532 "otherwise" "case" "try" "catch" "unwind_protect"
533 "unwind_protect_cleanup")
534 (smie-rule-parent octave-block-offset)
c4d17d50
SM
535 ;; For (invalid) code between switch and case.
536 ;; (if (smie-parent-p "switch") 4)
537 0))))
e17b68ed 538
b073dc4b
SM
539(defvar electric-indent-chars)
540
f2727dfb 541;;;###autoload
c82d5b11 542(define-derived-mode octave-mode prog-mode "Octave"
f2727dfb
RS
543 "Major mode for editing Octave code.
544
545This mode makes it easier to write Octave code by helping with
546indentation, doing some of the typing for you (with Abbrev mode) and by
0472835f 547showing keywords, comments, strings, etc. in different faces (with
f2727dfb
RS
548Font Lock mode on terminals that support it).
549
550Octave itself is a high-level language, primarily intended for numerical
551computations. It provides a convenient command line interface for
552solving linear and nonlinear problems numerically. Function definitions
553can also be stored in files, and it can be used in a batch mode (which
554is why you need this mode!).
555
556The latest released version of Octave is always available via anonymous
490a8abe 557ftp from ftp.octave.org in the directory `/pub/octave'. Complete
f2727dfb
RS
558source and binaries for several popular systems are available.
559
560Type \\[list-abbrevs] to display the built-in abbrevs for Octave keywords.
561
562Keybindings
563===========
564
565\\{octave-mode-map}
566
567Variables you can use to customize Octave mode
568==============================================
569
e22bbd48 570`octave-auto-indent'
d83ee578
KH
571 Non-nil means indent current line after a semicolon or space.
572 Default is nil.
573
e22bbd48 574`octave-auto-newline'
f2727dfb
RS
575 Non-nil means auto-insert a newline and indent after a semicolon.
576 Default is nil.
577
e22bbd48 578`octave-blink-matching-block'
f2727dfb
RS
579 Non-nil means show matching begin of block when inserting a space,
580 newline or semicolon after an else or end keyword. Default is t.
581
e22bbd48 582`octave-block-offset'
f2727dfb
RS
583 Extra indentation applied to statements in block structures.
584 Default is 2.
585
e22bbd48 586`octave-continuation-offset'
f2727dfb
RS
587 Extra indentation applied to Octave continuation lines.
588 Default is 4.
589
e22bbd48 590`octave-continuation-string'
f2727dfb
RS
591 String used for Octave continuation lines.
592 Default is a backslash.
593
e22bbd48 594`octave-send-echo-input'
f2727dfb
RS
595 Non-nil means always display `inferior-octave-buffer' after sending a
596 command to the inferior Octave process.
597
e22bbd48 598`octave-send-line-auto-forward'
f2727dfb
RS
599 Non-nil means always go to the next unsent line of Octave code after
600 sending a line to the inferior Octave process.
601
e22bbd48 602`octave-send-echo-input'
f2727dfb
RS
603 Non-nil means echo input sent to the inferior Octave process.
604
605Turning on Octave mode runs the hook `octave-mode-hook'.
606
607To begin using this mode for all `.m' files that you edit, add the
608following lines to your `.emacs' file:
609
e22bbd48 610 (add-to-list 'auto-mode-alist '(\"\\\\.m\\\\'\" . octave-mode))
f2727dfb 611
490a8abe 612To automatically turn on the abbrev and auto-fill features,
f2727dfb
RS
613add the following lines to your `.emacs' file as well:
614
615 (add-hook 'octave-mode-hook
616 (lambda ()
617 (abbrev-mode 1)
e22bbd48 618 (auto-fill-mode 1)))
f2727dfb
RS
619
620To submit a problem report, enter \\[octave-submit-bug-report] from \
621an Octave mode buffer.
622This automatically sets up a mail buffer with version information
623already added. You just need to add a description of the problem,
624including a reproducible test case and send the message."
f2727dfb 625 (setq local-abbrev-table octave-abbrev-table)
c82d5b11 626
674728d4 627 (smie-setup octave-smie-grammar #'octave-smie-rules
c4d17d50
SM
628 :forward-token #'octave-smie-forward-token
629 :backward-token #'octave-smie-backward-token)
e17b68ed 630 (set (make-local-variable 'smie-indent-basic) 'octave-block-offset)
c4d17d50 631
89acf735 632 (set (make-local-variable 'smie-blink-matching-triggers)
c4d17d50
SM
633 (cons ?\; smie-blink-matching-triggers))
634 (unless octave-blink-matching-block
635 (remove-hook 'post-self-insert-hook #'smie-blink-matching-open 'local))
89acf735 636
2122161f
SM
637 (set (make-local-variable 'electric-indent-chars)
638 (cons ?\; electric-indent-chars))
c82d5b11
SM
639
640 (set (make-local-variable 'comment-start) octave-comment-start)
641 (set (make-local-variable 'comment-end) "")
642 ;; Don't set it here: it's not really a property of the language,
643 ;; just a personal preference of the author.
644 ;; (set (make-local-variable 'comment-column) 32)
645 (set (make-local-variable 'comment-start-skip) "\\s<+\\s-*")
dc94fc85 646 (set (make-local-variable 'comment-add) 1)
f2727dfb 647
c82d5b11
SM
648 (set (make-local-variable 'parse-sexp-ignore-comments) t)
649 (set (make-local-variable 'paragraph-start)
650 (concat "\\s-*$\\|" page-delimiter))
651 (set (make-local-variable 'paragraph-separate) paragraph-start)
652 (set (make-local-variable 'paragraph-ignore-fill-prefix) t)
653 (set (make-local-variable 'fill-paragraph-function) 'octave-fill-paragraph)
654 ;; FIXME: Why disable it?
655 ;; (set (make-local-variable 'adaptive-fill-regexp) nil)
656 ;; Again, this is not a property of the language, don't set it here.
657 ;; (set (make-local-variable 'fill-column) 72)
658 (set (make-local-variable 'normal-auto-fill-function) 'octave-auto-fill)
659
660 (set (make-local-variable 'font-lock-defaults)
cf38dd42
SM
661 '(octave-font-lock-keywords))
662
663 (set (make-local-variable 'syntax-propertize-function)
664 #'octave-syntax-propertize-function)
c82d5b11
SM
665
666 (set (make-local-variable 'imenu-generic-expression)
667 octave-mode-imenu-generic-expression)
668 (set (make-local-variable 'imenu-case-fold-search) nil)
669
670 (add-hook 'completion-at-point-functions
671 'octave-completion-at-point-function nil t)
ff80a446
SM
672 (set (make-local-variable 'beginning-of-defun-function)
673 'octave-beginning-of-defun)
f2727dfb 674
ff80a446 675 (easy-menu-add octave-mode-menu)
f2727dfb 676 (octave-initialize-completions)
9a969196 677 (run-mode-hooks 'octave-mode-hook))
5d8137ab 678
ff80a446
SM
679(defvar info-lookup-mode)
680
5d8137ab
SM
681(defun octave-help ()
682 "Get help on Octave symbols from the Octave info files.
683Look up symbol in the function, operator and variable indices of the info files."
684 (let ((info-lookup-mode 'octave-mode))
685 (call-interactively 'info-lookup-symbol)))
f2727dfb
RS
686\f
687;;; Miscellaneous useful functions
f2727dfb 688
f2727dfb 689(defsubst octave-in-comment-p ()
e7f767c2 690 "Return t if point is inside an Octave comment."
f2727dfb 691 (save-excursion
c82d5b11 692 ;; FIXME: use syntax-ppss?
cb3d3ec1 693 (nth 4 (parse-partial-sexp (line-beginning-position) (point)))))
f2727dfb
RS
694
695(defsubst octave-in-string-p ()
e7f767c2 696 "Return t if point is inside an Octave string."
f2727dfb 697 (save-excursion
c82d5b11 698 ;; FIXME: use syntax-ppss?
cb3d3ec1 699 (nth 3 (parse-partial-sexp (line-beginning-position) (point)))))
f2727dfb
RS
700
701(defsubst octave-not-in-string-or-comment-p ()
e7f767c2 702 "Return t if point is not inside an Octave string or comment."
c82d5b11 703 ;; FIXME: Use syntax-ppss?
cb3d3ec1 704 (let ((pps (parse-partial-sexp (line-beginning-position) (point))))
f2727dfb
RS
705 (not (or (nth 3 pps) (nth 4 pps)))))
706
f2727dfb 707
a584f30f 708(defun octave-looking-at-kw (regexp)
050a4b35 709 "Like `looking-at', but sets `case-fold-search' nil."
a584f30f
GM
710 (let ((case-fold-search nil))
711 (looking-at regexp)))
712
d83ee578
KH
713(defun octave-maybe-insert-continuation-string ()
714 (if (or (octave-in-comment-p)
715 (save-excursion
716 (beginning-of-line)
717 (looking-at octave-continuation-regexp)))
718 nil
719 (delete-horizontal-space)
720 (insert (concat " " octave-continuation-string))))
721
f2727dfb
RS
722\f
723;;; Indentation
f2727dfb
RS
724
725(defun octave-indent-new-comment-line ()
726 "Break Octave line at point, continuing comment if within one.
727If within code, insert `octave-continuation-string' before breaking the
a1506d29
JB
728line. If within a string, signal an error.
729The new line is properly indented."
f2727dfb
RS
730 (interactive)
731 (delete-horizontal-space)
732 (cond
733 ((octave-in-comment-p)
734 (indent-new-comment-line))
735 ((octave-in-string-p)
736 (error "Cannot split a code line inside a string"))
737 (t
738 (insert (concat " " octave-continuation-string))
739 (octave-reindent-then-newline-and-indent))))
740
741(defun octave-indent-defun ()
e22bbd48 742 "Properly indent the Octave function which contains point."
f2727dfb
RS
743 (interactive)
744 (save-excursion
ff80a446 745 (mark-defun)
f2727dfb
RS
746 (message "Indenting function...")
747 (indent-region (point) (mark) nil))
748 (message "Indenting function...done."))
749
750\f
751;;; Motion
752(defun octave-next-code-line (&optional arg)
753 "Move ARG lines of Octave code forward (backward if ARG is negative).
754Skips past all empty and comment lines. Default for ARG is 1.
755
756On success, return 0. Otherwise, go as far as possible and return -1."
757 (interactive "p")
758 (or arg (setq arg 1))
759 (beginning-of-line)
760 (let ((n 0)
761 (inc (if (> arg 0) 1 -1)))
762 (while (and (/= arg 0) (= n 0))
763 (setq n (forward-line inc))
764 (while (and (= n 0)
765 (looking-at "\\s-*\\($\\|\\s<\\)"))
766 (setq n (forward-line inc)))
767 (setq arg (- arg inc)))
768 n))
a1506d29 769
f2727dfb
RS
770(defun octave-previous-code-line (&optional arg)
771 "Move ARG lines of Octave code backward (forward if ARG is negative).
772Skips past all empty and comment lines. Default for ARG is 1.
773
774On success, return 0. Otherwise, go as far as possible and return -1."
775 (interactive "p")
776 (or arg (setq arg 1))
777 (octave-next-code-line (- arg)))
778
779(defun octave-beginning-of-line ()
780 "Move point to beginning of current Octave line.
781If on an empty or comment line, go to the beginning of that line.
782Otherwise, move backward to the beginning of the first Octave code line
783which is not inside a continuation statement, i.e., which does not
784follow a code line ending in `...' or `\\', or is inside an open
785parenthesis list."
786 (interactive)
787 (beginning-of-line)
788 (if (not (looking-at "\\s-*\\($\\|\\s<\\)"))
789 (while (or (condition-case nil
790 (progn
791 (up-list -1)
792 (beginning-of-line)
793 t)
794 (error nil))
795 (and (or (looking-at "\\s-*\\($\\|\\s<\\)")
796 (save-excursion
797 (if (zerop (octave-previous-code-line))
798 (looking-at octave-continuation-regexp))))
799 (zerop (forward-line -1)))))))
800
801(defun octave-end-of-line ()
802 "Move point to end of current Octave line.
803If on an empty or comment line, go to the end of that line.
804Otherwise, move forward to the end of the first Octave code line which
805does not end in `...' or `\\' or is inside an open parenthesis list."
806 (interactive)
807 (end-of-line)
808 (if (save-excursion
809 (beginning-of-line)
810 (looking-at "\\s-*\\($\\|\\s<\\)"))
811 ()
812 (while (or (condition-case nil
813 (progn
814 (up-list 1)
815 (end-of-line)
816 t)
817 (error nil))
818 (and (save-excursion
819 (beginning-of-line)
820 (or (looking-at "\\s-*\\($\\|\\s<\\)")
821 (looking-at octave-continuation-regexp)))
822 (zerop (forward-line 1)))))
823 (end-of-line)))
a1506d29 824
f2727dfb
RS
825(defun octave-mark-block ()
826 "Put point at the beginning of this Octave block, mark at the end.
827The block marked is the one that contains point or follows point."
828 (interactive)
ec5d3ff7
SM
829 (unless (or (looking-at "\\s(")
830 (save-excursion
831 (let* ((token (funcall smie-forward-token-function))
6d2a1e35 832 (level (assoc token smie-grammar)))
ec5d3ff7
SM
833 (and level (null (cadr level))))))
834 (backward-up-list 1))
835 (mark-sexp))
f2727dfb 836
f2727dfb
RS
837(defun octave-beginning-of-defun (&optional arg)
838 "Move backward to the beginning of an Octave function.
839With positive ARG, do it that many times. Negative argument -N means
840move forward to Nth following beginning of a function.
841Returns t unless search stops at the beginning or end of the buffer."
f2727dfb
RS
842 (let* ((arg (or arg 1))
843 (inc (if (> arg 0) 1 -1))
ff80a446
SM
844 (found nil)
845 (case-fold-search nil))
f2727dfb 846 (and (not (eobp))
ff80a446 847 (not (and (> arg 0) (looking-at "\\<function\\>")))
f2727dfb
RS
848 (skip-syntax-forward "w"))
849 (while (and (/= arg 0)
850 (setq found
ff80a446 851 (re-search-backward "\\<function\\>" inc)))
f2727dfb
RS
852 (if (octave-not-in-string-or-comment-p)
853 (setq arg (- arg inc))))
854 (if found
855 (progn
856 (and (< inc 0) (goto-char (match-beginning 0)))
857 t))))
858
f2727dfb
RS
859\f
860;;; Filling
861(defun octave-auto-fill ()
d83ee578
KH
862 "Perform auto-fill in Octave mode.
863Returns nil if no feasible place to break the line could be found, and t
864otherwise."
865 (let (fc give-up)
866 (if (or (null (setq fc (current-fill-column)))
867 (save-excursion
a1506d29 868 (beginning-of-line)
d83ee578 869 (and auto-fill-inhibit-regexp
a584f30f 870 (octave-looking-at-kw auto-fill-inhibit-regexp))))
d83ee578
KH
871 nil ; Can't do anything
872 (if (and (not (octave-in-comment-p))
873 (> (current-column) fc))
874 (setq fc (- fc (+ (length octave-continuation-string) 1))))
875 (while (and (not give-up) (> (current-column) fc))
876 (let* ((opoint (point))
877 (fpoint
878 (save-excursion
879 (move-to-column (+ fc 1))
880 (skip-chars-backward "^ \t\n")
881 ;; If we're at the beginning of the line, break after
882 ;; the first word
883 (if (bolp)
884 (re-search-forward "[ \t]" opoint t))
885 ;; If we're in a comment line, don't break after the
886 ;; comment chars
887 (if (save-excursion
888 (skip-syntax-backward " <")
889 (bolp))
cb3d3ec1 890 (re-search-forward "[ \t]" (line-end-position)
d83ee578
KH
891 'move))
892 ;; If we're not in a comment line and just ahead the
893 ;; continuation string, don't break here.
894 (if (and (not (octave-in-comment-p))
895 (looking-at
896 (concat "\\s-*"
897 (regexp-quote
898 octave-continuation-string)
899 "\\s-*$")))
900 (end-of-line))
901 (skip-chars-backward " \t")
902 (point))))
903 (if (save-excursion
904 (goto-char fpoint)
905 (not (or (bolp) (eolp))))
906 (let ((prev-column (current-column)))
907 (if (save-excursion
908 (skip-chars-backward " \t")
909 (= (point) fpoint))
910 (progn
911 (octave-maybe-insert-continuation-string)
912 (indent-new-comment-line t))
913 (save-excursion
914 (goto-char fpoint)
915 (octave-maybe-insert-continuation-string)
916 (indent-new-comment-line t)))
917 (if (>= (current-column) prev-column)
918 (setq give-up t)))
919 (setq give-up t))))
920 (not give-up))))
f2727dfb
RS
921
922(defun octave-fill-paragraph (&optional arg)
ec5d3ff7
SM
923 "Fill paragraph of Octave code, handling Octave comments."
924 ;; FIXME: difference with generic fill-paragraph:
925 ;; - code lines are only split, never joined.
926 ;; - \n that end comments are never removed.
927 ;; - insert continuation marker when splitting code lines.
928 (interactive "P")
929 (save-excursion
930 (let ((end (progn (forward-paragraph) (copy-marker (point) t)))
931 (beg (progn
932 (forward-paragraph -1)
933 (skip-chars-forward " \t\n")
934 (beginning-of-line)
935 (point)))
936 (cfc (current-fill-column))
937 comment-prefix)
938 (goto-char beg)
939 (while (< (point) end)
940 (condition-case nil
941 (indent-according-to-mode)
942 (error nil))
943 (move-to-column cfc)
944 ;; First check whether we need to combine non-empty comment lines
945 (if (and (< (current-column) cfc)
946 (octave-in-comment-p)
947 (not (save-excursion
948 (beginning-of-line)
949 (looking-at "^\\s-*\\s<+\\s-*$"))))
950 ;; This is a nonempty comment line which does not extend
951 ;; past the fill column. If it is followed by a nonempty
952 ;; comment line with the same comment prefix, try to
953 ;; combine them, and repeat this until either we reach the
954 ;; fill-column or there is nothing more to combine.
955 (progn
956 ;; Get the comment prefix
957 (save-excursion
958 (beginning-of-line)
959 (while (and (re-search-forward "\\s<+")
960 (not (octave-in-comment-p))))
961 (setq comment-prefix (match-string 0)))
962 ;; And keep combining ...
963 (while (and (< (current-column) cfc)
964 (save-excursion
965 (forward-line 1)
966 (and (looking-at
967 (concat "^\\s-*"
968 comment-prefix
969 "\\S<"))
970 (not (looking-at
971 (concat "^\\s-*"
972 comment-prefix
973 "\\s-*$"))))))
974 (delete-char 1)
975 (re-search-forward comment-prefix)
976 (delete-region (match-beginning 0) (match-end 0))
977 (fixup-whitespace)
978 (move-to-column cfc))))
979 ;; We might also try to combine continued code lines> Perhaps
980 ;; some other time ...
981 (skip-chars-forward "^ \t\n")
982 (delete-horizontal-space)
983 (if (or (< (current-column) cfc)
984 (and (= (current-column) cfc) (eolp)))
985 (forward-line 1)
986 (if (not (eolp)) (insert " "))
987 (or (octave-auto-fill)
988 (forward-line 1))))
989 t)))
f2727dfb
RS
990
991\f
992;;; Completions
993(defun octave-initialize-completions ()
994 "Create an alist for Octave completions."
995 (if octave-completion-alist
996 ()
997 (setq octave-completion-alist
c82d5b11
SM
998 (append octave-reserved-words
999 octave-text-functions
1000 octave-variables))))
1001
1002(defun octave-completion-at-point-function ()
1003 "Find the text to complete and the corresponding table."
7e82caa7 1004 (let* ((beg (save-excursion (backward-sexp 1) (point)))
ff80a446
SM
1005 (end (point)))
1006 (if (< beg (point))
1007 ;; Extend region past point, if applicable.
1008 (save-excursion (goto-char beg) (forward-sexp 1)
1009 (setq end (max end (point)))))
c82d5b11 1010 (list beg end octave-completion-alist)))
f2727dfb
RS
1011
1012(defun octave-complete-symbol ()
1013 "Perform completion on Octave symbol preceding point.
1014Compare that symbol against Octave's reserved words and builtin
1015variables."
f2727dfb 1016 (interactive)
c82d5b11 1017 (apply 'completion-in-region (octave-completion-at-point-function)))
f2727dfb
RS
1018\f
1019;;; Electric characters && friends
1020(defun octave-reindent-then-newline-and-indent ()
1021 "Reindent current Octave line, insert newline, and indent the new line.
1022If Abbrev mode is on, expand abbrevs first."
ff80a446 1023 ;; FIXME: None of this is Octave-specific.
f2727dfb 1024 (interactive)
ff80a446 1025 (reindent-then-newline-and-indent))
f2727dfb
RS
1026
1027(defun octave-electric-semi ()
1028 "Insert a semicolon in Octave mode.
d83ee578 1029Maybe expand abbrevs and blink matching block open keywords.
0472835f 1030Reindent the line if `octave-auto-indent' is non-nil.
d83ee578 1031Insert a newline if `octave-auto-newline' is non-nil."
f2727dfb 1032 (interactive)
89acf735 1033 (setq last-command-event ?\;)
f2727dfb 1034 (if (not (octave-not-in-string-or-comment-p))
89acf735 1035 (self-insert-command 1)
d83ee578
KH
1036 (if octave-auto-indent
1037 (indent-according-to-mode))
89acf735 1038 (self-insert-command 1)
f2727dfb
RS
1039 (if octave-auto-newline
1040 (newline-and-indent))))
1041
1042(defun octave-electric-space ()
1043 "Insert a space in Octave mode.
d83ee578 1044Maybe expand abbrevs and blink matching block open keywords.
0472835f 1045Reindent the line if `octave-auto-indent' is non-nil."
f2727dfb 1046 (interactive)
1ba983e8 1047 (setq last-command-event ? )
d9f9aa72
EZ
1048 (if (and octave-auto-indent
1049 (not (octave-not-in-string-or-comment-p)))
f2727dfb
RS
1050 (progn
1051 (indent-according-to-mode)
1052 (self-insert-command 1))
d83ee578
KH
1053 (if (and octave-auto-indent
1054 (save-excursion
1055 (skip-syntax-backward " ")
1056 (not (bolp))))
f2727dfb
RS
1057 (indent-according-to-mode))
1058 (self-insert-command 1)))
1059
1060(defun octave-abbrev-start ()
1061 "Start entering an Octave abbreviation.
1062If Abbrev mode is turned on, typing ` (grave accent) followed by ? or
1063\\[help-command] lists all Octave abbrevs. Any other key combination is
1064executed normally.
1065Note that all Octave mode abbrevs start with a grave accent."
1066 (interactive)
1067 (if (not abbrev-mode)
1068 (self-insert-command 1)
1069 (let (c)
1ba983e8 1070 (insert last-command-event)
f8246027 1071 (if (if (featurep 'xemacs)
aa82f4fb
KH
1072 (or (eq (event-to-character (setq c (next-event))) ??)
1073 (eq (event-to-character c) help-char))
1074 (or (eq (setq c (read-event)) ??)
1075 (eq c help-char)))
1076 (let ((abbrev-table-name-list '(octave-abbrev-table)))
f2727dfb
RS
1077 (list-abbrevs))
1078 (setq unread-command-events (list c))))))
1079
c82d5b11 1080(define-skeleton octave-insert-defun
f2727dfb
RS
1081 "Insert an Octave function skeleton.
1082Prompt for the function's name, arguments and return values (to be
1083entered without parens)."
c82d5b11
SM
1084 (let* ((defname (substring (buffer-name) 0 -2))
1085 (name (read-string (format "Function name (default %s): " defname)
1086 nil nil defname))
1087 (args (read-string "Arguments: "))
1088 (vals (read-string "Return values: ")))
1089 (format "%s%s (%s)"
1090 (cond
1091 ((string-equal vals "") vals)
1092 ((string-match "[ ,]" vals) (concat "[" vals "] = "))
1093 (t (concat vals " = ")))
1094 name
1095 args))
1096 \n "function " > str \n \n
1097 octave-block-comment-start "usage: " str \n
1098 octave-block-comment-start \n octave-block-comment-start
1099 \n _ \n
1100 "endfunction" > \n)
f2727dfb 1101\f
f2727dfb
RS
1102;;; Communication with the inferior Octave process
1103(defun octave-kill-process ()
1104 "Kill inferior Octave process and its buffer."
1105 (interactive)
1106 (if inferior-octave-process
1107 (progn
1108 (process-send-string inferior-octave-process "quit;\n")
1109 (accept-process-output inferior-octave-process)))
1110 (if inferior-octave-buffer
1111 (kill-buffer inferior-octave-buffer)))
1112
1113(defun octave-show-process-buffer ()
1114 "Make sure that `inferior-octave-buffer' is displayed."
1115 (interactive)
1116 (if (get-buffer inferior-octave-buffer)
1117 (display-buffer inferior-octave-buffer)
1118 (message "No buffer named %s" inferior-octave-buffer)))
1119
1120(defun octave-hide-process-buffer ()
1121 "Delete all windows that display `inferior-octave-buffer'."
1122 (interactive)
1123 (if (get-buffer inferior-octave-buffer)
1124 (delete-windows-on inferior-octave-buffer)
1125 (message "No buffer named %s" inferior-octave-buffer)))
1126
1127(defun octave-send-region (beg end)
1128 "Send current region to the inferior Octave process."
1129 (interactive "r")
a1506d29 1130 (inferior-octave t)
f2727dfb
RS
1131 (let ((proc inferior-octave-process)
1132 (string (buffer-substring-no-properties beg end))
1133 line)
5d8137ab 1134 (with-current-buffer inferior-octave-buffer
f2727dfb
RS
1135 (setq inferior-octave-output-list nil)
1136 (while (not (string-equal string ""))
1137 (if (string-match "\n" string)
1138 (setq line (substring string 0 (match-beginning 0))
1139 string (substring string (match-end 0)))
1140 (setq line string string ""))
1141 (setq inferior-octave-receive-in-progress t)
1142 (inferior-octave-send-list-and-digest (list (concat line "\n")))
1143 (while inferior-octave-receive-in-progress
1144 (accept-process-output proc))
1145 (insert-before-markers
1146 (mapconcat 'identity
1147 (append
1148 (if octave-send-echo-input (list line) (list ""))
1149 (mapcar 'inferior-octave-strip-ctrl-g
1150 inferior-octave-output-list)
1151 (list inferior-octave-output-string))
1152 "\n")))))
1153 (if octave-send-show-buffer
1154 (display-buffer inferior-octave-buffer)))
1155
1156(defun octave-send-block ()
a1506d29 1157 "Send current Octave block to the inferior Octave process."
f2727dfb
RS
1158 (interactive)
1159 (save-excursion
1160 (octave-mark-block)
1161 (octave-send-region (point) (mark))))
1162
1163(defun octave-send-defun ()
1164 "Send current Octave function to the inferior Octave process."
1165 (interactive)
1166 (save-excursion
ff80a446 1167 (mark-defun)
f2727dfb
RS
1168 (octave-send-region (point) (mark))))
1169
1170(defun octave-send-line (&optional arg)
1171 "Send current Octave code line to the inferior Octave process.
1172With positive prefix ARG, send that many lines.
1173If `octave-send-line-auto-forward' is non-nil, go to the next unsent
1174code line."
1175 (interactive "P")
1176 (or arg (setq arg 1))
1177 (if (> arg 0)
1178 (let (beg end)
1179 (beginning-of-line)
1180 (setq beg (point))
1181 (octave-next-code-line (- arg 1))
1182 (end-of-line)
1183 (setq end (point))
1184 (if octave-send-line-auto-forward
1185 (octave-next-code-line 1))
1186 (octave-send-region beg end))))
1187
1188(defun octave-eval-print-last-sexp ()
1189 "Evaluate Octave sexp before point and print value into current buffer."
1190 (interactive)
1191 (inferior-octave t)
1192 (let ((standard-output (current-buffer))
1193 (print-escape-newlines nil)
1194 (opoint (point)))
1195 (terpri)
a1506d29 1196 (prin1
f2727dfb
RS
1197 (save-excursion
1198 (forward-sexp -1)
1199 (inferior-octave-send-list-and-digest
1200 (list (concat (buffer-substring-no-properties (point) opoint)
1201 "\n")))
1202 (mapconcat 'identity inferior-octave-output-list "\n")))
1203 (terpri)))
d1e49742 1204\f
d1e49742
RS
1205;;; Bug reporting
1206(defun octave-submit-bug-report ()
1207 "Submit a bug report on the Emacs Octave package via mail."
1208 (interactive)
1209 (require 'reporter)
1210 (and
1211 (y-or-n-p "Do you want to submit a bug report? ")
1212 (reporter-submit-bug-report
1213 octave-maintainer-address
1214 (concat "Emacs version " emacs-version)
1215 (list
d83ee578 1216 'octave-auto-indent
d1e49742
RS
1217 'octave-auto-newline
1218 'octave-blink-matching-block
1219 'octave-block-offset
1220 'octave-comment-char
1221 'octave-continuation-offset
1222 'octave-continuation-string
d1e49742
RS
1223 'octave-send-echo-input
1224 'octave-send-line-auto-forward
1225 'octave-send-show-buffer))))
1226
5d8137ab 1227;; provide ourself
d1e49742 1228
e7017ef9 1229(provide 'octave-mod)
d1e49742
RS
1230
1231;;; octave-mod.el ends here