]> git.eshelyaron.com Git - emacs.git/commitdiff
Initial revision
authorRichard M. Stallman <rms@gnu.org>
Tue, 21 Jan 1997 00:29:57 +0000 (00:29 +0000)
committerRichard M. Stallman <rms@gnu.org>
Tue, 21 Jan 1997 00:29:57 +0000 (00:29 +0000)
lisp/progmodes/octave-mod.el [new file with mode: 0644]

diff --git a/lisp/progmodes/octave-mod.el b/lisp/progmodes/octave-mod.el
new file mode 100644 (file)
index 0000000..d640154
--- /dev/null
@@ -0,0 +1,1227 @@
+;; octave-mod.el --- editing Octave source files under Emacs
+
+;;; Copyright (C) 1997 Free Software Foundation, Inc.
+
+;; Author: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at>
+;; Author: John Eaton <jwe@bevo.che.wisc.edu>
+;; Maintainer: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at>
+;; Keywords: languages
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'octave)
+
+;; Keep the debugger quiet
+(eval-when-compile (load "octave-inf"))
+
+(defvar octave-mode-map nil
+  "Keymap used in Octave mode.")
+(if octave-mode-map
+    ()
+  (let ((map (make-sparse-keymap)))
+    (define-key map "`" 'octave-abbrev-start)
+    (define-key map ";" 'octave-electric-semi)
+    (define-key map " " 'octave-electric-space)
+    (define-key map "\n" 'octave-reindent-then-newline-and-indent)
+    (define-key map "\t" 'indent-according-to-mode)
+    (define-key map "\e;" 'octave-indent-for-comment)
+    (define-key map "\e\n" 'octave-indent-new-comment-line)  
+    (define-key map "\e\t" 'octave-complete-symbol)
+    (define-key map "\M-\C-a" 'octave-beginning-of-defun)
+    (define-key map "\M-\C-e" 'octave-end-of-defun)
+    (define-key map "\M-\C-h" 'octave-mark-defun)
+    (define-key map "\M-\C-q" 'octave-indent-defun)  
+    (define-key map "\C-c;" 'octave-comment-region)
+    (define-key map "\C-c:" 'octave-uncomment-region)  
+    (define-key map "\C-c\C-b" 'octave-submit-bug-report)
+    (define-key map "\C-c\C-p" 'octave-previous-code-line)
+    (define-key map "\C-c\C-n" 'octave-next-code-line)
+    (define-key map "\C-c\C-a" 'octave-beginning-of-line)
+    (define-key map "\C-c\C-e" 'octave-end-of-line)  
+    (define-key map "\C-c\M-\C-n" 'octave-forward-block)
+    (define-key map "\C-c\M-\C-p" 'octave-backward-block)
+    (define-key map "\C-c\M-\C-u" 'octave-backward-up-block)
+    (define-key map "\C-c\M-\C-d" 'octave-down-block)
+    (define-key map "\C-c\M-\C-h" 'octave-mark-block)
+    (define-key map "\C-c]" 'octave-close-block)
+    (define-key map "\C-cf" 'octave-insert-defun)
+    (define-key map "\C-c\C-h" 'octave-help)
+    (define-key map "\C-cil" 'octave-send-line)
+    (define-key map "\C-cib" 'octave-send-block)
+    (define-key map "\C-cif" 'octave-send-defun)
+    (define-key map "\C-cir" 'octave-send-region)  
+    (define-key map "\C-cis" 'octave-show-process-buffer)
+    (define-key map "\C-cih" 'octave-hide-process-buffer)
+    (define-key map "\C-cik" 'octave-kill-process)
+    (setq octave-mode-map map)))
+
+(defvar octave-mode-menu
+  (list "Octave"
+       (list "Lines"
+             ["Previous Code Line"     octave-previous-code-line t]
+             ["Next Code Line"         octave-next-code-line t]
+             ["Begin of Continuation"  octave-beginning-of-line t]
+             ["End of Continuation"    octave-end-of-line t]
+             ["Split Line at Point"    octave-indent-new-comment-line t])
+       (list "Blocks"
+             ["Next Block"             octave-forward-block t]
+             ["Previous Block"         octave-backward-block t]
+             ["Down Block"             octave-down-block t]
+             ["Up Block"               octave-backward-up-block t]
+             ["Mark Block"             octave-mark-block t]
+             ["Close Block"            octave-close-block t])
+       (list "Functions"
+             ["Begin of Function"      octave-beginning-of-defun t]
+             ["End of Function"        octave-end-of-defun t]
+             ["Mark Function"          octave-mark-defun t]
+             ["Indent Function"        octave-indent-defun t]
+             ["Insert Function"        octave-insert-defun t])
+       "-"
+       (list "Debug"
+             ["Send Current Line"      octave-send-line t]
+             ["Send Current Block"     octave-send-block t]
+             ["Send Current Function"  octave-send-defun t]
+             ["Send Region"            octave-send-region t]
+             ["Show Process Buffer"    octave-show-process-buffer t]
+             ["Hide Process Buffer"    octave-hide-process-buffer t]
+             ["Kill Process"           octave-kill-process t])
+       "-"
+       ["Indent Line"                  indent-according-to-mode t]
+       ["Complete Symbol"              octave-complete-symbol t]
+       "-"
+       ["Toggle Abbrev Mode"           abbrev-mode t]
+       ["Toggle Auto-Fill Mode"        auto-fill-mode t]
+       "-"
+       ["Submit Bug Report"            octave-submit-bug-report t]
+       "-"
+       ["Describe Octave Mode"         octave-describe-major-mode t]
+       ["Lookup Octave Index"          octave-help t])
+  "Menu for Octave mode.")
+
+(defvar octave-mode-syntax-table nil
+  "Syntax table in use in octave-mode buffers.")
+(if octave-mode-syntax-table
+    ()
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?\r " "  table)
+    (modify-syntax-entry ?+ "."   table)
+    (modify-syntax-entry ?- "."   table)
+    (modify-syntax-entry ?= "."   table)
+    (modify-syntax-entry ?* "."   table)
+    (modify-syntax-entry ?/ "."   table)
+    (modify-syntax-entry ?> "."   table)
+    (modify-syntax-entry ?< "."   table)
+    (modify-syntax-entry ?& "."   table)
+    (modify-syntax-entry ?| "."   table)
+    (modify-syntax-entry ?! "."   table)
+    (modify-syntax-entry ?\\ "\\" table)
+    (modify-syntax-entry ?\' "."  table)
+    (modify-syntax-entry ?\` "w"  table)
+    (modify-syntax-entry ?\" "\"" table)
+    (modify-syntax-entry ?. "w"   table)
+    (modify-syntax-entry ?_ "w"   table)
+    (modify-syntax-entry ?\% "."  table)
+    (modify-syntax-entry ?\# "<"  table)
+    (modify-syntax-entry ?\n ">"  table)
+    (setq octave-mode-syntax-table table)))
+
+(defvar octave-auto-newline nil
+  "*Non-nil means automatically newline after a semicolon in Octave mode.")
+
+(defvar octave-blink-matching-block t
+  "*Control the blinking of matching Octave block keywords.
+Non-nil means show matching begin of block when inserting a space,
+newline or semicolon after an else or end keyword.")
+(defvar octave-block-offset 2
+  "*Extra indentation applied to statements in Octave block structures.")
+
+(defvar octave-block-begin-regexp
+  (concat "\\<\\("
+         (mapconcat 'identity octave-begin-keywords "\\|")
+         "\\)\\>"))
+(defvar octave-block-else-regexp
+  (concat "\\<\\("
+         (mapconcat 'identity octave-else-keywords "\\|")
+         "\\)\\>"))
+(defvar octave-block-end-regexp
+  (concat "\\<\\("
+         (mapconcat 'identity octave-end-keywords "\\|")
+         "\\)\\>"))
+(defvar octave-block-begin-or-end-regexp
+  (concat octave-block-begin-regexp "\\|" octave-block-end-regexp))
+(defvar octave-block-else-or-end-regexp
+  (concat octave-block-else-regexp "\\|" octave-block-end-regexp))
+(defvar octave-block-match-alist
+  '(("for" . ("end" "endfor"))
+    ("function" . ("end" "endfunction"))
+    ("if" . ("else" "elseif" "end" "endif"))
+    ("try" . ("catch" "end" "end_try_catch"))
+    ("unwind_protect" . ("unwind_protect_cleanup" "end"
+                        "end_unwind_protect"))
+    ("while" . ("end" "endwhile")))
+  "Alist with Octave's matching block keywords.
+Has Octave's begin keywords as keys and a list of the matching else or
+end keywords as associated values.")
+
+(defvar octave-block-comment-start
+  (concat (make-string 2 octave-comment-char) " ")
+  "String to insert to start a new Octave comment on an empty line.")
+
+(defvar octave-continuation-offset 4
+  "*Extra indentation applied to Octave continuation lines.")
+(defvar octave-continuation-regexp
+  "[^#%\n]*\\(\\\\\\|\\.\\.\\.\\)\\s-*\\(\\s<.*\\)?$")
+(defvar octave-continuation-string "\\"
+  "*Character string used for Octave continuation lines.  Normally \\.")
+
+(defvar octave-completion-alist nil
+  "Alist of Octave symbols for completion in Octave mode.
+Each element looks like (VAR . VAR), where the car and cdr are the same
+symbol (an Octave command or variable name).
+Currently, only builtin variables can be completed.") 
+
+(defvar octave-mode-imenu-generic-expression
+  (list
+   ;; Functions
+   (list nil octave-function-header-regexp 3))
+  "Imenu expression for Octave mode.  See `imenu-generic-expression'.")
+
+(defvar octave-mode-startup-message t
+  "*Nil means do not display the Octave mode startup message.")
+
+(defvar octave-mode-hook nil
+  "*Hook to be run when Octave mode is started.")
+
+(defvar octave-send-show-buffer t
+  "*Non-nil means display `inferior-octave-buffer' after sending to it.")
+(defvar octave-send-line-auto-forward t
+  "*Control auto-forward after sending to the inferior Octave process.
+Non-nil means always go to the next Octave code line after sending.")
+(defvar octave-send-echo-input t
+  "*Non-nil means echo input sent to the inferior Octave process.")
+
+\f
+;;;###autoload
+(defun octave-mode ()
+  "Major mode for editing Octave code.
+
+This mode makes it easier to write Octave code by helping with
+indentation, doing some of the typing for you (with Abbrev mode) and by
+showing keywords, comments, strings, etc. in different faces (with
+Font Lock mode on terminals that support it).
+
+Octave itself is a high-level language, primarily intended for numerical
+computations.  It provides a convenient command line interface for
+solving linear and nonlinear problems numerically.  Function definitions
+can also be stored in files, and it can be used in a batch mode (which
+is why you need this mode!).
+
+The latest released version of Octave is always available via anonymous
+ftp from bevo.che.wisc.edu in the directory `/pub/octave'.  Complete
+source and binaries for several popular systems are available.
+
+Type \\[list-abbrevs] to display the built-in abbrevs for Octave keywords.
+
+Keybindings
+===========
+
+\\{octave-mode-map}
+
+Variables you can use to customize Octave mode
+==============================================
+
+octave-auto-newline
+  Non-nil means auto-insert a newline and indent after a semicolon.
+  Default is nil.
+
+octave-blink-matching-block
+  Non-nil means show matching begin of block when inserting a space,
+  newline or semicolon after an else or end keyword.  Default is t.
+
+octave-block-offset
+  Extra indentation applied to statements in block structures.
+  Default is 2.
+
+octave-continuation-offset
+  Extra indentation applied to Octave continuation lines.
+  Default is 4.
+
+octave-continuation-string
+  String used for Octave continuation lines.
+  Default is a backslash.
+
+octave-mode-startup-message
+  Nil means do not display the Octave mode startup message.
+  Default is t.
+
+octave-send-echo-input
+  Non-nil means always display `inferior-octave-buffer' after sending a
+  command to the inferior Octave process.
+
+octave-send-line-auto-forward
+  Non-nil means always go to the next unsent line of Octave code after
+  sending a line to the inferior Octave process.
+
+octave-send-echo-input
+  Non-nil means echo input sent to the inferior Octave process.
+
+Turning on Octave mode runs the hook `octave-mode-hook'.
+
+To begin using this mode for all `.m' files that you edit, add the
+following lines to your `.emacs' file:
+
+  (autoload 'octave-mode \"octave-mod\" nil t)
+  (setq auto-mode-alist
+        (cons '(\"\\\\.m$\" . octave-mode) auto-mode-alist))
+
+To automatically turn on the abbrev, auto-fill and font-lock features,
+add the following lines to your `.emacs' file as well:
+
+  (add-hook 'octave-mode-hook
+           (lambda ()
+             (abbrev-mode 1)
+             (auto-fill-mode 1)
+             (if (eq window-system 'x)
+                 (font-lock-mode 1))))
+
+To submit a problem report, enter \\[octave-submit-bug-report] from \
+an Octave mode buffer.
+This automatically sets up a mail buffer with version information
+already added.  You just need to add a description of the problem,
+including a reproducible test case and send the message."
+  (interactive)
+  (kill-all-local-variables)
+
+  (use-local-map octave-mode-map)
+  (setq major-mode 'octave-mode)
+  (setq mode-name "Octave")
+  (setq local-abbrev-table octave-abbrev-table)
+  (set-syntax-table octave-mode-syntax-table)
+  
+  (make-local-variable 'indent-line-function)
+  (setq indent-line-function 'octave-indent-line)
+
+  (make-local-variable 'comment-start)  
+  (setq comment-start octave-comment-start)
+  (make-local-variable 'comment-end)
+  (setq comment-end "")
+  (make-local-variable 'comment-column)
+  (setq comment-column 32)    
+  (make-local-variable 'comment-start-skip)
+  (setq comment-start-skip "\\s<+\\s-*")
+  (make-local-variable 'comment-indent-function)
+  (setq comment-indent-function 'octave-comment-indent)
+
+  (make-local-variable 'parse-sexp-ignore-comments)
+  (setq parse-sexp-ignore-comments t)
+  (make-local-variable 'paragraph-start)
+  (setq paragraph-start (concat "\\s-*$\\|" page-delimiter))
+  (make-local-variable 'paragraph-separate)
+  (setq paragraph-separate paragraph-start)
+  (make-local-variable 'paragraph-ignore-fill-prefix)
+  (setq paragraph-ignore-fill-prefix t)
+  (make-local-variable 'fill-paragraph-function)
+  (setq fill-paragraph-function 'octave-fill-paragraph)
+  (make-local-variable 'adaptive-fill-regexp)
+  (setq adaptive-fill-regexp nil)
+  (make-local-variable 'fill-column)
+  (setq fill-column 72)
+  (make-local-variable 'normal-auto-fill-function)
+  (setq normal-auto-fill-function 'octave-auto-fill)
+
+  (make-local-variable 'font-lock-defaults)
+  (setq font-lock-defaults '(octave-font-lock-keywords nil nil))
+
+  (make-local-variable 'imenu-generic-expression)
+  (setq imenu-generic-expression octave-mode-imenu-generic-expression)
+
+  (octave-add-octave-menu)
+  (octave-initialize-completions)
+  (run-hooks 'octave-mode-hook)
+  (if octave-mode-startup-message
+      (message "Octave mode %s.  Bugs to %s"
+              octave-version octave-maintainer-address)))
+
+\f
+;;; Miscellaneous useful functions
+(defun octave-describe-major-mode ()
+  "Describe the current major mode."
+  (interactive)
+  (describe-function major-mode))
+
+(defun octave-point (position)
+  "Returns the value of point at certain positions." 
+  (save-excursion
+    (cond
+     ((eq position 'bol)  (beginning-of-line))
+     ((eq position 'eol)  (end-of-line))
+     ((eq position 'boi)  (back-to-indentation))
+     ((eq position 'bonl) (forward-line 1))
+     ((eq position 'bopl) (forward-line -1))
+     (t (error "unknown buffer position requested: %s" position)))
+    (point)))
+
+(defsubst octave-in-comment-p ()
+  "Returns t if point is inside an Octave comment, nil otherwise."
+  (interactive)
+  (save-excursion
+    (nth 4 (parse-partial-sexp (octave-point 'bol) (point)))))
+
+(defsubst octave-in-string-p ()
+  "Returns t if point is inside an Octave string, nil otherwise."
+  (interactive)
+  (save-excursion
+    (nth 3 (parse-partial-sexp (octave-point 'bol) (point)))))
+
+(defsubst octave-not-in-string-or-comment-p ()
+  "Returns t iff point is not inside an Octave string or comment."
+  (let ((pps (parse-partial-sexp (octave-point 'bol) (point))))
+    (not (or (nth 3 pps) (nth 4 pps)))))
+
+(defun octave-in-block-p ()
+  "Returns t if point is inside an Octave block, nil otherwise.
+The block is taken to start at the first letter of the begin keyword and
+to end after the end keyword."
+  (let ((pos (point)))
+    (save-excursion
+      (condition-case nil
+         (progn
+           (skip-syntax-forward "w")
+           (octave-up-block -1)
+           (octave-forward-block)
+           t)
+       (error nil))
+      (< pos (point)))))
+
+(defun octave-in-defun-p ()
+  "Returns t iff point is inside an Octave function declaration.
+The function is taken to start at the `f' of `function' and to end after
+the end keyword."
+  (let ((pos (point)))
+    (save-excursion
+      (or (and (looking-at "\\<function\\>")
+              (octave-not-in-string-or-comment-p))
+         (and (octave-beginning-of-defun)
+              (condition-case nil
+                  (progn
+                    (octave-forward-block)
+                    t)
+                (error nil))
+              (< pos (point)))))))
+
+;;; Comments
+(defun octave-comment-region (beg end &optional arg)
+  "Comment or uncomment each line in the region as Octave code.
+See `comment-region'."
+  (interactive "r\nP")
+  (let ((comment-start (char-to-string octave-comment-char)))
+    (comment-region beg end arg)))
+  
+(defun octave-uncomment-region (beg end &optional arg)
+  "Uncomment each line in the region as Octave code."
+  (interactive "r\nP")
+  (or arg (setq arg 1))
+  (octave-comment-region beg end (- arg)))
+
+\f
+;;; Indentation
+(defun calculate-octave-indent ()
+  "Return appropriate indentation for current line as Octave code.
+Returns an integer (the column to indent to) unless the line is a
+comment line with fixed goal golumn.  In that case, returns a list whose
+car is the column to indent to, and whose cdr is the current indentation
+level."
+  (let ((is-continuation-line
+        (save-excursion
+          (if (zerop (octave-previous-code-line))
+              (looking-at octave-continuation-regexp))))
+       (icol 0))
+    (save-excursion
+      (beginning-of-line)
+      ;; If we can move backward out one level of parentheses, take 1
+      ;; plus the indentation of that parenthesis.  Otherwise, go back
+      ;; to the beginning of the previous code line, and compute the
+      ;; offset this line gives.
+      (if (condition-case nil
+             (progn
+               (up-list -1)
+               t)
+           (error nil))
+         (setq icol (+ 1 (current-column)))
+       (if (zerop (octave-previous-code-line))
+           (progn
+             (octave-beginning-of-line)
+             (back-to-indentation)
+             (setq icol (current-column))
+             (let ((bot (point))
+                   (eol (octave-point 'eol)))
+               (while (< (point) eol)
+                 (if (octave-not-in-string-or-comment-p)
+                     (cond
+                      ((looking-at octave-block-begin-regexp)
+                       (setq icol (+ icol octave-block-offset)))
+                      ((looking-at octave-block-else-regexp)
+                       (if (= bot (point))
+                           (setq icol (+ icol octave-block-offset))))
+                      ((looking-at octave-block-end-regexp)
+                       (if (not (= bot (point)))
+                           (setq icol (- icol octave-block-offset))))))
+                 (forward-char)))
+             (if is-continuation-line
+                 (setq icol (+ icol octave-continuation-offset)))))))
+    (save-excursion
+      (back-to-indentation)
+      (cond
+       ((and (or (looking-at octave-block-else-regexp)
+                (looking-at octave-block-end-regexp))
+            (octave-not-in-string-or-comment-p))
+       (setq icol (- icol octave-block-offset)))
+       ((looking-at "\\s<\\s<\\s<\\S<")
+       (setq icol (list 0 icol)))
+       ((looking-at "\\s<\\S<")
+       (setq icol (list comment-column icol)))))
+    icol))
+
+(defun octave-comment-indent ()
+  (if (looking-at "\\s<\\s<\\s<")
+      0
+    (if (looking-at "\\s<\\s<")
+       (calculate-octave-indent)
+      (skip-syntax-backward " ")
+      (max (if (bolp) 0 (+ (current-column)))
+          comment-column))))
+
+(defun octave-indent-for-comment ()
+  "Maybe insert and indent an Octave comment.
+If there is no comment already on this line, create a code-level comment
+(started by two comment characters) if the line is empty, or an in-line
+comment (started by one comment character) otherwise. 
+Point is left after the start of the comment which is properly aligned."
+  (interactive)
+  (indent-for-comment)
+  (indent-according-to-mode))
+
+(defun octave-indent-line (&optional arg)
+  "Indent current line as Octave code.
+With optional ARG, use this as offset unless this line is a comment with
+fixed goal column."
+  (interactive)
+  (or arg (setq arg 0))
+  (let ((icol (calculate-octave-indent))
+       (relpos (- (current-column) (current-indentation))))
+    (if (listp icol)
+       (setq icol (car icol))
+      (setq icol (+ icol arg)))
+    (if (< icol 0)
+       (error "Unmatched end keyword")
+      (indent-line-to icol)
+      (if (> relpos 0)
+         (move-to-column (+ icol relpos))))))
+
+(defun octave-indent-new-comment-line ()
+  "Break Octave line at point, continuing comment if within one.
+If within code, insert `octave-continuation-string' before breaking the
+line.  If within a string, signal an error.   
+The new line is properly indented." 
+  (interactive)
+  (delete-horizontal-space)
+  (cond
+   ((octave-in-comment-p)
+    (indent-new-comment-line))
+   ((octave-in-string-p)
+    (error "Cannot split a code line inside a string"))
+   (t
+    (insert (concat " " octave-continuation-string))
+    (octave-reindent-then-newline-and-indent))))
+
+(defun octave-indent-defun ()
+  "Properly indents the Octave function which contains point."
+  (interactive)
+  (save-excursion
+    (octave-mark-defun)
+    (message "Indenting function...")
+    (indent-region (point) (mark) nil))
+  (message "Indenting function...done."))
+
+\f
+;;; Motion
+(defun octave-next-code-line (&optional arg)
+  "Move ARG lines of Octave code forward (backward if ARG is negative).
+Skips past all empty and comment lines.  Default for ARG is 1.
+
+On success, return 0.  Otherwise, go as far as possible and return -1."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (beginning-of-line)
+  (let ((n 0)
+       (inc (if (> arg 0) 1 -1)))
+    (while (and (/= arg 0) (= n 0))
+      (setq n (forward-line inc))
+      (while (and (= n 0)
+                 (looking-at "\\s-*\\($\\|\\s<\\)"))
+       (setq n (forward-line inc)))
+      (setq arg (- arg inc)))
+    n))
+      
+(defun octave-previous-code-line (&optional arg)
+  "Move ARG lines of Octave code backward (forward if ARG is negative).
+Skips past all empty and comment lines.  Default for ARG is 1.
+
+On success, return 0.  Otherwise, go as far as possible and return -1."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (octave-next-code-line (- arg)))
+
+(defun octave-beginning-of-line ()
+  "Move point to beginning of current Octave line.
+If on an empty or comment line, go to the beginning of that line.
+Otherwise, move backward to the beginning of the first Octave code line
+which is not inside a continuation statement, i.e., which does not
+follow a code line ending in `...' or `\\', or is inside an open
+parenthesis list."
+  (interactive)
+  (beginning-of-line)
+  (if (not (looking-at "\\s-*\\($\\|\\s<\\)"))
+      (while (or (condition-case nil
+                    (progn
+                      (up-list -1)
+                      (beginning-of-line)
+                      t)
+                  (error nil))
+                (and (or (looking-at "\\s-*\\($\\|\\s<\\)")
+                         (save-excursion
+                           (if (zerop (octave-previous-code-line))
+                               (looking-at octave-continuation-regexp))))
+                     (zerop (forward-line -1)))))))
+
+(defun octave-end-of-line ()
+  "Move point to end of current Octave line.
+If on an empty or comment line, go to the end of that line.
+Otherwise, move forward to the end of the first Octave code line which
+does not end in `...' or `\\' or is inside an open parenthesis list."
+  (interactive)
+  (end-of-line)
+  (if (save-excursion
+       (beginning-of-line)
+       (looking-at "\\s-*\\($\\|\\s<\\)"))
+      ()
+    (while (or (condition-case nil
+                  (progn
+                    (up-list 1)
+                    (end-of-line)
+                    t)
+                (error nil))
+              (and (save-excursion
+                     (beginning-of-line)
+                     (or (looking-at "\\s-*\\($\\|\\s<\\)")
+                         (looking-at octave-continuation-regexp)))
+                   (zerop (forward-line 1)))))
+    (end-of-line)))
+  
+(defun octave-scan-blocks (from count depth)
+  "Scan from character number FROM by COUNT Octave begin-end blocks.
+Returns the character number of the position thus found.
+
+If DEPTH is nonzero, block depth begins counting from that value.
+Only places where the depth in blocks becomes zero are candidates for
+stopping; COUNT such places are counted.
+
+If the beginning or end of the buffer is reached and the depth is wrong,
+an error is signaled."
+  (let ((min-depth (if (> depth 0) 0 depth))
+       (inc (if (> count 0) 1 -1)))
+    (save-excursion
+      (while (/= count 0)
+       (catch 'foo
+         (while (or (re-search-forward
+                     octave-block-begin-or-end-regexp nil 'move inc)
+                    (if (/= depth 0)
+                        (error "Unbalanced block")))
+           (if (octave-not-in-string-or-comment-p)
+               (progn
+                 (cond
+                  ((match-end 1)
+                   (setq depth (+ depth inc)))
+                  ((match-end 2)
+                   (setq depth (- depth inc))))
+                 (if (< depth min-depth)
+                     (error "Containing expression ends prematurely"))
+                 (if (= depth 0)
+                     (throw 'foo nil))))))
+       (setq count (- count inc)))
+      (point))))
+
+(defun octave-forward-block (&optional arg)
+  "Move forward across one balanced Octave begin-end block.
+With argument, do it that many times.
+Negative arg -N means move backward across N blocks."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (goto-char (or (octave-scan-blocks (point) arg 0) (buffer-end arg))))
+
+(defun octave-backward-block (&optional arg)
+  "Move backward across one balanced Octave begin-end block.
+With argument, do it that many times.
+Negative arg -N means move forward across N blocks."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (octave-forward-block (- arg)))
+
+(defun octave-down-block (arg)
+  "Move forward down one begin-end block level of Octave code.
+With argument, do this that many times.
+A negative argument means move backward but still go down a level.
+In Lisp programs, an argument is required."
+  (interactive "p")
+  (let ((inc (if (> arg 0) 1 -1)))
+    (while (/= arg 0)
+      (goto-char (or (octave-scan-blocks (point) inc -1)
+                    (buffer-end arg)))
+      (setq arg (- arg inc)))))
+
+(defun octave-backward-up-block (arg)
+  "Move backward out of one begin-end block level of Octave code.
+With argument, do this that many times.
+A negative argument means move forward but still to a less deep spot.
+In Lisp programs, an argument is required."
+  (interactive "p")
+  (octave-up-block (- arg)))
+
+(defun octave-up-block (arg)
+  "Move forward out of one begin-end block level of Octave code.
+With argument, do this that many times.
+A negative argument means move backward but still to a less deep spot.
+In Lisp programs, an argument is required."
+  (interactive "p")
+  (let ((inc (if (> arg 0) 1 -1)))
+    (while (/= arg 0)
+      (goto-char (or (octave-scan-blocks (point) inc 1)
+                    (buffer-end arg)))
+      (setq arg (- arg inc)))))
+
+(defun octave-mark-block ()
+  "Put point at the beginning of this Octave block, mark at the end.
+The block marked is the one that contains point or follows point."
+  (interactive)
+  (let ((pos (point)))
+    (if (or (and (octave-in-block-p)
+                (skip-syntax-forward "w"))
+           (condition-case nil
+               (progn
+                 (octave-down-block 1)
+                 (octave-in-block-p))
+             (error nil)))
+       (progn
+         (octave-up-block -1)
+         (push-mark (point))
+         (octave-forward-block)
+         (exchange-point-and-mark))
+      (goto-char pos)
+      (message "No block to mark found"))))
+
+(defun octave-close-block ()
+  "Close the current Octave block on a separate line.
+An error is signaled if no block to close is found."
+  (interactive)
+  (let (bb-keyword)
+    (condition-case nil
+       (progn
+         (save-excursion
+           (octave-backward-up-block 1)
+           (setq bb-keyword (buffer-substring-no-properties
+                             (match-beginning 1) (match-end 1))))
+         (if (save-excursion
+               (beginning-of-line)
+               (looking-at "^\\s-*$"))
+             (indent-according-to-mode)
+           (octave-reindent-then-newline-and-indent))
+         (insert (car (reverse
+                       (assoc bb-keyword
+                              octave-block-match-alist))))
+         (octave-reindent-then-newline-and-indent)
+         t)
+      (error (message "No block to close found")))))
+
+(defun octave-blink-matching-block-open ()
+  "Blink the matching Octave begin block keyword.
+If point is right after an Octave else or end type block keyword, move
+cursor momentarily to the corresponding begin keyword.
+Signal an error if the keywords are incompatible."
+  (interactive)
+  (let (bb-keyword bb-arg eb-keyword pos eol)
+    (if (and (octave-not-in-string-or-comment-p)
+            (looking-at "\\>")
+            (save-excursion
+              (skip-syntax-backward "w")
+              (looking-at octave-block-else-or-end-regexp)))
+       (save-excursion
+         (cond
+          ((match-end 1)
+           (setq eb-keyword
+                 (buffer-substring-no-properties
+                  (match-beginning 1) (match-end 1)))
+           (octave-backward-up-block 1))
+          ((match-end 2)
+           (setq eb-keyword
+                 (buffer-substring-no-properties
+                  (match-beginning 2) (match-end 2)))
+           (octave-backward-block)))
+         (setq pos (match-end 0)
+               bb-keyword
+               (buffer-substring-no-properties
+                (match-beginning 0) pos)
+               pos (+ pos 1)
+               eol (octave-point 'eol)
+               bb-arg
+               (save-excursion
+                 (save-restriction
+                   (goto-char pos)
+                   (while (and (skip-syntax-forward "^<" eol)
+                               (octave-in-string-p)
+                               (not (forward-char 1))))
+                   (skip-syntax-backward " ")
+                   (buffer-substring-no-properties pos (point)))))
+         (if (member eb-keyword
+                     (cdr (assoc bb-keyword octave-block-match-alist)))
+             (progn
+               (message "Matches `%s %s'" bb-keyword bb-arg)
+               (if (pos-visible-in-window-p)
+                   (sit-for blink-matching-delay)))
+           (error "Block keywords `%s' and `%s' do not match"
+                  bb-keyword eb-keyword))))))
+
+(defun octave-beginning-of-defun (&optional arg)
+  "Move backward to the beginning of an Octave function.
+With positive ARG, do it that many times.  Negative argument -N means
+move forward to Nth following beginning of a function.
+Returns t unless search stops at the beginning or end of the buffer."
+  (interactive "p")
+  (let* ((arg (or arg 1))
+        (inc (if (> arg 0) 1 -1))
+        (found))
+    (and (not (eobp))
+        (not (and (> arg 0) (looking-at "\\<function\\>")))
+        (skip-syntax-forward "w"))
+    (while (and (/= arg 0)
+               (setq found
+                     (re-search-backward "\\<function\\>" nil 'move inc)))
+      (if (octave-not-in-string-or-comment-p)
+         (setq arg (- arg inc))))
+    (if found
+       (progn
+         (and (< inc 0) (goto-char (match-beginning 0)))
+         t))))
+
+(defun octave-end-of-defun (&optional arg)
+  "Move forward to the end of an Octave function.
+With positive ARG, do it that many times.  Negative argument -N means
+move back to Nth preceding end of a function.
+
+An end of a function occurs right after the end keyword matching the
+`function' keyword that starts the function."
+  (interactive "p")
+  (or arg (setq arg 1))
+  (and (< arg 0) (skip-syntax-backward "w"))
+  (and (> arg 0) (skip-syntax-forward "w"))  
+  (if (octave-in-defun-p)
+      (setq arg (- arg 1)))
+  (if (= arg 0) (setq arg -1))
+  (if (octave-beginning-of-defun (- arg))
+      (octave-forward-block)))
+
+(defun octave-mark-defun ()
+  "Put point at the beginning of this Octave function, mark at its end.
+The function marked is the one containing point or following point."
+  (interactive)
+  (let ((pos (point)))
+    (if (or (octave-in-defun-p)
+           (and (octave-beginning-of-defun -1)
+                (octave-in-defun-p)))
+       (progn
+         (skip-syntax-forward "w")
+         (octave-beginning-of-defun)
+         (push-mark (point))
+         (octave-end-of-defun)
+         (exchange-point-and-mark))
+      (goto-char pos)
+      (message "No function to mark found"))))
+  
+\f
+;;; Filling
+(defun octave-auto-fill ()
+  "Perform auto-fill in Octave mode."
+  (if (> (current-column) (current-fill-column))
+      (if (octave-in-comment-p)
+         (do-auto-fill)
+       (if (> (current-column) (current-fill-column))
+           (let ((fill-column (- (current-fill-column)
+                                 (length octave-continuation-string))))
+             (do-auto-fill)
+             (save-excursion
+               (forward-line -1)
+               (end-of-line)
+               (insert (concat " " octave-continuation-string)))
+             (indent-according-to-mode))))))
+
+(defun octave-fill-paragraph (&optional arg)
+ "Fill paragraph of Octave code, handling Octave comments."
+ (interactive "P")
+ (save-excursion 
+   (let ((end (progn (forward-paragraph) (point)))
+        (beg (progn
+               (forward-paragraph -1)
+               (skip-chars-forward " \t\n")
+               (beginning-of-line)
+               (point)))
+        (cfc (current-fill-column))
+        (ind (calculate-octave-indent))
+        comment-prefix)
+     (save-restriction
+       (goto-char beg)
+       (narrow-to-region beg end)
+       (if (listp ind) (setq ind (nth 1 ind)))
+       (while (not (eobp))
+        (condition-case nil
+            (octave-indent-line ind)
+          (error nil))
+        (if (and (> ind 0)
+                 (not
+                  (save-excursion
+                    (beginning-of-line)
+                    (looking-at "^\\s-*\\($\\|\\s<+\\)"))))
+            (setq ind 0))
+        (move-to-column cfc)
+        ;; First check whether we need to combine non-empty comment lines
+        (if (and (< (current-column) cfc)
+                 (octave-in-comment-p)
+                 (not (save-excursion
+                        (beginning-of-line)
+                        (looking-at "^\\s-*\\s<+\\s-*$"))))
+            ;; This is a nonempty comment line which does not extend
+            ;; past the fill column.  If it is followed by an nonempty
+            ;; comment line with the same comment prefix, try to
+            ;; combine them, and repeat this until either we reach the
+            ;; fill-column or there is nothing more to combine.
+            (progn
+              ;; Get the comment prefix
+              (save-excursion
+                (beginning-of-line)
+                (while (and (re-search-forward "\\s<+")
+                            (not (octave-in-comment-p))))
+                (setq comment-prefix (match-string 0)))
+              ;; And keep combining ...
+              (while (and (< (current-column) cfc)
+                          (save-excursion
+                            (forward-line 1)
+                            (and (looking-at
+                                  (concat "^\\s-*"
+                                          comment-prefix
+                                          "\\S<"))
+                                 (not (looking-at
+                                       (concat "^\\s-*"
+                                               comment-prefix
+                                               "\\s-*$"))))))
+                (delete-char 1)
+                (re-search-forward comment-prefix)
+                (delete-region (match-beginning 0) (match-end 0))
+                (fixup-whitespace)
+                (move-to-column cfc))))
+        (skip-chars-forward "^ \t\n")
+        (delete-horizontal-space)
+        (if (or (< (current-column) cfc)
+                (and (= (current-column) cfc) (eolp)))
+            (forward-line 1)
+          (if (not (eolp)) (insert " "))
+          (octave-auto-fill))))
+     t)))
+
+\f
+;;; Completions
+(defun octave-initialize-completions ()
+  "Create an alist for Octave completions."
+  (if octave-completion-alist
+      ()
+    (setq octave-completion-alist
+         (mapcar '(lambda (var) (cons var var))
+                 (append octave-reserved-words
+                         octave-text-functions
+                         octave-variables)))))
+
+(defun octave-complete-symbol ()
+  "Perform completion on Octave symbol preceding point.
+Compare that symbol against Octave's reserved words and builtin
+variables."
+  ;; This code taken from lisp-complete-symbol
+  (interactive)
+  (let* ((end (point))
+        (beg (save-excursion (backward-sexp 1) (point)))
+        (string (buffer-substring-no-properties beg end))
+        (completion (try-completion string octave-completion-alist)))
+    (cond ((eq completion t))          ; ???
+         ((null completion)
+          (message "Can't find completion for \"%s\"" string)
+          (ding))
+         ((not (string= string completion))
+           (delete-region beg end)
+           (insert completion))
+         (t
+          (let ((list (all-completions string octave-completion-alist))
+                (conf (current-window-configuration)))
+            ;; Taken from comint.el
+            (message "Making completion list...")             
+            (with-output-to-temp-buffer "*Completions*"
+              (display-completion-list list))
+            (message "Hit space to flush")
+            (let (key first)
+              (if (save-excursion
+                    (set-buffer (get-buffer "*Completions*"))
+                    (setq key (read-key-sequence nil)
+                          first (aref key 0))
+                    (and (consp first) (consp (event-start first))
+                         (eq (window-buffer (posn-window (event-start
+                                                          first)))
+                             (get-buffer "*Completions*"))
+                         (eq (key-binding key) 'mouse-choose-completion)))
+                  (progn
+                    (mouse-choose-completion first)
+                    (set-window-configuration conf))
+                (if (eq first ?\ )
+                    (set-window-configuration conf)
+                  (setq unread-command-events
+                        (listify-key-sequence key))))))))))
+              
+\f
+;;; Electric characters && friends
+(defun octave-reindent-then-newline-and-indent ()
+  "Reindent current Octave line, insert newline, and indent the new line.
+If Abbrev mode is on, expand abbrevs first."
+  (interactive)
+  (if abbrev-mode (expand-abbrev))
+  (if octave-blink-matching-block
+      (octave-blink-matching-block-open))
+  (save-excursion
+    (delete-region (point) (progn (skip-chars-backward " \t") (point)))
+    (indent-according-to-mode))
+  (insert "\n")
+  (indent-according-to-mode))
+
+(defun octave-electric-semi ()
+  "Insert a semicolon in Octave mode.
+Always reindent the line.  Insert a newline if `octave-auto-newline' is
+non-nil."
+  (interactive)
+  (if (not (octave-not-in-string-or-comment-p))
+      (insert ";")
+    (if abbrev-mode (expand-abbrev))
+    (if octave-blink-matching-block
+       (octave-blink-matching-block-open))
+    (indent-according-to-mode)    
+    (insert ";")
+    (if octave-auto-newline
+       (newline-and-indent))))
+
+(defun octave-electric-space ()
+  "Insert a space in Octave mode.
+Maybe expand abbrevs and blink matching block open keywords."
+  (interactive)
+  (setq last-command-char ? )
+  (if (not (octave-not-in-string-or-comment-p))
+      (progn
+       (indent-according-to-mode)
+       (self-insert-command 1))
+    (if abbrev-mode (expand-abbrev))
+    (if octave-blink-matching-block
+       (octave-blink-matching-block-open))
+    (if (save-excursion
+         (skip-syntax-backward " ")
+         (not (bolp)))
+       (indent-according-to-mode))
+    (self-insert-command 1)))
+
+(defun octave-abbrev-start ()
+  "Start entering an Octave abbreviation.
+If Abbrev mode is turned on, typing ` (grave accent) followed by ? or
+\\[help-command] lists all Octave abbrevs.  Any other key combination is
+executed normally.
+Note that all Octave mode abbrevs start with a grave accent."
+  (interactive)
+  (if (not abbrev-mode)
+      (self-insert-command 1)
+    (let (c)
+      (insert last-command-char)
+      (if (or (eq (setq c (read-event)) ??)
+             (eq c help-char))
+         (let ((abbrev-table-name-list '(octave-mode-abbrev-table)))
+           (list-abbrevs))
+       (setq unread-command-events (list c))))))
+
+(defun octave-insert-defun (name args vals)
+  "Insert an Octave function skeleton.
+Prompt for the function's name, arguments and return values (to be
+entered without parens)."
+  (interactive
+   (list
+    (read-from-minibuffer "Function name: "
+                         (substring (buffer-name) 0 -2))
+    (read-from-minibuffer "Arguments: ")
+    (read-from-minibuffer "Return values: ")))
+  (let ((string (format "%s %s (%s)"
+                       (cond
+                        ((string-equal vals "")
+                         vals)
+                        ((string-match "[ ,]" vals)
+                         (concat " [" vals "] ="))
+                        (t
+                         (concat " " vals " =")))
+                       name
+                       args))
+       (prefix octave-block-comment-start))
+    (if (not (bobp)) (newline))
+    (insert "function" string)
+    (indent-according-to-mode)
+    (newline 2)
+    (insert prefix "usage: " string)
+    (reindent-then-newline-and-indent)    
+    (insert prefix)
+    (reindent-then-newline-and-indent)    
+    (insert prefix)
+    (indent-according-to-mode)
+    (save-excursion
+      (newline 2)
+      (insert "endfunction")
+      (indent-according-to-mode))))
+             
+\f
+;;; Menu
+(defun octave-add-octave-menu ()
+  "Adds the `Octave' menu to the menu bar in Octave mode."
+  (require 'easymenu)  
+  (easy-menu-define octave-mode-menu-map octave-mode-map
+                   "Menu keymap for Octave mode." octave-mode-menu)
+  (easy-menu-add octave-mode-menu-map octave-mode-map))
+
+\f
+;;; Communication with the inferior Octave process
+(defun octave-kill-process ()
+  "Kill inferior Octave process and its buffer."
+  (interactive)
+  (if inferior-octave-process
+      (progn
+       (process-send-string inferior-octave-process "quit;\n")
+       (accept-process-output inferior-octave-process)))
+  (if inferior-octave-buffer
+      (kill-buffer inferior-octave-buffer)))
+
+(defun octave-show-process-buffer ()
+  "Make sure that `inferior-octave-buffer' is displayed."
+  (interactive)
+  (if (get-buffer inferior-octave-buffer)
+      (display-buffer inferior-octave-buffer)
+    (message "No buffer named %s" inferior-octave-buffer)))
+
+(defun octave-hide-process-buffer ()
+  "Delete all windows that display `inferior-octave-buffer'."
+  (interactive)
+  (if (get-buffer inferior-octave-buffer)
+      (delete-windows-on inferior-octave-buffer)
+    (message "No buffer named %s" inferior-octave-buffer)))
+
+(defun octave-send-region (beg end)
+  "Send current region to the inferior Octave process."
+  (interactive "r")
+  (inferior-octave t)  
+  (let ((proc inferior-octave-process)
+       (string (buffer-substring-no-properties beg end))
+       line)
+    (save-excursion
+      (set-buffer inferior-octave-buffer)
+      (setq inferior-octave-output-list nil)
+      (while (not (string-equal string ""))
+       (if (string-match "\n" string)
+           (setq line (substring string 0 (match-beginning 0))
+                 string (substring string (match-end 0)))
+         (setq line string string ""))
+       (setq inferior-octave-receive-in-progress t)
+       (inferior-octave-send-list-and-digest (list (concat line "\n")))
+       (while inferior-octave-receive-in-progress
+         (accept-process-output proc))
+       (insert-before-markers
+        (mapconcat 'identity
+                   (append
+                    (if octave-send-echo-input (list line) (list ""))
+                    (mapcar 'inferior-octave-strip-ctrl-g
+                            inferior-octave-output-list)
+                    (list inferior-octave-output-string))
+                   "\n")))))
+  (if octave-send-show-buffer
+      (display-buffer inferior-octave-buffer)))
+
+(defun octave-send-block ()
+  "Send current Octave block to the inferior Octave process."  
+  (interactive)
+  (save-excursion
+    (octave-mark-block)
+    (octave-send-region (point) (mark))))
+
+(defun octave-send-defun ()
+  "Send current Octave function to the inferior Octave process."
+  (interactive)
+  (save-excursion
+    (octave-mark-defun)
+    (octave-send-region (point) (mark))))
+
+(defun octave-send-line (&optional arg)
+  "Send current Octave code line to the inferior Octave process.
+With positive prefix ARG, send that many lines.
+If `octave-send-line-auto-forward' is non-nil, go to the next unsent
+code line."
+  (interactive "P")
+  (or arg (setq arg 1))
+  (if (> arg 0)
+      (let (beg end)
+       (beginning-of-line)
+       (setq beg (point))
+       (octave-next-code-line (- arg 1))
+       (end-of-line)
+       (setq end (point))
+       (if octave-send-line-auto-forward
+           (octave-next-code-line 1))
+       (octave-send-region beg end))))
+
+(defun octave-eval-print-last-sexp ()
+  "Evaluate Octave sexp before point and print value into current buffer."
+  (interactive)
+  (inferior-octave t)
+  (let ((standard-output (current-buffer))
+       (print-escape-newlines nil)
+       (opoint (point)))
+    (terpri)
+    (prin1    
+     (save-excursion
+       (forward-sexp -1)
+       (inferior-octave-send-list-and-digest
+       (list (concat (buffer-substring-no-properties (point) opoint)
+                     "\n")))
+       (mapconcat 'identity inferior-octave-output-list "\n")))
+    (terpri)))
+    
+;;; octave-mod.el ends here
\ No newline at end of file