* progmodes/octave-mod.el (inferior-octave-send-list-and-digest):
[bpt/emacs.git] / lisp / progmodes / octave-mod.el
CommitLineData
092af6d8 1;;; octave-mod.el --- editing Octave source files under Emacs
f2727dfb 2
d7a0267c 3;; Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007
034babe1 4;; Free Software Foundation, Inc.
f2727dfb 5
f7fba1a8 6;; Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
f2727dfb 7;; Author: John Eaton <jwe@bevo.che.wisc.edu>
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
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
1a484753 15;; the Free Software Foundation; either version 3, or (at your option)
f2727dfb
RS
16;; 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; see the file COPYING. If not, write to the
3a35cf56
LK
25;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26;; Boston, MA 02110-1301, USA.
f2727dfb
RS
27
28;;; Commentary:
29
d1e49742
RS
30;; This package provides Emacs support for Octave.
31;; It defines Octave mode, a major mode for editing
32;; Octave code.
33
34;; The file octave-hlp.el provides `octave-help', a facility for looking up
35;; documentation on a symbol in the Octave info files.
36
37;; The file octave-inf.el contains code for interacting with an inferior
38;; Octave process using comint.
f2727dfb 39
d1e49742
RS
40;; See the documentation of `octave-mode', `octave-help' and
41;; `run-octave' for further information on usage and customization.
f2727dfb 42
d1e49742 43;;; Code:
2454554e 44(require 'custom)
f2727dfb 45
28d16ed3
AS
46(defgroup octave nil
47 "Major mode for editing Octave source files."
8ec3bce0 48 :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
28d16ed3
AS
49 :group 'languages)
50
e09735aa
RS
51(defvar inferior-octave-output-list nil)
52(defvar inferior-octave-output-string nil)
53(defvar inferior-octave-receive-in-progress nil)
54
004a00f4
DN
55(declare-function inferior-octave-send-list-and-digest "octave-inf" (list))
56
e7017ef9 57(defconst octave-maintainer-address
f7fba1a8 58 "Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>, bug-gnu-emacs@gnu.org"
e7017ef9
RS
59 "Current maintainer of the Emacs Octave package.")
60
61(defvar octave-abbrev-table nil
62 "Abbrev table for Octave's reserved words.
99158127 63Used in `octave-mode' and inferior-octave-mode buffers.
e7017ef9 64All Octave abbrevs start with a grave accent (`).")
99158127 65(unless octave-abbrev-table
a48edb29
GM
66 (define-abbrev-table 'octave-abbrev-table ()))
67
e22bbd48 68(let ((abbrevs-changed abbrevs-changed))
a48edb29
GM
69 (define-abbrev octave-abbrev-table "`a" "all_va_args" nil 0 t)
70 (define-abbrev octave-abbrev-table "`b" "break" nil 0 t)
71 (define-abbrev octave-abbrev-table "`cs" "case" nil 0 t)
72 (define-abbrev octave-abbrev-table "`ca" "catch" nil 0 t)
73 (define-abbrev octave-abbrev-table "`c" "continue" nil 0 t)
74 (define-abbrev octave-abbrev-table "`el" "else" nil 0 t)
75 (define-abbrev octave-abbrev-table "`eli" "elseif" nil 0 t)
76 (define-abbrev octave-abbrev-table "`et" "end_try_catch" nil 0 t)
77 (define-abbrev octave-abbrev-table "`eu" "end_unwind_protect" nil 0 t)
78 (define-abbrev octave-abbrev-table "`ef" "endfor" nil 0 t)
79 (define-abbrev octave-abbrev-table "`efu" "endfunction" nil 0 t)
80 (define-abbrev octave-abbrev-table "`ei" "endif" nil 0 t)
81 (define-abbrev octave-abbrev-table "`es" "endswitch" nil 0 t)
82 (define-abbrev octave-abbrev-table "`ew" "endwhile" nil 0 t)
83 (define-abbrev octave-abbrev-table "`f" "for" nil 0 t)
84 (define-abbrev octave-abbrev-table "`fu" "function" nil 0 t)
85 (define-abbrev octave-abbrev-table "`gl" "global" nil 0 t)
86 (define-abbrev octave-abbrev-table "`gp" "gplot" nil 0 t)
87 (define-abbrev octave-abbrev-table "`gs" "gsplot" nil 0 t)
88 (define-abbrev octave-abbrev-table "`if" "if ()" nil 0 t)
89 (define-abbrev octave-abbrev-table "`o" "otherwise" nil 0 t)
90 (define-abbrev octave-abbrev-table "`rp" "replot" nil 0 t)
91 (define-abbrev octave-abbrev-table "`r" "return" nil 0 t)
92 (define-abbrev octave-abbrev-table "`s" "switch" nil 0 t)
93 (define-abbrev octave-abbrev-table "`t" "try" nil 0 t)
490a8abe 94 (define-abbrev octave-abbrev-table "`u" "until ()" nil 0 t)
a48edb29
GM
95 (define-abbrev octave-abbrev-table "`up" "unwind_protect" nil 0 t)
96 (define-abbrev octave-abbrev-table "`upc" "unwind_protect_cleanup" nil 0 t)
e22bbd48 97 (define-abbrev octave-abbrev-table "`w" "while ()" nil 0 t))
e7017ef9
RS
98
99(defvar octave-comment-char ?#
100 "Character to start an Octave comment.")
101(defvar octave-comment-start
cb3d3ec1 102 (string octave-comment-char ?\ )
e7017ef9
RS
103 "String to insert to start a new Octave in-line comment.")
104(defvar octave-comment-start-skip "\\s<+\\s-*"
105 "Regexp to match the start of an Octave comment up to its body.")
106
107(defvar octave-begin-keywords
490a8abe 108 '("do" "for" "function" "if" "switch" "try" "unwind_protect" "while"))
e7017ef9 109(defvar octave-else-keywords
6e6d2764 110 '("case" "catch" "else" "elseif" "otherwise" "unwind_protect_cleanup"))
490a8abe
GM
111;; FIXME: only use specific "end" tokens here to avoid confusion when "end"
112;; is used in indexing (the real fix is much more complex).
e7017ef9 113(defvar octave-end-keywords
490a8abe
GM
114 '("endfor" "endfunction" "endif" "endswitch" "end_try_catch"
115 "end_unwind_protect" "endwhile" "until"))
e7017ef9
RS
116
117(defvar octave-reserved-words
6e6d2764
KH
118 (append octave-begin-keywords
119 octave-else-keywords
120 octave-end-keywords
490a8abe 121 '("break" "continue" "end" "global" "persistent" "return"))
e7017ef9
RS
122 "Reserved words in Octave.")
123
124(defvar octave-text-functions
125 '("casesen" "cd" "chdir" "clear" "diary" "dir" "document" "echo"
490a8abe
GM
126 "edit_history" "format" "help" "history" "hold"
127 "load" "ls" "more" "run_history" "save" "type"
e7017ef9 128 "which" "who" "whos")
490a8abe 129 "Text functions in Octave.")
e7017ef9
RS
130
131(defvar octave-variables
490a8abe
GM
132 '("DEFAULT_EXEC_PATH" "DEFAULT_LOADPATH"
133 "EDITOR" "EXEC_PATH" "F_DUPFD" "F_GETFD" "F_GETFL" "F_SETFD"
134 "F_SETFL" "I" "IMAGE_PATH" "Inf" "J"
135 "NaN" "OCTAVE_VERSION" "O_APPEND" "O_CREAT" "O_EXCL"
e7017ef9
RS
136 "O_NONBLOCK" "O_RDONLY" "O_RDWR" "O_TRUNC" "O_WRONLY" "PAGER" "PS1"
137 "PS2" "PS4" "PWD" "SEEK_CUR" "SEEK_END" "SEEK_SET" "__F_DUPFD__"
138 "__F_GETFD__" "__F_GETFL__" "__F_SETFD__" "__F_SETFL__" "__I__"
139 "__Inf__" "__J__" "__NaN__" "__OCTAVE_VERSION__" "__O_APPEND__"
140 "__O_CREAT__" "__O_EXCL__" "__O_NONBLOCK__" "__O_RDONLY__"
141 "__O_RDWR__" "__O_TRUNC__" "__O_WRONLY__" "__PWD__" "__SEEK_CUR__"
142 "__SEEK_END__" "__SEEK_SET__" "__argv__" "__e__" "__eps__"
490a8abe 143 "__i__" "__inf__" "__j__" "__nan__" "__pi__"
e7017ef9
RS
144 "__program_invocation_name__" "__program_name__" "__realmax__"
145 "__realmin__" "__stderr__" "__stdin__" "__stdout__" "ans" "argv"
490a8abe
GM
146 "beep_on_error" "completion_append_char"
147 "crash_dumps_octave_core" "default_save_format"
148 "e" "echo_executing_commands" "eps"
149 "error_text" "gnuplot_binary" "history_file"
150 "history_size" "ignore_function_time_stamp"
151 "inf" "nan" "nargin" "output_max_field_width" "output_precision"
e7017ef9 152 "page_output_immediately" "page_screen_output" "pi"
e7017ef9 153 "print_answer_id_name" "print_empty_dimensions"
490a8abe
GM
154 "program_invocation_name" "program_name"
155 "realmax" "realmin" "return_last_computed_value" "save_precision"
156 "saving_history" "sighup_dumps_octave_core" "sigterm_dumps_octave_core"
e7017ef9
RS
157 "silent_functions" "split_long_rows" "stderr" "stdin" "stdout"
158 "string_fill_char" "struct_levels_to_print"
490a8abe 159 "suppress_verbose_help_message")
e7017ef9
RS
160 "Builtin variables in Octave.")
161
162(defvar octave-function-header-regexp
163 (concat "^\\s-*\\<\\(function\\)\\>"
164 "\\([^=;\n]*=[ \t]*\\|[ \t]*\\)\\(\\w+\\)\\>")
165 "Regexp to match an Octave function header.
166The string `function' and its name are given by the first and third
167parenthetical grouping.")
168
169(defvar octave-font-lock-keywords
170 (list
171 ;; Fontify all builtin keywords.
172 (cons (concat "\\<\\("
173 (mapconcat 'identity octave-reserved-words "\\|")
174 (mapconcat 'identity octave-text-functions "\\|")
175 "\\)\\>")
176 'font-lock-keyword-face)
177 ;; Fontify all builtin operators.
178 (cons "\\(&\\||\\|<=\\|>=\\|==\\|<\\|>\\|!=\\|!\\)"
cb41203e
GM
179 (if (boundp 'font-lock-builtin-face)
180 'font-lock-builtin-face
181 'font-lock-preprocessor-face))
e7017ef9
RS
182 ;; Fontify all builtin variables.
183 (cons (concat "\\<\\("
184 (mapconcat 'identity octave-variables "\\|")
185 "\\)\\>")
186 'font-lock-variable-name-face)
187 ;; Fontify all function declarations.
188 (list octave-function-header-regexp
189 '(1 font-lock-keyword-face)
190 '(3 font-lock-function-name-face nil t)))
191 "Additional Octave expressions to highlight.")
192
28d16ed3 193(defcustom inferior-octave-buffer "*Inferior Octave*"
e22bbd48 194 "Name of buffer for running an inferior Octave process."
28d16ed3
AS
195 :type 'string
196 :group 'octave-inferior)
e7017ef9
RS
197
198(defvar inferior-octave-process nil)
199\f
e22bbd48 200(defvar octave-mode-map
f2727dfb
RS
201 (let ((map (make-sparse-keymap)))
202 (define-key map "`" 'octave-abbrev-start)
203 (define-key map ";" 'octave-electric-semi)
204 (define-key map " " 'octave-electric-space)
205 (define-key map "\n" 'octave-reindent-then-newline-and-indent)
f2727dfb 206 (define-key map "\e;" 'octave-indent-for-comment)
a1506d29 207 (define-key map "\e\n" 'octave-indent-new-comment-line)
f2727dfb
RS
208 (define-key map "\e\t" 'octave-complete-symbol)
209 (define-key map "\M-\C-a" 'octave-beginning-of-defun)
210 (define-key map "\M-\C-e" 'octave-end-of-defun)
211 (define-key map "\M-\C-h" 'octave-mark-defun)
a1506d29 212 (define-key map "\M-\C-q" 'octave-indent-defun)
f2727dfb 213 (define-key map "\C-c;" 'octave-comment-region)
a1506d29 214 (define-key map "\C-c:" 'octave-uncomment-region)
f2727dfb
RS
215 (define-key map "\C-c\C-b" 'octave-submit-bug-report)
216 (define-key map "\C-c\C-p" 'octave-previous-code-line)
217 (define-key map "\C-c\C-n" 'octave-next-code-line)
218 (define-key map "\C-c\C-a" 'octave-beginning-of-line)
a1506d29 219 (define-key map "\C-c\C-e" 'octave-end-of-line)
f2727dfb
RS
220 (define-key map "\C-c\M-\C-n" 'octave-forward-block)
221 (define-key map "\C-c\M-\C-p" 'octave-backward-block)
222 (define-key map "\C-c\M-\C-u" 'octave-backward-up-block)
223 (define-key map "\C-c\M-\C-d" 'octave-down-block)
224 (define-key map "\C-c\M-\C-h" 'octave-mark-block)
225 (define-key map "\C-c]" 'octave-close-block)
34a463f1 226 (define-key map "\C-c\C-f" 'octave-insert-defun)
f2727dfb 227 (define-key map "\C-c\C-h" 'octave-help)
34a463f1
RS
228 (define-key map "\C-c\C-il" 'octave-send-line)
229 (define-key map "\C-c\C-ib" 'octave-send-block)
230 (define-key map "\C-c\C-if" 'octave-send-defun)
a1506d29 231 (define-key map "\C-c\C-ir" 'octave-send-region)
34a463f1
RS
232 (define-key map "\C-c\C-is" 'octave-show-process-buffer)
233 (define-key map "\C-c\C-ih" 'octave-hide-process-buffer)
234 (define-key map "\C-c\C-ik" 'octave-kill-process)
235 (define-key map "\C-c\C-i\C-l" 'octave-send-line)
236 (define-key map "\C-c\C-i\C-b" 'octave-send-block)
237 (define-key map "\C-c\C-i\C-f" 'octave-send-defun)
a1506d29 238 (define-key map "\C-c\C-i\C-r" 'octave-send-region)
34a463f1
RS
239 (define-key map "\C-c\C-i\C-s" 'octave-show-process-buffer)
240 (define-key map "\C-c\C-i\C-h" 'octave-hide-process-buffer)
241 (define-key map "\C-c\C-i\C-k" 'octave-kill-process)
e22bbd48
SM
242 map)
243 "Keymap used in Octave mode.")
244
f2727dfb
RS
245
246(defvar octave-mode-menu
e22bbd48
SM
247 '("Octave"
248 '("Lines"
249 ["Previous Code Line" octave-previous-code-line t]
250 ["Next Code Line" octave-next-code-line t]
251 ["Begin of Continuation" octave-beginning-of-line t]
252 ["End of Continuation" octave-end-of-line t]
253 ["Split Line at Point" octave-indent-new-comment-line t])
254 '("Blocks"
255 ["Next Block" octave-forward-block t]
256 ["Previous Block" octave-backward-block t]
257 ["Down Block" octave-down-block t]
258 ["Up Block" octave-backward-up-block t]
259 ["Mark Block" octave-mark-block t]
260 ["Close Block" octave-close-block t])
261 '("Functions"
262 ["Begin of Function" octave-beginning-of-defun t]
263 ["End of Function" octave-end-of-defun t]
264 ["Mark Function" octave-mark-defun t]
265 ["Indent Function" octave-indent-defun t]
266 ["Insert Function" octave-insert-defun t])
267 "-"
268 '("Debug"
269 ["Send Current Line" octave-send-line t]
270 ["Send Current Block" octave-send-block t]
271 ["Send Current Function" octave-send-defun t]
272 ["Send Region" octave-send-region t]
273 ["Show Process Buffer" octave-show-process-buffer t]
274 ["Hide Process Buffer" octave-hide-process-buffer t]
275 ["Kill Process" octave-kill-process t])
276 "-"
277 ["Indent Line" indent-according-to-mode t]
278 ["Complete Symbol" octave-complete-symbol t]
279 "-"
280 ["Toggle Abbrev Mode" abbrev-mode t]
281 ["Toggle Auto-Fill Mode" auto-fill-mode t]
282 "-"
283 ["Submit Bug Report" octave-submit-bug-report t]
284 "-"
285 ["Describe Octave Mode" octave-describe-major-mode t]
286 ["Lookup Octave Index" octave-help t])
f2727dfb
RS
287 "Menu for Octave mode.")
288
cb3d3ec1 289(defvar octave-mode-syntax-table
f2727dfb
RS
290 (let ((table (make-syntax-table)))
291 (modify-syntax-entry ?\r " " 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)
303 (modify-syntax-entry ?\' "." table)
304 (modify-syntax-entry ?\` "w" table)
305 (modify-syntax-entry ?\" "\"" table)
306 (modify-syntax-entry ?. "w" table)
307 (modify-syntax-entry ?_ "w" table)
cb3d3ec1 308 (modify-syntax-entry ?\% "<" table)
f2727dfb
RS
309 (modify-syntax-entry ?\# "<" table)
310 (modify-syntax-entry ?\n ">" table)
cb3d3ec1
SM
311 table)
312 "Syntax table in use in `octave-mode' buffers.")
f2727dfb 313
28d16ed3 314(defcustom octave-auto-indent nil
e22bbd48 315 "Non-nil means indent line after a semicolon or space in Octave mode."
28d16ed3 316 :type 'boolean
2454554e 317 :group 'octave)
d83ee578 318
28d16ed3 319(defcustom octave-auto-newline nil
e22bbd48 320 "Non-nil means automatically newline after a semicolon in Octave mode."
28d16ed3
AS
321 :type 'boolean
322 :group 'octave)
f2727dfb 323
28d16ed3 324(defcustom octave-blink-matching-block t
e22bbd48 325 "Control the blinking of matching Octave block keywords.
f2727dfb 326Non-nil means show matching begin of block when inserting a space,
28d16ed3
AS
327newline or semicolon after an else or end keyword."
328 :type 'boolean
329 :group 'octave)
330(defcustom octave-block-offset 2
e22bbd48 331 "Extra indentation applied to statements in Octave block structures."
28d16ed3
AS
332 :type 'integer
333 :group 'octave)
f2727dfb
RS
334
335(defvar octave-block-begin-regexp
336 (concat "\\<\\("
337 (mapconcat 'identity octave-begin-keywords "\\|")
338 "\\)\\>"))
339(defvar octave-block-else-regexp
340 (concat "\\<\\("
341 (mapconcat 'identity octave-else-keywords "\\|")
342 "\\)\\>"))
343(defvar octave-block-end-regexp
344 (concat "\\<\\("
345 (mapconcat 'identity octave-end-keywords "\\|")
346 "\\)\\>"))
347(defvar octave-block-begin-or-end-regexp
348 (concat octave-block-begin-regexp "\\|" octave-block-end-regexp))
349(defvar octave-block-else-or-end-regexp
350 (concat octave-block-else-regexp "\\|" octave-block-end-regexp))
490a8abe
GM
351;; FIXME: only use specific "end" tokens here to avoid confusion when "end"
352;; is used in indexing (the real fix is much more complex).
f2727dfb 353(defvar octave-block-match-alist
490a8abe
GM
354 '(("do" . ("until"))
355 ("for" . ("endfor"))
356 ("function" . ("endfunction"))
357 ("if" . ("else" "elseif" "endif"))
358 ("switch" . ("case" "otherwise" "endswitch"))
359 ("try" . ("catch" "end_try_catch"))
360 ("unwind_protect" . ("unwind_protect_cleanup" "end_unwind_protect"))
361 ("while" . ("endwhile")))
f2727dfb
RS
362 "Alist with Octave's matching block keywords.
363Has Octave's begin keywords as keys and a list of the matching else or
364end keywords as associated values.")
365
366(defvar octave-block-comment-start
367 (concat (make-string 2 octave-comment-char) " ")
368 "String to insert to start a new Octave comment on an empty line.")
369
28d16ed3 370(defcustom octave-continuation-offset 4
e22bbd48 371 "Extra indentation applied to Octave continuation lines."
28d16ed3
AS
372 :type 'integer
373 :group 'octave)
f2727dfb
RS
374(defvar octave-continuation-regexp
375 "[^#%\n]*\\(\\\\\\|\\.\\.\\.\\)\\s-*\\(\\s<.*\\)?$")
28d16ed3 376(defcustom octave-continuation-string "\\"
e22bbd48 377 "Character string used for Octave continuation lines. Normally \\."
28d16ed3
AS
378 :type 'string
379 :group 'octave)
f2727dfb
RS
380
381(defvar octave-completion-alist nil
382 "Alist of Octave symbols for completion in Octave mode.
383Each element looks like (VAR . VAR), where the car and cdr are the same
384symbol (an Octave command or variable name).
a1506d29 385Currently, only builtin variables can be completed.")
f2727dfb
RS
386
387(defvar octave-mode-imenu-generic-expression
388 (list
389 ;; Functions
390 (list nil octave-function-header-regexp 3))
391 "Imenu expression for Octave mode. See `imenu-generic-expression'.")
392
28d16ed3 393(defcustom octave-mode-hook nil
e22bbd48 394 "Hook to be run when Octave mode is started."
28d16ed3
AS
395 :type 'hook
396 :group 'octave)
397
398(defcustom octave-send-show-buffer t
e22bbd48 399 "Non-nil means display `inferior-octave-buffer' after sending to it."
28d16ed3
AS
400 :type 'boolean
401 :group 'octave)
402(defcustom octave-send-line-auto-forward t
e22bbd48 403 "Control auto-forward after sending to the inferior Octave process.
28d16ed3
AS
404Non-nil means always go to the next Octave code line after sending."
405 :type 'boolean
406 :group 'octave)
407(defcustom octave-send-echo-input t
e22bbd48 408 "Non-nil means echo input sent to the inferior Octave process."
28d16ed3
AS
409 :type 'boolean
410 :group 'octave)
f2727dfb
RS
411
412\f
413;;;###autoload
414(defun octave-mode ()
415 "Major mode for editing Octave code.
416
417This mode makes it easier to write Octave code by helping with
418indentation, doing some of the typing for you (with Abbrev mode) and by
e22bbd48 419showing keywords, comments, strings, etc.. in different faces (with
f2727dfb
RS
420Font Lock mode on terminals that support it).
421
422Octave itself is a high-level language, primarily intended for numerical
423computations. It provides a convenient command line interface for
424solving linear and nonlinear problems numerically. Function definitions
425can also be stored in files, and it can be used in a batch mode (which
426is why you need this mode!).
427
428The latest released version of Octave is always available via anonymous
490a8abe 429ftp from ftp.octave.org in the directory `/pub/octave'. Complete
f2727dfb
RS
430source and binaries for several popular systems are available.
431
432Type \\[list-abbrevs] to display the built-in abbrevs for Octave keywords.
433
434Keybindings
435===========
436
437\\{octave-mode-map}
438
439Variables you can use to customize Octave mode
440==============================================
441
e22bbd48 442`octave-auto-indent'
d83ee578
KH
443 Non-nil means indent current line after a semicolon or space.
444 Default is nil.
445
e22bbd48 446`octave-auto-newline'
f2727dfb
RS
447 Non-nil means auto-insert a newline and indent after a semicolon.
448 Default is nil.
449
e22bbd48 450`octave-blink-matching-block'
f2727dfb
RS
451 Non-nil means show matching begin of block when inserting a space,
452 newline or semicolon after an else or end keyword. Default is t.
453
e22bbd48 454`octave-block-offset'
f2727dfb
RS
455 Extra indentation applied to statements in block structures.
456 Default is 2.
457
e22bbd48 458`octave-continuation-offset'
f2727dfb
RS
459 Extra indentation applied to Octave continuation lines.
460 Default is 4.
461
e22bbd48 462`octave-continuation-string'
f2727dfb
RS
463 String used for Octave continuation lines.
464 Default is a backslash.
465
e22bbd48 466`octave-send-echo-input'
f2727dfb
RS
467 Non-nil means always display `inferior-octave-buffer' after sending a
468 command to the inferior Octave process.
469
e22bbd48 470`octave-send-line-auto-forward'
f2727dfb
RS
471 Non-nil means always go to the next unsent line of Octave code after
472 sending a line to the inferior Octave process.
473
e22bbd48 474`octave-send-echo-input'
f2727dfb
RS
475 Non-nil means echo input sent to the inferior Octave process.
476
477Turning on Octave mode runs the hook `octave-mode-hook'.
478
479To begin using this mode for all `.m' files that you edit, add the
480following lines to your `.emacs' file:
481
e22bbd48 482 (add-to-list 'auto-mode-alist '(\"\\\\.m\\\\'\" . octave-mode))
f2727dfb 483
490a8abe 484To automatically turn on the abbrev and auto-fill features,
f2727dfb
RS
485add the following lines to your `.emacs' file as well:
486
487 (add-hook 'octave-mode-hook
488 (lambda ()
489 (abbrev-mode 1)
e22bbd48 490 (auto-fill-mode 1)))
f2727dfb
RS
491
492To submit a problem report, enter \\[octave-submit-bug-report] from \
493an Octave mode buffer.
494This automatically sets up a mail buffer with version information
495already added. You just need to add a description of the problem,
496including a reproducible test case and send the message."
497 (interactive)
498 (kill-all-local-variables)
499
500 (use-local-map octave-mode-map)
501 (setq major-mode 'octave-mode)
502 (setq mode-name "Octave")
503 (setq local-abbrev-table octave-abbrev-table)
504 (set-syntax-table octave-mode-syntax-table)
a1506d29 505
f2727dfb
RS
506 (make-local-variable 'indent-line-function)
507 (setq indent-line-function 'octave-indent-line)
508
a1506d29 509 (make-local-variable 'comment-start)
f2727dfb
RS
510 (setq comment-start octave-comment-start)
511 (make-local-variable 'comment-end)
512 (setq comment-end "")
513 (make-local-variable 'comment-column)
a1506d29 514 (setq comment-column 32)
f2727dfb
RS
515 (make-local-variable 'comment-start-skip)
516 (setq comment-start-skip "\\s<+\\s-*")
517 (make-local-variable 'comment-indent-function)
518 (setq comment-indent-function 'octave-comment-indent)
519
520 (make-local-variable 'parse-sexp-ignore-comments)
521 (setq parse-sexp-ignore-comments t)
522 (make-local-variable 'paragraph-start)
523 (setq paragraph-start (concat "\\s-*$\\|" page-delimiter))
524 (make-local-variable 'paragraph-separate)
525 (setq paragraph-separate paragraph-start)
526 (make-local-variable 'paragraph-ignore-fill-prefix)
527 (setq paragraph-ignore-fill-prefix t)
528 (make-local-variable 'fill-paragraph-function)
529 (setq fill-paragraph-function 'octave-fill-paragraph)
530 (make-local-variable 'adaptive-fill-regexp)
531 (setq adaptive-fill-regexp nil)
532 (make-local-variable 'fill-column)
533 (setq fill-column 72)
534 (make-local-variable 'normal-auto-fill-function)
535 (setq normal-auto-fill-function 'octave-auto-fill)
536
537 (make-local-variable 'font-lock-defaults)
538 (setq font-lock-defaults '(octave-font-lock-keywords nil nil))
539
540 (make-local-variable 'imenu-generic-expression)
c0b08eb0
DL
541 (setq imenu-generic-expression octave-mode-imenu-generic-expression
542 imenu-case-fold-search nil)
f2727dfb
RS
543
544 (octave-add-octave-menu)
545 (octave-initialize-completions)
9a969196 546 (run-mode-hooks 'octave-mode-hook))
f2727dfb
RS
547\f
548;;; Miscellaneous useful functions
549(defun octave-describe-major-mode ()
550 "Describe the current major mode."
551 (interactive)
552 (describe-function major-mode))
553
f2727dfb 554(defsubst octave-in-comment-p ()
e7f767c2 555 "Return t if point is inside an Octave comment."
f2727dfb
RS
556 (interactive)
557 (save-excursion
cb3d3ec1 558 (nth 4 (parse-partial-sexp (line-beginning-position) (point)))))
f2727dfb
RS
559
560(defsubst octave-in-string-p ()
e7f767c2 561 "Return t if point is inside an Octave string."
f2727dfb
RS
562 (interactive)
563 (save-excursion
cb3d3ec1 564 (nth 3 (parse-partial-sexp (line-beginning-position) (point)))))
f2727dfb
RS
565
566(defsubst octave-not-in-string-or-comment-p ()
e7f767c2 567 "Return t if point is not inside an Octave string or comment."
cb3d3ec1 568 (let ((pps (parse-partial-sexp (line-beginning-position) (point))))
f2727dfb
RS
569 (not (or (nth 3 pps) (nth 4 pps)))))
570
571(defun octave-in-block-p ()
e7f767c2 572 "Return t if point is inside an Octave block.
f2727dfb
RS
573The block is taken to start at the first letter of the begin keyword and
574to end after the end keyword."
575 (let ((pos (point)))
576 (save-excursion
577 (condition-case nil
578 (progn
579 (skip-syntax-forward "w")
580 (octave-up-block -1)
581 (octave-forward-block)
582 t)
583 (error nil))
584 (< pos (point)))))
585
a584f30f 586(defun octave-looking-at-kw (regexp)
050a4b35 587 "Like `looking-at', but sets `case-fold-search' nil."
a584f30f
GM
588 (let ((case-fold-search nil))
589 (looking-at regexp)))
590
050a4b35
GM
591(defun octave-re-search-forward-kw (regexp count)
592 "Like `re-search-forward', but sets `case-fold-search' nil, and moves point."
a584f30f 593 (let ((case-fold-search nil))
050a4b35 594 (re-search-forward regexp nil 'move count)))
a584f30f 595
050a4b35
GM
596(defun octave-re-search-backward-kw (regexp count)
597 "Like `re-search-backward', but sets `case-fold-search' nil, and moves point."
a584f30f 598 (let ((case-fold-search nil))
050a4b35 599 (re-search-backward regexp nil 'move count)))
a584f30f 600
f2727dfb 601(defun octave-in-defun-p ()
e7f767c2 602 "Return t if point is inside an Octave function declaration.
f2727dfb
RS
603The function is taken to start at the `f' of `function' and to end after
604the end keyword."
605 (let ((pos (point)))
606 (save-excursion
a584f30f 607 (or (and (octave-looking-at-kw "\\<function\\>")
f2727dfb
RS
608 (octave-not-in-string-or-comment-p))
609 (and (octave-beginning-of-defun)
610 (condition-case nil
611 (progn
612 (octave-forward-block)
613 t)
614 (error nil))
615 (< pos (point)))))))
616
d83ee578
KH
617(defun octave-maybe-insert-continuation-string ()
618 (if (or (octave-in-comment-p)
619 (save-excursion
620 (beginning-of-line)
621 (looking-at octave-continuation-regexp)))
622 nil
623 (delete-horizontal-space)
624 (insert (concat " " octave-continuation-string))))
625
f2727dfb
RS
626;;; Comments
627(defun octave-comment-region (beg end &optional arg)
628 "Comment or uncomment each line in the region as Octave code.
629See `comment-region'."
630 (interactive "r\nP")
631 (let ((comment-start (char-to-string octave-comment-char)))
632 (comment-region beg end arg)))
a1506d29 633
f2727dfb
RS
634(defun octave-uncomment-region (beg end &optional arg)
635 "Uncomment each line in the region as Octave code."
636 (interactive "r\nP")
637 (or arg (setq arg 1))
638 (octave-comment-region beg end (- arg)))
639
640\f
641;;; Indentation
642(defun calculate-octave-indent ()
643 "Return appropriate indentation for current line as Octave code.
644Returns an integer (the column to indent to) unless the line is a
645comment line with fixed goal golumn. In that case, returns a list whose
646car is the column to indent to, and whose cdr is the current indentation
647level."
648 (let ((is-continuation-line
649 (save-excursion
650 (if (zerop (octave-previous-code-line))
651 (looking-at octave-continuation-regexp))))
652 (icol 0))
653 (save-excursion
654 (beginning-of-line)
655 ;; If we can move backward out one level of parentheses, take 1
656 ;; plus the indentation of that parenthesis. Otherwise, go back
657 ;; to the beginning of the previous code line, and compute the
658 ;; offset this line gives.
659 (if (condition-case nil
660 (progn
661 (up-list -1)
662 t)
663 (error nil))
664 (setq icol (+ 1 (current-column)))
665 (if (zerop (octave-previous-code-line))
666 (progn
667 (octave-beginning-of-line)
668 (back-to-indentation)
669 (setq icol (current-column))
670 (let ((bot (point))
cb3d3ec1 671 (eol (line-end-position)))
f2727dfb
RS
672 (while (< (point) eol)
673 (if (octave-not-in-string-or-comment-p)
674 (cond
a584f30f 675 ((octave-looking-at-kw "\\<switch\\>")
6e6d2764 676 (setq icol (+ icol (* 2 octave-block-offset))))
a584f30f 677 ((octave-looking-at-kw octave-block-begin-regexp)
f2727dfb 678 (setq icol (+ icol octave-block-offset)))
a584f30f 679 ((octave-looking-at-kw octave-block-else-regexp)
f2727dfb
RS
680 (if (= bot (point))
681 (setq icol (+ icol octave-block-offset))))
a584f30f 682 ((octave-looking-at-kw octave-block-end-regexp)
f2727dfb 683 (if (not (= bot (point)))
6e6d2764
KH
684 (setq icol (- icol
685 (octave-block-end-offset)))))))
f2727dfb
RS
686 (forward-char)))
687 (if is-continuation-line
688 (setq icol (+ icol octave-continuation-offset)))))))
689 (save-excursion
690 (back-to-indentation)
691 (cond
a584f30f 692 ((and (octave-looking-at-kw octave-block-else-regexp)
f2727dfb
RS
693 (octave-not-in-string-or-comment-p))
694 (setq icol (- icol octave-block-offset)))
a584f30f 695 ((and (octave-looking-at-kw octave-block-end-regexp)
6e6d2764
KH
696 (octave-not-in-string-or-comment-p))
697 (setq icol (- icol (octave-block-end-offset))))
d83ee578
KH
698 ((or (looking-at "\\s<\\s<\\s<\\S<")
699 (octave-before-magic-comment-p))
f2727dfb
RS
700 (setq icol (list 0 icol)))
701 ((looking-at "\\s<\\S<")
702 (setq icol (list comment-column icol)))))
703 icol))
704
6e6d2764
KH
705(defun octave-block-end-offset ()
706 (save-excursion
707 (octave-backward-up-block 1)
708 (* octave-block-offset
709 (if (string-match (match-string 0) "switch") 2 1))))
710
d83ee578
KH
711(defun octave-before-magic-comment-p ()
712 (save-excursion
713 (beginning-of-line)
714 (and (bobp) (looking-at "\\s-*#!"))))
715
f2727dfb 716(defun octave-comment-indent ()
d83ee578
KH
717 (if (or (looking-at "\\s<\\s<\\s<")
718 (octave-before-magic-comment-p))
f2727dfb
RS
719 0
720 (if (looking-at "\\s<\\s<")
721 (calculate-octave-indent)
722 (skip-syntax-backward " ")
6e6d2764 723 (max (if (bolp) 0 (+ 1 (current-column)))
f2727dfb
RS
724 comment-column))))
725
726(defun octave-indent-for-comment ()
727 "Maybe insert and indent an Octave comment.
728If there is no comment already on this line, create a code-level comment
52dcc114 729\(started by two comment characters) if the line is empty, or an in-line
a1506d29 730comment (started by one comment character) otherwise.
f2727dfb
RS
731Point is left after the start of the comment which is properly aligned."
732 (interactive)
0c93f715
EZ
733 (beginning-of-line)
734 (if (looking-at "^\\s-*$")
735 (insert octave-block-comment-start)
736 (indent-for-comment))
f2727dfb
RS
737 (indent-according-to-mode))
738
739(defun octave-indent-line (&optional arg)
740 "Indent current line as Octave code.
741With optional ARG, use this as offset unless this line is a comment with
742fixed goal column."
743 (interactive)
744 (or arg (setq arg 0))
745 (let ((icol (calculate-octave-indent))
746 (relpos (- (current-column) (current-indentation))))
747 (if (listp icol)
748 (setq icol (car icol))
749 (setq icol (+ icol arg)))
750 (if (< icol 0)
751 (error "Unmatched end keyword")
752 (indent-line-to icol)
753 (if (> relpos 0)
754 (move-to-column (+ icol relpos))))))
755
756(defun octave-indent-new-comment-line ()
757 "Break Octave line at point, continuing comment if within one.
758If within code, insert `octave-continuation-string' before breaking the
a1506d29
JB
759line. If within a string, signal an error.
760The new line is properly indented."
f2727dfb
RS
761 (interactive)
762 (delete-horizontal-space)
763 (cond
764 ((octave-in-comment-p)
765 (indent-new-comment-line))
766 ((octave-in-string-p)
767 (error "Cannot split a code line inside a string"))
768 (t
769 (insert (concat " " octave-continuation-string))
770 (octave-reindent-then-newline-and-indent))))
771
772(defun octave-indent-defun ()
e22bbd48 773 "Properly indent the Octave function which contains point."
f2727dfb
RS
774 (interactive)
775 (save-excursion
776 (octave-mark-defun)
777 (message "Indenting function...")
778 (indent-region (point) (mark) nil))
779 (message "Indenting function...done."))
780
781\f
782;;; Motion
783(defun octave-next-code-line (&optional arg)
784 "Move ARG lines of Octave code forward (backward if ARG is negative).
785Skips past all empty and comment lines. Default for ARG is 1.
786
787On success, return 0. Otherwise, go as far as possible and return -1."
788 (interactive "p")
789 (or arg (setq arg 1))
790 (beginning-of-line)
791 (let ((n 0)
792 (inc (if (> arg 0) 1 -1)))
793 (while (and (/= arg 0) (= n 0))
794 (setq n (forward-line inc))
795 (while (and (= n 0)
796 (looking-at "\\s-*\\($\\|\\s<\\)"))
797 (setq n (forward-line inc)))
798 (setq arg (- arg inc)))
799 n))
a1506d29 800
f2727dfb
RS
801(defun octave-previous-code-line (&optional arg)
802 "Move ARG lines of Octave code backward (forward if ARG is negative).
803Skips past all empty and comment lines. Default for ARG is 1.
804
805On success, return 0. Otherwise, go as far as possible and return -1."
806 (interactive "p")
807 (or arg (setq arg 1))
808 (octave-next-code-line (- arg)))
809
810(defun octave-beginning-of-line ()
811 "Move point to beginning of current Octave line.
812If on an empty or comment line, go to the beginning of that line.
813Otherwise, move backward to the beginning of the first Octave code line
814which is not inside a continuation statement, i.e., which does not
815follow a code line ending in `...' or `\\', or is inside an open
816parenthesis list."
817 (interactive)
818 (beginning-of-line)
819 (if (not (looking-at "\\s-*\\($\\|\\s<\\)"))
820 (while (or (condition-case nil
821 (progn
822 (up-list -1)
823 (beginning-of-line)
824 t)
825 (error nil))
826 (and (or (looking-at "\\s-*\\($\\|\\s<\\)")
827 (save-excursion
828 (if (zerop (octave-previous-code-line))
829 (looking-at octave-continuation-regexp))))
830 (zerop (forward-line -1)))))))
831
832(defun octave-end-of-line ()
833 "Move point to end of current Octave line.
834If on an empty or comment line, go to the end of that line.
835Otherwise, move forward to the end of the first Octave code line which
836does not end in `...' or `\\' or is inside an open parenthesis list."
837 (interactive)
838 (end-of-line)
839 (if (save-excursion
840 (beginning-of-line)
841 (looking-at "\\s-*\\($\\|\\s<\\)"))
842 ()
843 (while (or (condition-case nil
844 (progn
845 (up-list 1)
846 (end-of-line)
847 t)
848 (error nil))
849 (and (save-excursion
850 (beginning-of-line)
851 (or (looking-at "\\s-*\\($\\|\\s<\\)")
852 (looking-at octave-continuation-regexp)))
853 (zerop (forward-line 1)))))
854 (end-of-line)))
a1506d29 855
e22bbd48
SM
856(defun octave-scan-blocks (count depth)
857 "Scan from point by COUNT Octave begin-end blocks.
f2727dfb
RS
858Returns the character number of the position thus found.
859
860If DEPTH is nonzero, block depth begins counting from that value.
861Only places where the depth in blocks becomes zero are candidates for
862stopping; COUNT such places are counted.
863
864If the beginning or end of the buffer is reached and the depth is wrong,
865an error is signaled."
866 (let ((min-depth (if (> depth 0) 0 depth))
867 (inc (if (> count 0) 1 -1)))
868 (save-excursion
869 (while (/= count 0)
870 (catch 'foo
a584f30f 871 (while (or (octave-re-search-forward-kw
050a4b35 872 octave-block-begin-or-end-regexp inc)
f2727dfb
RS
873 (if (/= depth 0)
874 (error "Unbalanced block")))
875 (if (octave-not-in-string-or-comment-p)
876 (progn
877 (cond
878 ((match-end 1)
879 (setq depth (+ depth inc)))
880 ((match-end 2)
881 (setq depth (- depth inc))))
882 (if (< depth min-depth)
883 (error "Containing expression ends prematurely"))
884 (if (= depth 0)
885 (throw 'foo nil))))))
886 (setq count (- count inc)))
887 (point))))
888
889(defun octave-forward-block (&optional arg)
890 "Move forward across one balanced Octave begin-end block.
891With argument, do it that many times.
892Negative arg -N means move backward across N blocks."
893 (interactive "p")
894 (or arg (setq arg 1))
e22bbd48 895 (goto-char (or (octave-scan-blocks arg 0) (buffer-end arg))))
f2727dfb
RS
896
897(defun octave-backward-block (&optional arg)
898 "Move backward across one balanced Octave begin-end block.
899With argument, do it that many times.
900Negative arg -N means move forward across N blocks."
901 (interactive "p")
902 (or arg (setq arg 1))
903 (octave-forward-block (- arg)))
904
905(defun octave-down-block (arg)
906 "Move forward down one begin-end block level of Octave code.
907With argument, do this that many times.
908A negative argument means move backward but still go down a level.
909In Lisp programs, an argument is required."
910 (interactive "p")
911 (let ((inc (if (> arg 0) 1 -1)))
912 (while (/= arg 0)
e22bbd48 913 (goto-char (or (octave-scan-blocks inc -1)
f2727dfb
RS
914 (buffer-end arg)))
915 (setq arg (- arg inc)))))
916
917(defun octave-backward-up-block (arg)
918 "Move backward out of one begin-end block level of Octave code.
919With argument, do this that many times.
920A negative argument means move forward but still to a less deep spot.
921In Lisp programs, an argument is required."
922 (interactive "p")
923 (octave-up-block (- arg)))
924
925(defun octave-up-block (arg)
926 "Move forward out of one begin-end block level of Octave code.
927With argument, do this that many times.
928A negative argument means move backward but still to a less deep spot.
929In Lisp programs, an argument is required."
930 (interactive "p")
931 (let ((inc (if (> arg 0) 1 -1)))
932 (while (/= arg 0)
e22bbd48 933 (goto-char (or (octave-scan-blocks inc 1)
f2727dfb
RS
934 (buffer-end arg)))
935 (setq arg (- arg inc)))))
936
937(defun octave-mark-block ()
938 "Put point at the beginning of this Octave block, mark at the end.
939The block marked is the one that contains point or follows point."
940 (interactive)
941 (let ((pos (point)))
942 (if (or (and (octave-in-block-p)
943 (skip-syntax-forward "w"))
944 (condition-case nil
945 (progn
946 (octave-down-block 1)
947 (octave-in-block-p))
948 (error nil)))
949 (progn
950 (octave-up-block -1)
951 (push-mark (point))
952 (octave-forward-block)
953 (exchange-point-and-mark))
954 (goto-char pos)
955 (message "No block to mark found"))))
956
957(defun octave-close-block ()
958 "Close the current Octave block on a separate line.
959An error is signaled if no block to close is found."
960 (interactive)
961 (let (bb-keyword)
962 (condition-case nil
963 (progn
964 (save-excursion
965 (octave-backward-up-block 1)
966 (setq bb-keyword (buffer-substring-no-properties
967 (match-beginning 1) (match-end 1))))
968 (if (save-excursion
969 (beginning-of-line)
970 (looking-at "^\\s-*$"))
971 (indent-according-to-mode)
972 (octave-reindent-then-newline-and-indent))
973 (insert (car (reverse
974 (assoc bb-keyword
975 octave-block-match-alist))))
976 (octave-reindent-then-newline-and-indent)
977 t)
978 (error (message "No block to close found")))))
979
980(defun octave-blink-matching-block-open ()
981 "Blink the matching Octave begin block keyword.
982If point is right after an Octave else or end type block keyword, move
983cursor momentarily to the corresponding begin keyword.
984Signal an error if the keywords are incompatible."
985 (interactive)
986 (let (bb-keyword bb-arg eb-keyword pos eol)
987 (if (and (octave-not-in-string-or-comment-p)
988 (looking-at "\\>")
989 (save-excursion
990 (skip-syntax-backward "w")
a584f30f 991 (octave-looking-at-kw octave-block-else-or-end-regexp)))
f2727dfb
RS
992 (save-excursion
993 (cond
994 ((match-end 1)
995 (setq eb-keyword
996 (buffer-substring-no-properties
997 (match-beginning 1) (match-end 1)))
998 (octave-backward-up-block 1))
999 ((match-end 2)
1000 (setq eb-keyword
1001 (buffer-substring-no-properties
1002 (match-beginning 2) (match-end 2)))
1003 (octave-backward-block)))
1004 (setq pos (match-end 0)
1005 bb-keyword
1006 (buffer-substring-no-properties
1007 (match-beginning 0) pos)
1008 pos (+ pos 1)
cb3d3ec1 1009 eol (line-end-position)
f2727dfb
RS
1010 bb-arg
1011 (save-excursion
1012 (save-restriction
1013 (goto-char pos)
1014 (while (and (skip-syntax-forward "^<" eol)
1015 (octave-in-string-p)
1016 (not (forward-char 1))))
1017 (skip-syntax-backward " ")
1018 (buffer-substring-no-properties pos (point)))))
1019 (if (member eb-keyword
1020 (cdr (assoc bb-keyword octave-block-match-alist)))
1021 (progn
1022 (message "Matches `%s %s'" bb-keyword bb-arg)
1023 (if (pos-visible-in-window-p)
1024 (sit-for blink-matching-delay)))
1025 (error "Block keywords `%s' and `%s' do not match"
1026 bb-keyword eb-keyword))))))
1027
1028(defun octave-beginning-of-defun (&optional arg)
1029 "Move backward to the beginning of an Octave function.
1030With positive ARG, do it that many times. Negative argument -N means
1031move forward to Nth following beginning of a function.
1032Returns t unless search stops at the beginning or end of the buffer."
1033 (interactive "p")
1034 (let* ((arg (or arg 1))
1035 (inc (if (> arg 0) 1 -1))
1036 (found))
1037 (and (not (eobp))
a584f30f 1038 (not (and (> arg 0) (octave-looking-at-kw "\\<function\\>")))
f2727dfb
RS
1039 (skip-syntax-forward "w"))
1040 (while (and (/= arg 0)
1041 (setq found
050a4b35 1042 (octave-re-search-backward-kw "\\<function\\>" inc)))
f2727dfb
RS
1043 (if (octave-not-in-string-or-comment-p)
1044 (setq arg (- arg inc))))
1045 (if found
1046 (progn
1047 (and (< inc 0) (goto-char (match-beginning 0)))
1048 t))))
1049
1050(defun octave-end-of-defun (&optional arg)
1051 "Move forward to the end of an Octave function.
1052With positive ARG, do it that many times. Negative argument -N means
1053move back to Nth preceding end of a function.
1054
1055An end of a function occurs right after the end keyword matching the
1056`function' keyword that starts the function."
1057 (interactive "p")
1058 (or arg (setq arg 1))
1059 (and (< arg 0) (skip-syntax-backward "w"))
a1506d29 1060 (and (> arg 0) (skip-syntax-forward "w"))
f2727dfb
RS
1061 (if (octave-in-defun-p)
1062 (setq arg (- arg 1)))
1063 (if (= arg 0) (setq arg -1))
1064 (if (octave-beginning-of-defun (- arg))
1065 (octave-forward-block)))
1066
1067(defun octave-mark-defun ()
1068 "Put point at the beginning of this Octave function, mark at its end.
1069The function marked is the one containing point or following point."
1070 (interactive)
1071 (let ((pos (point)))
1072 (if (or (octave-in-defun-p)
1073 (and (octave-beginning-of-defun -1)
1074 (octave-in-defun-p)))
1075 (progn
1076 (skip-syntax-forward "w")
1077 (octave-beginning-of-defun)
1078 (push-mark (point))
1079 (octave-end-of-defun)
1080 (exchange-point-and-mark))
1081 (goto-char pos)
1082 (message "No function to mark found"))))
a1506d29 1083
f2727dfb
RS
1084\f
1085;;; Filling
1086(defun octave-auto-fill ()
d83ee578
KH
1087 "Perform auto-fill in Octave mode.
1088Returns nil if no feasible place to break the line could be found, and t
1089otherwise."
1090 (let (fc give-up)
1091 (if (or (null (setq fc (current-fill-column)))
1092 (save-excursion
a1506d29 1093 (beginning-of-line)
d83ee578 1094 (and auto-fill-inhibit-regexp
a584f30f 1095 (octave-looking-at-kw auto-fill-inhibit-regexp))))
d83ee578
KH
1096 nil ; Can't do anything
1097 (if (and (not (octave-in-comment-p))
1098 (> (current-column) fc))
1099 (setq fc (- fc (+ (length octave-continuation-string) 1))))
1100 (while (and (not give-up) (> (current-column) fc))
1101 (let* ((opoint (point))
1102 (fpoint
1103 (save-excursion
1104 (move-to-column (+ fc 1))
1105 (skip-chars-backward "^ \t\n")
1106 ;; If we're at the beginning of the line, break after
1107 ;; the first word
1108 (if (bolp)
1109 (re-search-forward "[ \t]" opoint t))
1110 ;; If we're in a comment line, don't break after the
1111 ;; comment chars
1112 (if (save-excursion
1113 (skip-syntax-backward " <")
1114 (bolp))
cb3d3ec1 1115 (re-search-forward "[ \t]" (line-end-position)
d83ee578
KH
1116 'move))
1117 ;; If we're not in a comment line and just ahead the
1118 ;; continuation string, don't break here.
1119 (if (and (not (octave-in-comment-p))
1120 (looking-at
1121 (concat "\\s-*"
1122 (regexp-quote
1123 octave-continuation-string)
1124 "\\s-*$")))
1125 (end-of-line))
1126 (skip-chars-backward " \t")
1127 (point))))
1128 (if (save-excursion
1129 (goto-char fpoint)
1130 (not (or (bolp) (eolp))))
1131 (let ((prev-column (current-column)))
1132 (if (save-excursion
1133 (skip-chars-backward " \t")
1134 (= (point) fpoint))
1135 (progn
1136 (octave-maybe-insert-continuation-string)
1137 (indent-new-comment-line t))
1138 (save-excursion
1139 (goto-char fpoint)
1140 (octave-maybe-insert-continuation-string)
1141 (indent-new-comment-line t)))
1142 (if (>= (current-column) prev-column)
1143 (setq give-up t)))
1144 (setq give-up t))))
1145 (not give-up))))
f2727dfb
RS
1146
1147(defun octave-fill-paragraph (&optional arg)
1148 "Fill paragraph of Octave code, handling Octave comments."
e22bbd48
SM
1149 ;; FIXME: now that the default fill-paragraph takes care of similar issues,
1150 ;; this seems obsolete. --Stef
f2727dfb 1151 (interactive "P")
a1506d29 1152 (save-excursion
f2727dfb
RS
1153 (let ((end (progn (forward-paragraph) (point)))
1154 (beg (progn
1155 (forward-paragraph -1)
1156 (skip-chars-forward " \t\n")
1157 (beginning-of-line)
1158 (point)))
1159 (cfc (current-fill-column))
1160 (ind (calculate-octave-indent))
1161 comment-prefix)
1162 (save-restriction
1163 (goto-char beg)
1164 (narrow-to-region beg end)
1165 (if (listp ind) (setq ind (nth 1 ind)))
1166 (while (not (eobp))
1167 (condition-case nil
1168 (octave-indent-line ind)
1169 (error nil))
1170 (if (and (> ind 0)
1171 (not
1172 (save-excursion
1173 (beginning-of-line)
1174 (looking-at "^\\s-*\\($\\|\\s<+\\)"))))
1175 (setq ind 0))
1176 (move-to-column cfc)
1177 ;; First check whether we need to combine non-empty comment lines
1178 (if (and (< (current-column) cfc)
1179 (octave-in-comment-p)
1180 (not (save-excursion
1181 (beginning-of-line)
1182 (looking-at "^\\s-*\\s<+\\s-*$"))))
1183 ;; This is a nonempty comment line which does not extend
6c83d99f 1184 ;; past the fill column. If it is followed by a nonempty
f2727dfb
RS
1185 ;; comment line with the same comment prefix, try to
1186 ;; combine them, and repeat this until either we reach the
1187 ;; fill-column or there is nothing more to combine.
1188 (progn
1189 ;; Get the comment prefix
1190 (save-excursion
1191 (beginning-of-line)
1192 (while (and (re-search-forward "\\s<+")
1193 (not (octave-in-comment-p))))
1194 (setq comment-prefix (match-string 0)))
1195 ;; And keep combining ...
1196 (while (and (< (current-column) cfc)
1197 (save-excursion
1198 (forward-line 1)
1199 (and (looking-at
1200 (concat "^\\s-*"
1201 comment-prefix
1202 "\\S<"))
1203 (not (looking-at
1204 (concat "^\\s-*"
1205 comment-prefix
1206 "\\s-*$"))))))
1207 (delete-char 1)
1208 (re-search-forward comment-prefix)
1209 (delete-region (match-beginning 0) (match-end 0))
1210 (fixup-whitespace)
1211 (move-to-column cfc))))
d83ee578
KH
1212 ;; We might also try to combine continued code lines> Perhaps
1213 ;; some other time ...
f2727dfb
RS
1214 (skip-chars-forward "^ \t\n")
1215 (delete-horizontal-space)
1216 (if (or (< (current-column) cfc)
1217 (and (= (current-column) cfc) (eolp)))
1218 (forward-line 1)
1219 (if (not (eolp)) (insert " "))
d83ee578
KH
1220 (or (octave-auto-fill)
1221 (forward-line 1)))))
f2727dfb
RS
1222 t)))
1223
1224\f
1225;;; Completions
1226(defun octave-initialize-completions ()
1227 "Create an alist for Octave completions."
1228 (if octave-completion-alist
1229 ()
1230 (setq octave-completion-alist
1231 (mapcar '(lambda (var) (cons var var))
1232 (append octave-reserved-words
1233 octave-text-functions
1234 octave-variables)))))
1235
1236(defun octave-complete-symbol ()
1237 "Perform completion on Octave symbol preceding point.
1238Compare that symbol against Octave's reserved words and builtin
1239variables."
1240 ;; This code taken from lisp-complete-symbol
1241 (interactive)
1242 (let* ((end (point))
1243 (beg (save-excursion (backward-sexp 1) (point)))
1244 (string (buffer-substring-no-properties beg end))
1245 (completion (try-completion string octave-completion-alist)))
1246 (cond ((eq completion t)) ; ???
1247 ((null completion)
1248 (message "Can't find completion for \"%s\"" string)
1249 (ding))
1250 ((not (string= string completion))
1251 (delete-region beg end)
1252 (insert completion))
1253 (t
1254 (let ((list (all-completions string octave-completion-alist))
1255 (conf (current-window-configuration)))
1256 ;; Taken from comint.el
a1506d29 1257 (message "Making completion list...")
f2727dfb 1258 (with-output-to-temp-buffer "*Completions*"
f5fab556 1259 (display-completion-list list string))
f2727dfb
RS
1260 (message "Hit space to flush")
1261 (let (key first)
1262 (if (save-excursion
1263 (set-buffer (get-buffer "*Completions*"))
1264 (setq key (read-key-sequence nil)
1265 first (aref key 0))
1266 (and (consp first) (consp (event-start first))
1267 (eq (window-buffer (posn-window (event-start
1268 first)))
1269 (get-buffer "*Completions*"))
1270 (eq (key-binding key) 'mouse-choose-completion)))
1271 (progn
1272 (mouse-choose-completion first)
1273 (set-window-configuration conf))
1274 (if (eq first ?\ )
1275 (set-window-configuration conf)
1276 (setq unread-command-events
1277 (listify-key-sequence key))))))))))
a1506d29 1278
f2727dfb
RS
1279\f
1280;;; Electric characters && friends
1281(defun octave-reindent-then-newline-and-indent ()
1282 "Reindent current Octave line, insert newline, and indent the new line.
1283If Abbrev mode is on, expand abbrevs first."
1284 (interactive)
1285 (if abbrev-mode (expand-abbrev))
1286 (if octave-blink-matching-block
1287 (octave-blink-matching-block-open))
1288 (save-excursion
1289 (delete-region (point) (progn (skip-chars-backward " \t") (point)))
1290 (indent-according-to-mode))
1291 (insert "\n")
1292 (indent-according-to-mode))
1293
1294(defun octave-electric-semi ()
1295 "Insert a semicolon in Octave mode.
d83ee578
KH
1296Maybe expand abbrevs and blink matching block open keywords.
1297Reindent the line of `octave-auto-indent' is non-nil.
1298Insert a newline if `octave-auto-newline' is non-nil."
f2727dfb
RS
1299 (interactive)
1300 (if (not (octave-not-in-string-or-comment-p))
1301 (insert ";")
1302 (if abbrev-mode (expand-abbrev))
1303 (if octave-blink-matching-block
1304 (octave-blink-matching-block-open))
d83ee578
KH
1305 (if octave-auto-indent
1306 (indent-according-to-mode))
f2727dfb
RS
1307 (insert ";")
1308 (if octave-auto-newline
1309 (newline-and-indent))))
1310
1311(defun octave-electric-space ()
1312 "Insert a space in Octave mode.
d83ee578
KH
1313Maybe expand abbrevs and blink matching block open keywords.
1314Reindent the line of `octave-auto-indent' is non-nil."
f2727dfb
RS
1315 (interactive)
1316 (setq last-command-char ? )
d9f9aa72
EZ
1317 (if (and octave-auto-indent
1318 (not (octave-not-in-string-or-comment-p)))
f2727dfb
RS
1319 (progn
1320 (indent-according-to-mode)
1321 (self-insert-command 1))
1322 (if abbrev-mode (expand-abbrev))
1323 (if octave-blink-matching-block
1324 (octave-blink-matching-block-open))
d83ee578
KH
1325 (if (and octave-auto-indent
1326 (save-excursion
1327 (skip-syntax-backward " ")
1328 (not (bolp))))
f2727dfb
RS
1329 (indent-according-to-mode))
1330 (self-insert-command 1)))
1331
1332(defun octave-abbrev-start ()
1333 "Start entering an Octave abbreviation.
1334If Abbrev mode is turned on, typing ` (grave accent) followed by ? or
1335\\[help-command] lists all Octave abbrevs. Any other key combination is
1336executed normally.
1337Note that all Octave mode abbrevs start with a grave accent."
1338 (interactive)
1339 (if (not abbrev-mode)
1340 (self-insert-command 1)
1341 (let (c)
1342 (insert last-command-char)
f8246027 1343 (if (if (featurep 'xemacs)
aa82f4fb
KH
1344 (or (eq (event-to-character (setq c (next-event))) ??)
1345 (eq (event-to-character c) help-char))
1346 (or (eq (setq c (read-event)) ??)
1347 (eq c help-char)))
1348 (let ((abbrev-table-name-list '(octave-abbrev-table)))
f2727dfb
RS
1349 (list-abbrevs))
1350 (setq unread-command-events (list c))))))
1351
1352(defun octave-insert-defun (name args vals)
1353 "Insert an Octave function skeleton.
1354Prompt for the function's name, arguments and return values (to be
1355entered without parens)."
1356 (interactive
1357 (list
1358 (read-from-minibuffer "Function name: "
1359 (substring (buffer-name) 0 -2))
1360 (read-from-minibuffer "Arguments: ")
1361 (read-from-minibuffer "Return values: ")))
1362 (let ((string (format "%s %s (%s)"
1363 (cond
1364 ((string-equal vals "")
1365 vals)
1366 ((string-match "[ ,]" vals)
1367 (concat " [" vals "] ="))
1368 (t
1369 (concat " " vals " =")))
1370 name
1371 args))
1372 (prefix octave-block-comment-start))
1373 (if (not (bobp)) (newline))
1374 (insert "function" string)
1375 (indent-according-to-mode)
1376 (newline 2)
1377 (insert prefix "usage: " string)
a1506d29 1378 (reindent-then-newline-and-indent)
f2727dfb 1379 (insert prefix)
a1506d29 1380 (reindent-then-newline-and-indent)
f2727dfb
RS
1381 (insert prefix)
1382 (indent-according-to-mode)
1383 (save-excursion
1384 (newline 2)
1385 (insert "endfunction")
1386 (indent-according-to-mode))))
a1506d29 1387
f2727dfb
RS
1388\f
1389;;; Menu
1390(defun octave-add-octave-menu ()
e22bbd48 1391 "Add the `Octave' menu to the menu bar in Octave mode."
a1506d29 1392 (require 'easymenu)
f2727dfb
RS
1393 (easy-menu-define octave-mode-menu-map octave-mode-map
1394 "Menu keymap for Octave mode." octave-mode-menu)
1395 (easy-menu-add octave-mode-menu-map octave-mode-map))
1396
1397\f
1398;;; Communication with the inferior Octave process
1399(defun octave-kill-process ()
1400 "Kill inferior Octave process and its buffer."
1401 (interactive)
1402 (if inferior-octave-process
1403 (progn
1404 (process-send-string inferior-octave-process "quit;\n")
1405 (accept-process-output inferior-octave-process)))
1406 (if inferior-octave-buffer
1407 (kill-buffer inferior-octave-buffer)))
1408
1409(defun octave-show-process-buffer ()
1410 "Make sure that `inferior-octave-buffer' is displayed."
1411 (interactive)
1412 (if (get-buffer inferior-octave-buffer)
1413 (display-buffer inferior-octave-buffer)
1414 (message "No buffer named %s" inferior-octave-buffer)))
1415
1416(defun octave-hide-process-buffer ()
1417 "Delete all windows that display `inferior-octave-buffer'."
1418 (interactive)
1419 (if (get-buffer inferior-octave-buffer)
1420 (delete-windows-on inferior-octave-buffer)
1421 (message "No buffer named %s" inferior-octave-buffer)))
1422
1423(defun octave-send-region (beg end)
1424 "Send current region to the inferior Octave process."
1425 (interactive "r")
a1506d29 1426 (inferior-octave t)
f2727dfb
RS
1427 (let ((proc inferior-octave-process)
1428 (string (buffer-substring-no-properties beg end))
1429 line)
1430 (save-excursion
1431 (set-buffer inferior-octave-buffer)
1432 (setq inferior-octave-output-list nil)
1433 (while (not (string-equal string ""))
1434 (if (string-match "\n" string)
1435 (setq line (substring string 0 (match-beginning 0))
1436 string (substring string (match-end 0)))
1437 (setq line string string ""))
1438 (setq inferior-octave-receive-in-progress t)
1439 (inferior-octave-send-list-and-digest (list (concat line "\n")))
1440 (while inferior-octave-receive-in-progress
1441 (accept-process-output proc))
1442 (insert-before-markers
1443 (mapconcat 'identity
1444 (append
1445 (if octave-send-echo-input (list line) (list ""))
1446 (mapcar 'inferior-octave-strip-ctrl-g
1447 inferior-octave-output-list)
1448 (list inferior-octave-output-string))
1449 "\n")))))
1450 (if octave-send-show-buffer
1451 (display-buffer inferior-octave-buffer)))
1452
1453(defun octave-send-block ()
a1506d29 1454 "Send current Octave block to the inferior Octave process."
f2727dfb
RS
1455 (interactive)
1456 (save-excursion
1457 (octave-mark-block)
1458 (octave-send-region (point) (mark))))
1459
1460(defun octave-send-defun ()
1461 "Send current Octave function to the inferior Octave process."
1462 (interactive)
1463 (save-excursion
1464 (octave-mark-defun)
1465 (octave-send-region (point) (mark))))
1466
1467(defun octave-send-line (&optional arg)
1468 "Send current Octave code line to the inferior Octave process.
1469With positive prefix ARG, send that many lines.
1470If `octave-send-line-auto-forward' is non-nil, go to the next unsent
1471code line."
1472 (interactive "P")
1473 (or arg (setq arg 1))
1474 (if (> arg 0)
1475 (let (beg end)
1476 (beginning-of-line)
1477 (setq beg (point))
1478 (octave-next-code-line (- arg 1))
1479 (end-of-line)
1480 (setq end (point))
1481 (if octave-send-line-auto-forward
1482 (octave-next-code-line 1))
1483 (octave-send-region beg end))))
1484
1485(defun octave-eval-print-last-sexp ()
1486 "Evaluate Octave sexp before point and print value into current buffer."
1487 (interactive)
1488 (inferior-octave t)
1489 (let ((standard-output (current-buffer))
1490 (print-escape-newlines nil)
1491 (opoint (point)))
1492 (terpri)
a1506d29 1493 (prin1
f2727dfb
RS
1494 (save-excursion
1495 (forward-sexp -1)
1496 (inferior-octave-send-list-and-digest
1497 (list (concat (buffer-substring-no-properties (point) opoint)
1498 "\n")))
1499 (mapconcat 'identity inferior-octave-output-list "\n")))
1500 (terpri)))
d1e49742 1501\f
d1e49742
RS
1502;;; Bug reporting
1503(defun octave-submit-bug-report ()
1504 "Submit a bug report on the Emacs Octave package via mail."
1505 (interactive)
1506 (require 'reporter)
1507 (and
1508 (y-or-n-p "Do you want to submit a bug report? ")
1509 (reporter-submit-bug-report
1510 octave-maintainer-address
1511 (concat "Emacs version " emacs-version)
1512 (list
d83ee578 1513 'octave-auto-indent
d1e49742
RS
1514 'octave-auto-newline
1515 'octave-blink-matching-block
1516 'octave-block-offset
1517 'octave-comment-char
1518 'octave-continuation-offset
1519 'octave-continuation-string
1520 'octave-help-files
d1e49742
RS
1521 'octave-send-echo-input
1522 'octave-send-line-auto-forward
1523 'octave-send-show-buffer))))
1524
1525;;; provide ourself
1526
e7017ef9 1527(provide 'octave-mod)
d1e49742 1528
e22bbd48 1529;; arch-tag: 05f1ce09-be87-4c00-803e-4919ffa26c23
d1e49742 1530;;; octave-mod.el ends here