changeset 16901:f2035f66dba0

Initial revision
author Richard M. Stallman <rms@gnu.org>
date Tue, 21 Jan 1997 00:29:57 +0000
parents b0961ba869d6
children 6a94efd704e6
files lisp/progmodes/octave-mod.el
diffstat 1 files changed, 1227 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/octave-mod.el	Tue Jan 21 00:29:57 1997 +0000
@@ -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.")
+
+
+;;;###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)))
+
+
+;;; 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)))
+
+
+;;; 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."))
+
+
+;;; 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"))))
+  
+
+;;; 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)))
+
+
+;;; 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))))))))))
+	       
+
+;;; 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))))
+	      
+
+;;; 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))
+
+
+;;; 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