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