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