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