Replace last-command-char with last-command-event.
[bpt/emacs.git] / lisp / progmodes / octave-mod.el
CommitLineData
092af6d8 1;;; octave-mod.el --- editing Octave source files under Emacs
f2727dfb 2
ae940284 3;; Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
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
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
cb3d3ec1 95 (string octave-comment-char ?\ )
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"))
490a8abe
GM
104;; FIXME: only use specific "end" tokens here to avoid confusion when "end"
105;; is used in indexing (the real fix is much more complex).
e7017ef9 106(defvar octave-end-keywords
490a8abe
GM
107 '("endfor" "endfunction" "endif" "endswitch" "end_try_catch"
108 "end_unwind_protect" "endwhile" "until"))
e7017ef9
RS
109
110(defvar octave-reserved-words
6e6d2764
KH
111 (append octave-begin-keywords
112 octave-else-keywords
113 octave-end-keywords
490a8abe 114 '("break" "continue" "end" "global" "persistent" "return"))
e7017ef9
RS
115 "Reserved words in Octave.")
116
117(defvar octave-text-functions
118 '("casesen" "cd" "chdir" "clear" "diary" "dir" "document" "echo"
490a8abe
GM
119 "edit_history" "format" "help" "history" "hold"
120 "load" "ls" "more" "run_history" "save" "type"
e7017ef9 121 "which" "who" "whos")
490a8abe 122 "Text functions in Octave.")
e7017ef9
RS
123
124(defvar octave-variables
490a8abe
GM
125 '("DEFAULT_EXEC_PATH" "DEFAULT_LOADPATH"
126 "EDITOR" "EXEC_PATH" "F_DUPFD" "F_GETFD" "F_GETFL" "F_SETFD"
127 "F_SETFL" "I" "IMAGE_PATH" "Inf" "J"
128 "NaN" "OCTAVE_VERSION" "O_APPEND" "O_CREAT" "O_EXCL"
e7017ef9
RS
129 "O_NONBLOCK" "O_RDONLY" "O_RDWR" "O_TRUNC" "O_WRONLY" "PAGER" "PS1"
130 "PS2" "PS4" "PWD" "SEEK_CUR" "SEEK_END" "SEEK_SET" "__F_DUPFD__"
131 "__F_GETFD__" "__F_GETFL__" "__F_SETFD__" "__F_SETFL__" "__I__"
132 "__Inf__" "__J__" "__NaN__" "__OCTAVE_VERSION__" "__O_APPEND__"
133 "__O_CREAT__" "__O_EXCL__" "__O_NONBLOCK__" "__O_RDONLY__"
134 "__O_RDWR__" "__O_TRUNC__" "__O_WRONLY__" "__PWD__" "__SEEK_CUR__"
135 "__SEEK_END__" "__SEEK_SET__" "__argv__" "__e__" "__eps__"
490a8abe 136 "__i__" "__inf__" "__j__" "__nan__" "__pi__"
e7017ef9
RS
137 "__program_invocation_name__" "__program_name__" "__realmax__"
138 "__realmin__" "__stderr__" "__stdin__" "__stdout__" "ans" "argv"
490a8abe
GM
139 "beep_on_error" "completion_append_char"
140 "crash_dumps_octave_core" "default_save_format"
141 "e" "echo_executing_commands" "eps"
142 "error_text" "gnuplot_binary" "history_file"
143 "history_size" "ignore_function_time_stamp"
144 "inf" "nan" "nargin" "output_max_field_width" "output_precision"
e7017ef9 145 "page_output_immediately" "page_screen_output" "pi"
e7017ef9 146 "print_answer_id_name" "print_empty_dimensions"
490a8abe
GM
147 "program_invocation_name" "program_name"
148 "realmax" "realmin" "return_last_computed_value" "save_precision"
149 "saving_history" "sighup_dumps_octave_core" "sigterm_dumps_octave_core"
e7017ef9
RS
150 "silent_functions" "split_long_rows" "stderr" "stdin" "stdout"
151 "string_fill_char" "struct_levels_to_print"
490a8abe 152 "suppress_verbose_help_message")
e7017ef9
RS
153 "Builtin variables in Octave.")
154
155(defvar octave-function-header-regexp
156 (concat "^\\s-*\\<\\(function\\)\\>"
157 "\\([^=;\n]*=[ \t]*\\|[ \t]*\\)\\(\\w+\\)\\>")
158 "Regexp to match an Octave function header.
159The string `function' and its name are given by the first and third
160parenthetical grouping.")
161
162(defvar octave-font-lock-keywords
163 (list
164 ;; Fontify all builtin keywords.
165 (cons (concat "\\<\\("
166 (mapconcat 'identity octave-reserved-words "\\|")
167 (mapconcat 'identity octave-text-functions "\\|")
168 "\\)\\>")
169 'font-lock-keyword-face)
170 ;; Fontify all builtin operators.
171 (cons "\\(&\\||\\|<=\\|>=\\|==\\|<\\|>\\|!=\\|!\\)"
cb41203e
GM
172 (if (boundp 'font-lock-builtin-face)
173 'font-lock-builtin-face
174 'font-lock-preprocessor-face))
e7017ef9
RS
175 ;; Fontify all builtin variables.
176 (cons (concat "\\<\\("
177 (mapconcat 'identity octave-variables "\\|")
178 "\\)\\>")
179 'font-lock-variable-name-face)
180 ;; Fontify all function declarations.
181 (list octave-function-header-regexp
182 '(1 font-lock-keyword-face)
183 '(3 font-lock-function-name-face nil t)))
184 "Additional Octave expressions to highlight.")
185
28d16ed3 186(defcustom inferior-octave-buffer "*Inferior Octave*"
e22bbd48 187 "Name of buffer for running an inferior Octave process."
28d16ed3
AS
188 :type 'string
189 :group 'octave-inferior)
e7017ef9
RS
190
191(defvar inferior-octave-process nil)
192\f
e22bbd48 193(defvar octave-mode-map
f2727dfb
RS
194 (let ((map (make-sparse-keymap)))
195 (define-key map "`" 'octave-abbrev-start)
196 (define-key map ";" 'octave-electric-semi)
197 (define-key map " " 'octave-electric-space)
198 (define-key map "\n" 'octave-reindent-then-newline-and-indent)
f2727dfb 199 (define-key map "\e;" 'octave-indent-for-comment)
a1506d29 200 (define-key map "\e\n" 'octave-indent-new-comment-line)
f2727dfb
RS
201 (define-key map "\e\t" 'octave-complete-symbol)
202 (define-key map "\M-\C-a" 'octave-beginning-of-defun)
203 (define-key map "\M-\C-e" 'octave-end-of-defun)
204 (define-key map "\M-\C-h" 'octave-mark-defun)
a1506d29 205 (define-key map "\M-\C-q" 'octave-indent-defun)
f2727dfb 206 (define-key map "\C-c;" 'octave-comment-region)
a1506d29 207 (define-key map "\C-c:" 'octave-uncomment-region)
f2727dfb
RS
208 (define-key map "\C-c\C-b" 'octave-submit-bug-report)
209 (define-key map "\C-c\C-p" 'octave-previous-code-line)
210 (define-key map "\C-c\C-n" 'octave-next-code-line)
211 (define-key map "\C-c\C-a" 'octave-beginning-of-line)
a1506d29 212 (define-key map "\C-c\C-e" 'octave-end-of-line)
f2727dfb
RS
213 (define-key map "\C-c\M-\C-n" 'octave-forward-block)
214 (define-key map "\C-c\M-\C-p" 'octave-backward-block)
215 (define-key map "\C-c\M-\C-u" 'octave-backward-up-block)
216 (define-key map "\C-c\M-\C-d" 'octave-down-block)
217 (define-key map "\C-c\M-\C-h" 'octave-mark-block)
218 (define-key map "\C-c]" 'octave-close-block)
34a463f1 219 (define-key map "\C-c\C-f" 'octave-insert-defun)
f2727dfb 220 (define-key map "\C-c\C-h" 'octave-help)
34a463f1
RS
221 (define-key map "\C-c\C-il" 'octave-send-line)
222 (define-key map "\C-c\C-ib" 'octave-send-block)
223 (define-key map "\C-c\C-if" 'octave-send-defun)
a1506d29 224 (define-key map "\C-c\C-ir" 'octave-send-region)
34a463f1
RS
225 (define-key map "\C-c\C-is" 'octave-show-process-buffer)
226 (define-key map "\C-c\C-ih" 'octave-hide-process-buffer)
227 (define-key map "\C-c\C-ik" 'octave-kill-process)
228 (define-key map "\C-c\C-i\C-l" 'octave-send-line)
229 (define-key map "\C-c\C-i\C-b" 'octave-send-block)
230 (define-key map "\C-c\C-i\C-f" 'octave-send-defun)
a1506d29 231 (define-key map "\C-c\C-i\C-r" 'octave-send-region)
34a463f1
RS
232 (define-key map "\C-c\C-i\C-s" 'octave-show-process-buffer)
233 (define-key map "\C-c\C-i\C-h" 'octave-hide-process-buffer)
234 (define-key map "\C-c\C-i\C-k" 'octave-kill-process)
e22bbd48
SM
235 map)
236 "Keymap used in Octave mode.")
237
f2727dfb
RS
238
239(defvar octave-mode-menu
e22bbd48 240 '("Octave"
67885e8c 241 ("Lines"
e22bbd48
SM
242 ["Previous Code Line" octave-previous-code-line t]
243 ["Next Code Line" octave-next-code-line t]
244 ["Begin of Continuation" octave-beginning-of-line t]
245 ["End of Continuation" octave-end-of-line t]
246 ["Split Line at Point" octave-indent-new-comment-line t])
67885e8c 247 ("Blocks"
e22bbd48
SM
248 ["Next Block" octave-forward-block t]
249 ["Previous Block" octave-backward-block t]
250 ["Down Block" octave-down-block t]
251 ["Up Block" octave-backward-up-block t]
252 ["Mark Block" octave-mark-block t]
253 ["Close Block" octave-close-block t])
67885e8c 254 ("Functions"
e22bbd48
SM
255 ["Begin of Function" octave-beginning-of-defun t]
256 ["End of Function" octave-end-of-defun t]
257 ["Mark Function" octave-mark-defun t]
258 ["Indent Function" octave-indent-defun t]
259 ["Insert Function" octave-insert-defun t])
260 "-"
67885e8c 261 ("Debug"
e22bbd48
SM
262 ["Send Current Line" octave-send-line t]
263 ["Send Current Block" octave-send-block t]
264 ["Send Current Function" octave-send-defun t]
265 ["Send Region" octave-send-region t]
266 ["Show Process Buffer" octave-show-process-buffer t]
267 ["Hide Process Buffer" octave-hide-process-buffer t]
268 ["Kill Process" octave-kill-process t])
269 "-"
270 ["Indent Line" indent-according-to-mode t]
271 ["Complete Symbol" octave-complete-symbol t]
272 "-"
273 ["Toggle Abbrev Mode" abbrev-mode t]
274 ["Toggle Auto-Fill Mode" auto-fill-mode t]
275 "-"
276 ["Submit Bug Report" octave-submit-bug-report t]
277 "-"
278 ["Describe Octave Mode" octave-describe-major-mode t]
279 ["Lookup Octave Index" octave-help t])
f2727dfb
RS
280 "Menu for Octave mode.")
281
cb3d3ec1 282(defvar octave-mode-syntax-table
f2727dfb
RS
283 (let ((table (make-syntax-table)))
284 (modify-syntax-entry ?\r " " table)
285 (modify-syntax-entry ?+ "." table)
286 (modify-syntax-entry ?- "." table)
287 (modify-syntax-entry ?= "." table)
288 (modify-syntax-entry ?* "." table)
289 (modify-syntax-entry ?/ "." table)
290 (modify-syntax-entry ?> "." 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)
7210c33f
SM
297 ;; Was "w" for abbrevs, but now that it's not necessary any more,
298 (modify-syntax-entry ?\` "." table)
f2727dfb
RS
299 (modify-syntax-entry ?\" "\"" table)
300 (modify-syntax-entry ?. "w" table)
301 (modify-syntax-entry ?_ "w" table)
cb3d3ec1 302 (modify-syntax-entry ?\% "<" table)
f2727dfb
RS
303 (modify-syntax-entry ?\# "<" table)
304 (modify-syntax-entry ?\n ">" table)
cb3d3ec1
SM
305 table)
306 "Syntax table in use in `octave-mode' buffers.")
f2727dfb 307
28d16ed3 308(defcustom octave-auto-indent nil
e22bbd48 309 "Non-nil means indent line after a semicolon or space in Octave mode."
28d16ed3 310 :type 'boolean
2454554e 311 :group 'octave)
d83ee578 312
28d16ed3 313(defcustom octave-auto-newline nil
e22bbd48 314 "Non-nil means automatically newline after a semicolon in Octave mode."
28d16ed3
AS
315 :type 'boolean
316 :group 'octave)
f2727dfb 317
28d16ed3 318(defcustom octave-blink-matching-block t
e22bbd48 319 "Control the blinking of matching Octave block keywords.
f2727dfb 320Non-nil means show matching begin of block when inserting a space,
28d16ed3
AS
321newline or semicolon after an else or end keyword."
322 :type 'boolean
323 :group 'octave)
324(defcustom octave-block-offset 2
e22bbd48 325 "Extra indentation applied to statements in Octave block structures."
28d16ed3
AS
326 :type 'integer
327 :group 'octave)
f2727dfb
RS
328
329(defvar octave-block-begin-regexp
330 (concat "\\<\\("
331 (mapconcat 'identity octave-begin-keywords "\\|")
332 "\\)\\>"))
333(defvar octave-block-else-regexp
334 (concat "\\<\\("
335 (mapconcat 'identity octave-else-keywords "\\|")
336 "\\)\\>"))
337(defvar octave-block-end-regexp
338 (concat "\\<\\("
339 (mapconcat 'identity octave-end-keywords "\\|")
340 "\\)\\>"))
341(defvar octave-block-begin-or-end-regexp
342 (concat octave-block-begin-regexp "\\|" octave-block-end-regexp))
343(defvar octave-block-else-or-end-regexp
344 (concat octave-block-else-regexp "\\|" octave-block-end-regexp))
490a8abe
GM
345;; FIXME: only use specific "end" tokens here to avoid confusion when "end"
346;; is used in indexing (the real fix is much more complex).
f2727dfb 347(defvar octave-block-match-alist
490a8abe
GM
348 '(("do" . ("until"))
349 ("for" . ("endfor"))
350 ("function" . ("endfunction"))
351 ("if" . ("else" "elseif" "endif"))
352 ("switch" . ("case" "otherwise" "endswitch"))
353 ("try" . ("catch" "end_try_catch"))
354 ("unwind_protect" . ("unwind_protect_cleanup" "end_unwind_protect"))
355 ("while" . ("endwhile")))
f2727dfb
RS
356 "Alist with Octave's matching block keywords.
357Has Octave's begin keywords as keys and a list of the matching else or
358end keywords as associated values.")
359
360(defvar octave-block-comment-start
361 (concat (make-string 2 octave-comment-char) " ")
362 "String to insert to start a new Octave comment on an empty line.")
363
28d16ed3 364(defcustom octave-continuation-offset 4
e22bbd48 365 "Extra indentation applied to Octave continuation lines."
28d16ed3
AS
366 :type 'integer
367 :group 'octave)
f2727dfb
RS
368(defvar octave-continuation-regexp
369 "[^#%\n]*\\(\\\\\\|\\.\\.\\.\\)\\s-*\\(\\s<.*\\)?$")
28d16ed3 370(defcustom octave-continuation-string "\\"
e22bbd48 371 "Character string used for Octave continuation lines. Normally \\."
28d16ed3
AS
372 :type 'string
373 :group 'octave)
f2727dfb
RS
374
375(defvar octave-completion-alist nil
376 "Alist of Octave symbols for completion in Octave mode.
377Each element looks like (VAR . VAR), where the car and cdr are the same
378symbol (an Octave command or variable name).
a1506d29 379Currently, only builtin variables can be completed.")
f2727dfb
RS
380
381(defvar octave-mode-imenu-generic-expression
382 (list
383 ;; Functions
384 (list nil octave-function-header-regexp 3))
385 "Imenu expression for Octave mode. See `imenu-generic-expression'.")
386
28d16ed3 387(defcustom octave-mode-hook nil
e22bbd48 388 "Hook to be run when Octave mode is started."
28d16ed3
AS
389 :type 'hook
390 :group 'octave)
391
392(defcustom octave-send-show-buffer t
e22bbd48 393 "Non-nil means display `inferior-octave-buffer' after sending to it."
28d16ed3
AS
394 :type 'boolean
395 :group 'octave)
396(defcustom octave-send-line-auto-forward t
e22bbd48 397 "Control auto-forward after sending to the inferior Octave process.
28d16ed3
AS
398Non-nil means always go to the next Octave code line after sending."
399 :type 'boolean
400 :group 'octave)
401(defcustom octave-send-echo-input t
e22bbd48 402 "Non-nil means echo input sent to the inferior Octave process."
28d16ed3
AS
403 :type 'boolean
404 :group 'octave)
f2727dfb
RS
405
406\f
407;;;###autoload
408(defun octave-mode ()
409 "Major mode for editing Octave code.
410
411This mode makes it easier to write Octave code by helping with
412indentation, doing some of the typing for you (with Abbrev mode) and by
e22bbd48 413showing keywords, comments, strings, etc.. in different faces (with
f2727dfb
RS
414Font Lock mode on terminals that support it).
415
416Octave itself is a high-level language, primarily intended for numerical
417computations. It provides a convenient command line interface for
418solving linear and nonlinear problems numerically. Function definitions
419can also be stored in files, and it can be used in a batch mode (which
420is why you need this mode!).
421
422The latest released version of Octave is always available via anonymous
490a8abe 423ftp from ftp.octave.org in the directory `/pub/octave'. Complete
f2727dfb
RS
424source and binaries for several popular systems are available.
425
426Type \\[list-abbrevs] to display the built-in abbrevs for Octave keywords.
427
428Keybindings
429===========
430
431\\{octave-mode-map}
432
433Variables you can use to customize Octave mode
434==============================================
435
e22bbd48 436`octave-auto-indent'
d83ee578
KH
437 Non-nil means indent current line after a semicolon or space.
438 Default is nil.
439
e22bbd48 440`octave-auto-newline'
f2727dfb
RS
441 Non-nil means auto-insert a newline and indent after a semicolon.
442 Default is nil.
443
e22bbd48 444`octave-blink-matching-block'
f2727dfb
RS
445 Non-nil means show matching begin of block when inserting a space,
446 newline or semicolon after an else or end keyword. Default is t.
447
e22bbd48 448`octave-block-offset'
f2727dfb
RS
449 Extra indentation applied to statements in block structures.
450 Default is 2.
451
e22bbd48 452`octave-continuation-offset'
f2727dfb
RS
453 Extra indentation applied to Octave continuation lines.
454 Default is 4.
455
e22bbd48 456`octave-continuation-string'
f2727dfb
RS
457 String used for Octave continuation lines.
458 Default is a backslash.
459
e22bbd48 460`octave-send-echo-input'
f2727dfb
RS
461 Non-nil means always display `inferior-octave-buffer' after sending a
462 command to the inferior Octave process.
463
e22bbd48 464`octave-send-line-auto-forward'
f2727dfb
RS
465 Non-nil means always go to the next unsent line of Octave code after
466 sending a line to the inferior Octave process.
467
e22bbd48 468`octave-send-echo-input'
f2727dfb
RS
469 Non-nil means echo input sent to the inferior Octave process.
470
471Turning on Octave mode runs the hook `octave-mode-hook'.
472
473To begin using this mode for all `.m' files that you edit, add the
474following lines to your `.emacs' file:
475
e22bbd48 476 (add-to-list 'auto-mode-alist '(\"\\\\.m\\\\'\" . octave-mode))
f2727dfb 477
490a8abe 478To automatically turn on the abbrev and auto-fill features,
f2727dfb
RS
479add the following lines to your `.emacs' file as well:
480
481 (add-hook 'octave-mode-hook
482 (lambda ()
483 (abbrev-mode 1)
e22bbd48 484 (auto-fill-mode 1)))
f2727dfb
RS
485
486To submit a problem report, enter \\[octave-submit-bug-report] from \
487an Octave mode buffer.
488This automatically sets up a mail buffer with version information
489already added. You just need to add a description of the problem,
490including a reproducible test case and send the message."
491 (interactive)
492 (kill-all-local-variables)
493
494 (use-local-map octave-mode-map)
495 (setq major-mode 'octave-mode)
496 (setq mode-name "Octave")
497 (setq local-abbrev-table octave-abbrev-table)
498 (set-syntax-table octave-mode-syntax-table)
a1506d29 499
f2727dfb
RS
500 (make-local-variable 'indent-line-function)
501 (setq indent-line-function 'octave-indent-line)
502
a1506d29 503 (make-local-variable 'comment-start)
f2727dfb
RS
504 (setq comment-start octave-comment-start)
505 (make-local-variable 'comment-end)
506 (setq comment-end "")
507 (make-local-variable 'comment-column)
a1506d29 508 (setq comment-column 32)
f2727dfb
RS
509 (make-local-variable 'comment-start-skip)
510 (setq comment-start-skip "\\s<+\\s-*")
511 (make-local-variable 'comment-indent-function)
512 (setq comment-indent-function 'octave-comment-indent)
513
514 (make-local-variable 'parse-sexp-ignore-comments)
515 (setq parse-sexp-ignore-comments t)
516 (make-local-variable 'paragraph-start)
517 (setq paragraph-start (concat "\\s-*$\\|" page-delimiter))
518 (make-local-variable 'paragraph-separate)
519 (setq paragraph-separate paragraph-start)
520 (make-local-variable 'paragraph-ignore-fill-prefix)
521 (setq paragraph-ignore-fill-prefix t)
522 (make-local-variable 'fill-paragraph-function)
523 (setq fill-paragraph-function 'octave-fill-paragraph)
524 (make-local-variable 'adaptive-fill-regexp)
525 (setq adaptive-fill-regexp nil)
526 (make-local-variable 'fill-column)
527 (setq fill-column 72)
528 (make-local-variable 'normal-auto-fill-function)
529 (setq normal-auto-fill-function 'octave-auto-fill)
530
531 (make-local-variable 'font-lock-defaults)
532 (setq font-lock-defaults '(octave-font-lock-keywords nil nil))
533
534 (make-local-variable 'imenu-generic-expression)
c0b08eb0
DL
535 (setq imenu-generic-expression octave-mode-imenu-generic-expression
536 imenu-case-fold-search nil)
f2727dfb
RS
537
538 (octave-add-octave-menu)
539 (octave-initialize-completions)
9a969196 540 (run-mode-hooks 'octave-mode-hook))
5d8137ab
SM
541
542(defun octave-help ()
543 "Get help on Octave symbols from the Octave info files.
544Look up symbol in the function, operator and variable indices of the info files."
545 (let ((info-lookup-mode 'octave-mode))
546 (call-interactively 'info-lookup-symbol)))
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)
5d8137ab 1262 (if (with-current-buffer (get-buffer "*Completions*")
f2727dfb
RS
1263 (setq key (read-key-sequence nil)
1264 first (aref key 0))
1265 (and (consp first) (consp (event-start first))
1266 (eq (window-buffer (posn-window (event-start
1267 first)))
1268 (get-buffer "*Completions*"))
1269 (eq (key-binding key) 'mouse-choose-completion)))
1270 (progn
1271 (mouse-choose-completion first)
1272 (set-window-configuration conf))
1273 (if (eq first ?\ )
1274 (set-window-configuration conf)
1275 (setq unread-command-events
1276 (listify-key-sequence key))))))))))
a1506d29 1277
f2727dfb
RS
1278\f
1279;;; Electric characters && friends
1280(defun octave-reindent-then-newline-and-indent ()
1281 "Reindent current Octave line, insert newline, and indent the new line.
1282If Abbrev mode is on, expand abbrevs first."
1283 (interactive)
1284 (if abbrev-mode (expand-abbrev))
1285 (if octave-blink-matching-block
1286 (octave-blink-matching-block-open))
1287 (save-excursion
1288 (delete-region (point) (progn (skip-chars-backward " \t") (point)))
1289 (indent-according-to-mode))
1290 (insert "\n")
1291 (indent-according-to-mode))
1292
1293(defun octave-electric-semi ()
1294 "Insert a semicolon in Octave mode.
d83ee578
KH
1295Maybe expand abbrevs and blink matching block open keywords.
1296Reindent the line of `octave-auto-indent' is non-nil.
1297Insert a newline if `octave-auto-newline' is non-nil."
f2727dfb
RS
1298 (interactive)
1299 (if (not (octave-not-in-string-or-comment-p))
1300 (insert ";")
1301 (if abbrev-mode (expand-abbrev))
1302 (if octave-blink-matching-block
1303 (octave-blink-matching-block-open))
d83ee578
KH
1304 (if octave-auto-indent
1305 (indent-according-to-mode))
f2727dfb
RS
1306 (insert ";")
1307 (if octave-auto-newline
1308 (newline-and-indent))))
1309
1310(defun octave-electric-space ()
1311 "Insert a space in Octave mode.
d83ee578
KH
1312Maybe expand abbrevs and blink matching block open keywords.
1313Reindent the line of `octave-auto-indent' is non-nil."
f2727dfb 1314 (interactive)
1ba983e8 1315 (setq last-command-event ? )
d9f9aa72
EZ
1316 (if (and octave-auto-indent
1317 (not (octave-not-in-string-or-comment-p)))
f2727dfb
RS
1318 (progn
1319 (indent-according-to-mode)
1320 (self-insert-command 1))
1321 (if abbrev-mode (expand-abbrev))
1322 (if octave-blink-matching-block
1323 (octave-blink-matching-block-open))
d83ee578
KH
1324 (if (and octave-auto-indent
1325 (save-excursion
1326 (skip-syntax-backward " ")
1327 (not (bolp))))
f2727dfb
RS
1328 (indent-according-to-mode))
1329 (self-insert-command 1)))
1330
1331(defun octave-abbrev-start ()
1332 "Start entering an Octave abbreviation.
1333If Abbrev mode is turned on, typing ` (grave accent) followed by ? or
1334\\[help-command] lists all Octave abbrevs. Any other key combination is
1335executed normally.
1336Note that all Octave mode abbrevs start with a grave accent."
1337 (interactive)
1338 (if (not abbrev-mode)
1339 (self-insert-command 1)
1340 (let (c)
1ba983e8 1341 (insert last-command-event)
f8246027 1342 (if (if (featurep 'xemacs)
aa82f4fb
KH
1343 (or (eq (event-to-character (setq c (next-event))) ??)
1344 (eq (event-to-character c) help-char))
1345 (or (eq (setq c (read-event)) ??)
1346 (eq c help-char)))
1347 (let ((abbrev-table-name-list '(octave-abbrev-table)))
f2727dfb
RS
1348 (list-abbrevs))
1349 (setq unread-command-events (list c))))))
1350
1351(defun octave-insert-defun (name args vals)
1352 "Insert an Octave function skeleton.
1353Prompt for the function's name, arguments and return values (to be
1354entered without parens)."
1355 (interactive
1356 (list
1357 (read-from-minibuffer "Function name: "
1358 (substring (buffer-name) 0 -2))
1359 (read-from-minibuffer "Arguments: ")
1360 (read-from-minibuffer "Return values: ")))
1361 (let ((string (format "%s %s (%s)"
1362 (cond
1363 ((string-equal vals "")
1364 vals)
1365 ((string-match "[ ,]" vals)
1366 (concat " [" vals "] ="))
1367 (t
1368 (concat " " vals " =")))
1369 name
1370 args))
1371 (prefix octave-block-comment-start))
1372 (if (not (bobp)) (newline))
1373 (insert "function" string)
1374 (indent-according-to-mode)
1375 (newline 2)
1376 (insert prefix "usage: " string)
a1506d29 1377 (reindent-then-newline-and-indent)
f2727dfb 1378 (insert prefix)
a1506d29 1379 (reindent-then-newline-and-indent)
f2727dfb
RS
1380 (insert prefix)
1381 (indent-according-to-mode)
1382 (save-excursion
1383 (newline 2)
1384 (insert "endfunction")
1385 (indent-according-to-mode))))
a1506d29 1386
f2727dfb
RS
1387\f
1388;;; Menu
1389(defun octave-add-octave-menu ()
e22bbd48 1390 "Add the `Octave' menu to the menu bar in Octave mode."
a1506d29 1391 (require 'easymenu)
f2727dfb
RS
1392 (easy-menu-define octave-mode-menu-map octave-mode-map
1393 "Menu keymap for Octave mode." octave-mode-menu)
1394 (easy-menu-add octave-mode-menu-map octave-mode-map))
1395
1396\f
1397;;; Communication with the inferior Octave process
1398(defun octave-kill-process ()
1399 "Kill inferior Octave process and its buffer."
1400 (interactive)
1401 (if inferior-octave-process
1402 (progn
1403 (process-send-string inferior-octave-process "quit;\n")
1404 (accept-process-output inferior-octave-process)))
1405 (if inferior-octave-buffer
1406 (kill-buffer inferior-octave-buffer)))
1407
1408(defun octave-show-process-buffer ()
1409 "Make sure that `inferior-octave-buffer' is displayed."
1410 (interactive)
1411 (if (get-buffer inferior-octave-buffer)
1412 (display-buffer inferior-octave-buffer)
1413 (message "No buffer named %s" inferior-octave-buffer)))
1414
1415(defun octave-hide-process-buffer ()
1416 "Delete all windows that display `inferior-octave-buffer'."
1417 (interactive)
1418 (if (get-buffer inferior-octave-buffer)
1419 (delete-windows-on inferior-octave-buffer)
1420 (message "No buffer named %s" inferior-octave-buffer)))
1421
1422(defun octave-send-region (beg end)
1423 "Send current region to the inferior Octave process."
1424 (interactive "r")
a1506d29 1425 (inferior-octave t)
f2727dfb
RS
1426 (let ((proc inferior-octave-process)
1427 (string (buffer-substring-no-properties beg end))
1428 line)
5d8137ab 1429 (with-current-buffer inferior-octave-buffer
f2727dfb
RS
1430 (setq inferior-octave-output-list nil)
1431 (while (not (string-equal string ""))
1432 (if (string-match "\n" string)
1433 (setq line (substring string 0 (match-beginning 0))
1434 string (substring string (match-end 0)))
1435 (setq line string string ""))
1436 (setq inferior-octave-receive-in-progress t)
1437 (inferior-octave-send-list-and-digest (list (concat line "\n")))
1438 (while inferior-octave-receive-in-progress
1439 (accept-process-output proc))
1440 (insert-before-markers
1441 (mapconcat 'identity
1442 (append
1443 (if octave-send-echo-input (list line) (list ""))
1444 (mapcar 'inferior-octave-strip-ctrl-g
1445 inferior-octave-output-list)
1446 (list inferior-octave-output-string))
1447 "\n")))))
1448 (if octave-send-show-buffer
1449 (display-buffer inferior-octave-buffer)))
1450
1451(defun octave-send-block ()
a1506d29 1452 "Send current Octave block to the inferior Octave process."
f2727dfb
RS
1453 (interactive)
1454 (save-excursion
1455 (octave-mark-block)
1456 (octave-send-region (point) (mark))))
1457
1458(defun octave-send-defun ()
1459 "Send current Octave function to the inferior Octave process."
1460 (interactive)
1461 (save-excursion
1462 (octave-mark-defun)
1463 (octave-send-region (point) (mark))))
1464
1465(defun octave-send-line (&optional arg)
1466 "Send current Octave code line to the inferior Octave process.
1467With positive prefix ARG, send that many lines.
1468If `octave-send-line-auto-forward' is non-nil, go to the next unsent
1469code line."
1470 (interactive "P")
1471 (or arg (setq arg 1))
1472 (if (> arg 0)
1473 (let (beg end)
1474 (beginning-of-line)
1475 (setq beg (point))
1476 (octave-next-code-line (- arg 1))
1477 (end-of-line)
1478 (setq end (point))
1479 (if octave-send-line-auto-forward
1480 (octave-next-code-line 1))
1481 (octave-send-region beg end))))
1482
1483(defun octave-eval-print-last-sexp ()
1484 "Evaluate Octave sexp before point and print value into current buffer."
1485 (interactive)
1486 (inferior-octave t)
1487 (let ((standard-output (current-buffer))
1488 (print-escape-newlines nil)
1489 (opoint (point)))
1490 (terpri)
a1506d29 1491 (prin1
f2727dfb
RS
1492 (save-excursion
1493 (forward-sexp -1)
1494 (inferior-octave-send-list-and-digest
1495 (list (concat (buffer-substring-no-properties (point) opoint)
1496 "\n")))
1497 (mapconcat 'identity inferior-octave-output-list "\n")))
1498 (terpri)))
d1e49742 1499\f
d1e49742
RS
1500;;; Bug reporting
1501(defun octave-submit-bug-report ()
1502 "Submit a bug report on the Emacs Octave package via mail."
1503 (interactive)
1504 (require 'reporter)
1505 (and
1506 (y-or-n-p "Do you want to submit a bug report? ")
1507 (reporter-submit-bug-report
1508 octave-maintainer-address
1509 (concat "Emacs version " emacs-version)
1510 (list
d83ee578 1511 'octave-auto-indent
d1e49742
RS
1512 'octave-auto-newline
1513 'octave-blink-matching-block
1514 'octave-block-offset
1515 'octave-comment-char
1516 'octave-continuation-offset
1517 'octave-continuation-string
d1e49742
RS
1518 'octave-send-echo-input
1519 'octave-send-line-auto-forward
1520 'octave-send-show-buffer))))
1521
5d8137ab 1522;; provide ourself
d1e49742 1523
e7017ef9 1524(provide 'octave-mod)
d1e49742 1525
e22bbd48 1526;; arch-tag: 05f1ce09-be87-4c00-803e-4919ffa26c23
d1e49742 1527;;; octave-mod.el ends here