Refill some copyright headers.
[bpt/emacs.git] / lisp / progmodes / octave-mod.el
index 30bb304..f523ea8 100644 (file)
@@ -1,10 +1,10 @@
 ;;; octave-mod.el --- editing Octave source files under Emacs
 
-;; Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+;;   2009, 2010, 2011  Free Software Foundation, Inc.
 
 ;; Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
-;; Author: John Eaton <jwe@bevo.che.wisc.edu>
+;; Author: John Eaton <jwe@octave.org>
 ;; Maintainer: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
 ;; Keywords: languages
 
@@ -92,7 +92,7 @@ All Octave abbrevs start with a grave accent (`)."
 (defvar octave-comment-char ?#
   "Character to start an Octave comment.")
 (defvar octave-comment-start
-  (string octave-comment-char ?\ )
+  (string octave-comment-char ?\s)
   "String to insert to start a new Octave in-line comment.")
 (defvar octave-comment-start-skip "\\s<+\\s-*"
   "Regexp to match the start of an Octave comment up to its body.")
@@ -101,11 +101,9 @@ All Octave abbrevs start with a grave accent (`)."
   '("do" "for" "function" "if" "switch" "try" "unwind_protect" "while"))
 (defvar octave-else-keywords
   '("case" "catch" "else" "elseif" "otherwise" "unwind_protect_cleanup"))
-;; FIXME: only use specific "end" tokens here to avoid confusion when "end"
-;; is used in indexing (the real fix is much more complex).
 (defvar octave-end-keywords
   '("endfor" "endfunction" "endif" "endswitch" "end_try_catch"
-    "end_unwind_protect" "endwhile" "until"))
+    "end_unwind_protect" "endwhile" "until" "end"))
 
 (defvar octave-reserved-words
   (append octave-begin-keywords
@@ -163,8 +161,8 @@ parenthetical grouping.")
   (list
    ;; Fontify all builtin keywords.
    (cons (concat "\\<\\("
-                (mapconcat 'identity octave-reserved-words "\\|")
-                (mapconcat 'identity octave-text-functions "\\|")
+                (regexp-opt (append octave-reserved-words
+                                     octave-text-functions))
                 "\\)\\>")
         'font-lock-keyword-face)
    ;; Fontify all builtin operators.
@@ -173,9 +171,7 @@ parenthetical grouping.")
             'font-lock-builtin-face
           'font-lock-preprocessor-face))
    ;; Fontify all builtin variables.
-   (cons (concat "\\<\\("
-                (mapconcat 'identity octave-variables "\\|")
-                "\\)\\>")
+   (cons (concat "\\<" (regexp-opt octave-variables) "\\>")
         'font-lock-variable-name-face)
    ;; Fontify all function declarations.
    (list octave-function-header-regexp
@@ -183,6 +179,29 @@ parenthetical grouping.")
         '(3 font-lock-function-name-face nil t)))
   "Additional Octave expressions to highlight.")
 
+(defun octave-syntax-propertize-function (start end)
+  (goto-char start)
+  (octave-syntax-propertize-sqs end)
+  (funcall (syntax-propertize-rules
+  ;; Try to distinguish the string-quotes from the transpose-quotes.
+            ("[[({,; ]\\('\\)"
+             (1 (prog1 "\"'" (octave-syntax-propertize-sqs end)))))
+           (point) end))
+
+(defun octave-syntax-propertize-sqs (end)
+  "Propertize the content/end of single-quote strings."
+  (when (eq (nth 3 (syntax-ppss)) ?\')
+        ;; A '..' string.
+    (when (re-search-forward
+           "\\(?:\\=\\|[^']\\)\\(?:''\\)*\\('\\)\\($\\|[^']\\)" end 'move)
+      (goto-char (match-beginning 2))
+            (when (eq (char-before (match-beginning 1)) ?\\)
+              ;; Backslash cannot escape a single quote.
+              (put-text-property (1- (match-beginning 1)) (match-beginning 1)
+                                 'syntax-table (string-to-syntax ".")))
+            (put-text-property (match-beginning 1) (match-end 1)
+                         'syntax-table (string-to-syntax "\"'")))))
+
 (defcustom inferior-octave-buffer "*Inferior Octave*"
   "Name of buffer for running an inferior Octave process."
   :type 'string
@@ -193,29 +212,17 @@ parenthetical grouping.")
 (defvar 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 "\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 [remap down-list] 'smie-down-list)
     (define-key map "\C-c\M-\C-h" 'octave-mark-block)
-    (define-key map "\C-c]" 'octave-close-block)
+    (define-key map "\C-c]" 'smie-close-block)
+    (define-key map "\C-c/" 'smie-close-block)
     (define-key map "\C-c\C-f" 'octave-insert-defun)
     (define-key map "\C-c\C-h" 'octave-help)
     (define-key map "\C-c\C-il" 'octave-send-line)
@@ -236,29 +243,24 @@ parenthetical grouping.")
   "Keymap used in Octave mode.")
 
 
-(defvar octave-mode-menu
+
+(easy-menu-define octave-mode-menu octave-mode-map
+  "Menu for Octave mode."
   '("Octave"
-    '("Lines"
+    ("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])
-    '("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]
+    ("Blocks"
       ["Mark Block"            octave-mark-block t]
-      ["Close Block"           octave-close-block t])
-    '("Functions"
-      ["Begin of Function"     octave-beginning-of-defun t]
-      ["End of Function"       octave-end-of-defun t]
-      ["Mark Function"         octave-mark-defun t]
+      ["Close Block"           smie-close-block t])
+    ("Functions"
       ["Indent Function"       octave-indent-defun t]
       ["Insert Function"       octave-insert-defun t])
     "-"
-    '("Debug"
+    ("Debug"
       ["Send Current Line"     octave-send-line t]
       ["Send Current Block"    octave-send-block t]
       ["Send Current Function" octave-send-defun t]
@@ -268,16 +270,17 @@ parenthetical grouping.")
       ["Kill Process"          octave-kill-process t])
     "-"
     ["Indent Line"             indent-according-to-mode t]
-    ["Complete Symbol"         octave-complete-symbol t]
+    ["Complete Symbol"         completion-at-point t]
     "-"
-    ["Toggle Abbrev Mode"      abbrev-mode t]
-    ["Toggle Auto-Fill Mode"   auto-fill-mode t]
+    ["Toggle Abbrev Mode"      abbrev-mode
+     :style toggle :selected abbrev-mode]
+    ["Toggle Auto-Fill Mode"   auto-fill-mode
+     :style toggle :selected auto-fill-function]
     "-"
     ["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.")
+    ["Describe Octave Mode"    describe-mode t]
+    ["Lookup Octave Index"     info-lookup-symbol t]))
 
 (defvar octave-mode-syntax-table
   (let ((table (make-syntax-table)))
@@ -299,64 +302,32 @@ parenthetical grouping.")
     (modify-syntax-entry ?\" "\"" table)
     (modify-syntax-entry ?. "w"   table)
     (modify-syntax-entry ?_ "w"   table)
-    (modify-syntax-entry ?\% "<"  table)
-    (modify-syntax-entry ?\# "<"  table)
+    ;; The "b" flag only applies to the second letter of the comstart
+    ;; and the first letter of the comend, i.e. the "4b" below is ineffective.
+    ;; If we try to put `b' on the single-line comments, we get a similar
+    ;; problem where the % and # chars appear as first chars of the 2-char
+    ;; comend, so the multi-line ender is also turned into style-b.
+    ;; So we need the new "c" comment style.
+    (modify-syntax-entry ?\% "< 13"  table)
+    (modify-syntax-entry ?\# "< 13"  table)
+    (modify-syntax-entry ?\{ "(} 2c"  table)
+    (modify-syntax-entry ?\} "){ 4c"  table)
     (modify-syntax-entry ?\n ">"  table)
     table)
   "Syntax table in use in `octave-mode' buffers.")
 
-(defcustom octave-auto-indent nil
-  "Non-nil means indent line after a semicolon or space in Octave mode."
-  :type 'boolean
-  :group 'octave)
-
-(defcustom octave-auto-newline nil
-  "Non-nil means automatically newline after a semicolon in Octave mode."
-  :type 'boolean
-  :group 'octave)
-
 (defcustom 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."
   :type 'boolean
   :group 'octave)
+
 (defcustom octave-block-offset 2
   "Extra indentation applied to statements in Octave block structures."
   :type 'integer
   :group 'octave)
 
-(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))
-;; FIXME: only use specific "end" tokens here to avoid confusion when "end"
-;; is used in indexing (the real fix is much more complex).
-(defvar octave-block-match-alist
-  '(("do" . ("until"))
-    ("for" . ("endfor"))
-    ("function" . ("endfunction"))
-    ("if" . ("else" "elseif" "endif"))
-    ("switch" . ("case" "otherwise" "endswitch"))
-    ("try" . ("catch" "end_try_catch"))
-    ("unwind_protect" . ("unwind_protect_cleanup" "end_unwind_protect"))
-    ("while" . ("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.")
@@ -365,8 +336,11 @@ end keywords as associated values.")
   "Extra indentation applied to Octave continuation lines."
   :type 'integer
   :group 'octave)
+(eval-and-compile
+  (defconst octave-continuation-marker-regexp "\\\\\\|\\.\\.\\."))
 (defvar octave-continuation-regexp
-  "[^#%\n]*\\(\\\\\\|\\.\\.\\.\\)\\s-*\\(\\s<.*\\)?$")
+  (concat "[^#%\n]*\\(" octave-continuation-marker-regexp
+          "\\)\\s-*\\(\\s<.*\\)?$"))
 (defcustom octave-continuation-string "\\"
   "Character string used for Octave continuation lines.  Normally \\."
   :type 'string
@@ -404,13 +378,160 @@ Non-nil means always go to the next Octave code line after sending."
   :group 'octave)
 
 \f
+;;; SMIE indentation
+
+(require 'smie)
+
+(defconst octave-operator-table
+  '((assoc ";" "\n") (assoc ",") ; The doc claims they have equal precedence!?
+    (right "=" "+=" "-=" "*=" "/=")
+    (assoc "&&") (assoc "||") ; The doc claims they have equal precedence!?
+    (assoc "&") (assoc "|")   ; The doc claims they have equal precedence!?
+    (nonassoc "<" "<=" "==" ">=" ">" "!=" "~=")
+    (nonassoc ":")                      ;No idea what this is.
+    (assoc "+" "-")
+    (assoc "*" "/" "\\" ".\\" ".*" "./")
+    (nonassoc "'" ".'")
+    (nonassoc "++" "--" "!" "~")        ;And unary "+" and "-".
+    (right "^" "**" ".^" ".**")
+    ;; It's not really an operator, but for indentation purposes it
+    ;; could be convenient to treat it as one.
+    (assoc "...")))
+
+(defconst octave-smie-bnf-table
+  '((atom)
+    ;; We can't distinguish the first element in a sequence with
+    ;; precedence grammars, so we can't distinguish the condition
+    ;; if the `if' from the subsequent body, for example.
+    ;; This has to be done later in the indentation rules.
+    (exp (exp "\n" exp)
+         ;; We need to mention at least one of the operators in this part
+         ;; of the grammar: if the BNF and the operator table have
+         ;; no overlap, SMIE can't know how they relate.
+         (exp ";" exp)
+         ("try" exp "catch" exp "end_try_catch")
+         ("try" exp "catch" exp "end")
+         ("unwind_protect" exp
+          "unwind_protect_cleanup" exp "end_unwind_protect")
+         ("unwind_protect" exp "unwind_protect_cleanup" exp "end")
+         ("for" exp "endfor")
+         ("for" exp "end")
+         ("do" exp "until" atom)
+         ("while" exp "endwhile")
+         ("while" exp "end")
+         ("if" exp "endif")
+         ("if" exp "else" exp "endif")
+         ("if" exp "elseif" exp "else" exp "endif")
+         ("if" exp "elseif" exp "elseif" exp "else" exp "endif")
+         ("if" exp "elseif" exp "elseif" exp "else" exp "end")
+         ("switch" exp "case" exp "endswitch")
+         ("switch" exp "case" exp "otherwise" exp "endswitch")
+         ("switch" exp "case" exp "case" exp "otherwise" exp "endswitch")
+         ("switch" exp "case" exp "case" exp "otherwise" exp "end")
+         ("function" exp "endfunction")
+         ("function" exp "end"))
+    ;; (fundesc (atom "=" atom))
+    ))
+
+(defconst octave-smie-grammar
+  (smie-prec2->grammar
+   (smie-merge-prec2s
+    (smie-bnf->prec2 octave-smie-bnf-table
+                     '((assoc "\n" ";")))
+
+    (smie-precs->prec2 octave-operator-table))))
+
+;; Tokenizing needs to be refined so that ";;" is treated as two
+;; tokens and also so as to recognize the \n separator (and
+;; corresponding continuation lines).
+
+(defconst octave-operator-regexp
+  (regexp-opt (apply 'append (mapcar 'cdr octave-operator-table))))
+
+(defun octave-smie-backward-token ()
+  (let ((pos (point)))
+    (forward-comment (- (point)))
+    (cond
+     ((and (not (eq (char-before) ?\;)) ;Coalesce ";" and "\n".
+           (> pos (line-end-position))
+           (if (looking-back octave-continuation-marker-regexp (- (point) 3))
+               (progn
+                 (goto-char (match-beginning 0))
+                 (forward-comment (- (point)))
+                 nil)
+             t)
+           ;; Ignore it if it's within parentheses.
+           (let ((ppss (syntax-ppss)))
+             (not (and (nth 1 ppss)
+                       (eq ?\( (char-after (nth 1 ppss)))))))
+      (skip-chars-forward " \t")
+      ;; Why bother distinguishing \n and ;?
+      ";") ;;"\n"
+     ((and (looking-back octave-operator-regexp (- (point) 3) 'greedy)
+           ;; Don't mistake a string quote for a transpose.
+           (not (looking-back "\\s\"" (1- (point)))))
+      (goto-char (match-beginning 0))
+      (match-string-no-properties 0))
+     (t
+      (smie-default-backward-token)))))
+
+(defun octave-smie-forward-token ()
+  (skip-chars-forward " \t")
+  (when (looking-at (eval-when-compile
+                      (concat "\\(" octave-continuation-marker-regexp
+                              "\\)[ \t]*\\($\\|[%#]\\)")))
+    (goto-char (match-end 1))
+    (forward-comment 1))
+  (cond
+   ((and (looking-at "$\\|[%#]")
+         ;; Ignore it if it's within parentheses.
+         (prog1 (let ((ppss (syntax-ppss)))
+                  (not (and (nth 1 ppss)
+                            (eq ?\( (char-after (nth 1 ppss))))))
+           (forward-comment (point-max))))
+    ;; Why bother distinguishing \n and ;?
+    ";") ;;"\n"
+   ((looking-at ";[ \t]*\\($\\|[%#]\\)")
+    ;; Combine the ; with the subsequent \n.
+    (goto-char (match-beginning 1))
+    (forward-comment 1)
+    ";")
+   ((and (looking-at octave-operator-regexp)
+         ;; Don't mistake a string quote for a transpose.
+         (not (looking-at "\\s\"")))
+    (goto-char (match-end 0))
+    (match-string-no-properties 0))
+   (t
+    (smie-default-forward-token))))
+
+(defun octave-smie-rules (kind token)
+  (pcase (cons kind token)
+    ;; We could set smie-indent-basic instead, but that would have two
+    ;; disadvantages:
+    ;; - changes to octave-block-offset wouldn't take effect immediately.
+    ;; - edebug wouldn't show the use of this variable.
+    (`(:elem . basic) octave-block-offset)
+    ;; Since "case" is in the same BNF rules as switch..end, SMIE by default
+    ;; aligns it with "switch".
+    (`(:before . "case") (if (not (smie-rule-sibling-p)) octave-block-offset))
+    (`(:after . ";")
+     (if (smie-rule-parent-p "function" "if" "while" "else" "elseif" "for"
+                             "otherwise" "case" "try" "catch" "unwind_protect"
+                             "unwind_protect_cleanup")
+         (smie-rule-parent octave-block-offset)
+       ;; For (invalid) code between switch and case.
+       ;; (if (smie-parent-p "switch") 4)
+       0))))
+
+(defvar electric-layout-rules)
+
 ;;;###autoload
-(defun octave-mode ()
+(define-derived-mode octave-mode prog-mode "Octave"
   "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
+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
@@ -433,14 +554,6 @@ Keybindings
 Variables you can use to customize Octave mode
 ==============================================
 
-`octave-auto-indent'
-  Non-nil means indent current line after a semicolon or space.
-  Default is nil.
-
-`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.
@@ -488,56 +601,63 @@ 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
-        imenu-case-fold-search nil)
-
-  (octave-add-octave-menu)
-  (octave-initialize-completions)
-  (run-mode-hooks 'octave-mode-hook))
+
+  (smie-setup octave-smie-grammar #'octave-smie-rules
+              :forward-token  #'octave-smie-forward-token
+              :backward-token #'octave-smie-backward-token)
+  (set (make-local-variable 'smie-indent-basic) 'octave-block-offset)
+
+    (set (make-local-variable 'smie-blink-matching-triggers)
+       (cons ?\; smie-blink-matching-triggers))
+  (unless octave-blink-matching-block
+    (remove-hook 'post-self-insert-hook #'smie-blink-matching-open 'local))
+
+  (set (make-local-variable 'electric-indent-chars)
+       (cons ?\; electric-indent-chars))
+  ;; IIUC matlab-mode takes the opposite approach: it makes RET insert
+  ;; a ";" at those places where it's correct (i.e. outside of parens).
+  (set (make-local-variable 'electric-layout-rules) '((?\; . after)))
+
+  (set (make-local-variable 'comment-start) octave-comment-start)
+  (set (make-local-variable 'comment-end) "")
+  ;; Don't set it here: it's not really a property of the language,
+  ;; just a personal preference of the author.
+  ;; (set (make-local-variable 'comment-column) 32)
+  (set (make-local-variable 'comment-start-skip) "\\s<+\\s-*")
+  (set (make-local-variable 'comment-add) 1)
+
+  (set (make-local-variable 'parse-sexp-ignore-comments) t)
+  (set (make-local-variable 'paragraph-start)
+       (concat "\\s-*$\\|" page-delimiter))
+  (set (make-local-variable 'paragraph-separate) paragraph-start)
+  (set (make-local-variable 'paragraph-ignore-fill-prefix) t)
+  (set (make-local-variable 'fill-paragraph-function) 'octave-fill-paragraph)
+  ;; FIXME: Why disable it?
+  ;; (set (make-local-variable 'adaptive-fill-regexp) nil)
+  ;; Again, this is not a property of the language, don't set it here.
+  ;; (set (make-local-variable 'fill-column) 72)
+  (set (make-local-variable 'normal-auto-fill-function) 'octave-auto-fill)
+
+  (set (make-local-variable 'font-lock-defaults)
+       '(octave-font-lock-keywords))
+
+  (set (make-local-variable 'syntax-propertize-function)
+       #'octave-syntax-propertize-function)
+
+  (set (make-local-variable 'imenu-generic-expression)
+       octave-mode-imenu-generic-expression)
+  (set (make-local-variable 'imenu-case-fold-search) nil)
+
+  (add-hook 'completion-at-point-functions
+            'octave-completion-at-point-function nil t)
+  (set (make-local-variable 'beginning-of-defun-function)
+       'octave-beginning-of-defun)
+
+  (easy-menu-add octave-mode-menu)
+  (octave-initialize-completions))
+
+(defvar info-lookup-mode)
 
 (defun octave-help ()
   "Get help on Octave symbols from the Octave info files.
@@ -546,74 +666,31 @@ Look up symbol in the function, operator and variable indices of the info files.
     (call-interactively 'info-lookup-symbol)))
 \f
 ;;; Miscellaneous useful functions
-(defun octave-describe-major-mode ()
-  "Describe the current major mode."
-  (interactive)
-  (describe-function major-mode))
 
 (defsubst octave-in-comment-p ()
   "Return t if point is inside an Octave comment."
-  (interactive)
   (save-excursion
+    ;; FIXME: use syntax-ppss?
     (nth 4 (parse-partial-sexp (line-beginning-position) (point)))))
 
 (defsubst octave-in-string-p ()
   "Return t if point is inside an Octave string."
-  (interactive)
   (save-excursion
+    ;; FIXME: use syntax-ppss?
     (nth 3 (parse-partial-sexp (line-beginning-position) (point)))))
 
 (defsubst octave-not-in-string-or-comment-p ()
   "Return t if point is not inside an Octave string or comment."
+  ;; FIXME: Use syntax-ppss?
   (let ((pps (parse-partial-sexp (line-beginning-position) (point))))
     (not (or (nth 3 pps) (nth 4 pps)))))
 
-(defun octave-in-block-p ()
-  "Return t if point is inside an Octave block.
-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-looking-at-kw (regexp)
   "Like `looking-at', but sets `case-fold-search' nil."
   (let ((case-fold-search nil))
     (looking-at regexp)))
 
-(defun octave-re-search-forward-kw (regexp count)
-  "Like `re-search-forward', but sets `case-fold-search' nil, and moves point."
-  (let ((case-fold-search nil))
-    (re-search-forward regexp nil 'move count)))
-
-(defun octave-re-search-backward-kw (regexp count)
-  "Like `re-search-backward', but sets `case-fold-search' nil, and moves point."
-  (let ((case-fold-search nil))
-    (re-search-backward regexp nil 'move count)))
-
-(defun octave-in-defun-p ()
-  "Return t if 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 (octave-looking-at-kw "\\<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)))))))
-
 (defun octave-maybe-insert-continuation-string ()
   (if (or (octave-in-comment-p)
          (save-excursion
@@ -623,135 +700,8 @@ the end keyword."
     (delete-horizontal-space)
     (insert (concat " " octave-continuation-string))))
 
-;;; 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 (line-end-position)))
-               (while (< (point) eol)
-                 (if (octave-not-in-string-or-comment-p)
-                     (cond
-                      ((octave-looking-at-kw "\\<switch\\>")
-                       (setq icol (+ icol (* 2 octave-block-offset))))
-                      ((octave-looking-at-kw octave-block-begin-regexp)
-                       (setq icol (+ icol octave-block-offset)))
-                      ((octave-looking-at-kw octave-block-else-regexp)
-                       (if (= bot (point))
-                           (setq icol (+ icol octave-block-offset))))
-                      ((octave-looking-at-kw octave-block-end-regexp)
-                       (if (not (= bot (point)))
-                           (setq icol (- icol
-                                         (octave-block-end-offset)))))))
-                 (forward-char)))
-             (if is-continuation-line
-                 (setq icol (+ icol octave-continuation-offset)))))))
-    (save-excursion
-      (back-to-indentation)
-      (cond
-       ((and (octave-looking-at-kw octave-block-else-regexp)
-            (octave-not-in-string-or-comment-p))
-       (setq icol (- icol octave-block-offset)))
-       ((and (octave-looking-at-kw octave-block-end-regexp)
-            (octave-not-in-string-or-comment-p))
-       (setq icol (- icol (octave-block-end-offset))))
-       ((or (looking-at "\\s<\\s<\\s<\\S<")
-           (octave-before-magic-comment-p))
-       (setq icol (list 0 icol)))
-       ((looking-at "\\s<\\S<")
-       (setq icol (list comment-column icol)))))
-    icol))
-
-(defun octave-block-end-offset ()
-  (save-excursion
-    (octave-backward-up-block 1)
-    (* octave-block-offset
-       (if (string-match (match-string 0) "switch") 2 1))))
-
-(defun octave-before-magic-comment-p ()
-  (save-excursion
-    (beginning-of-line)
-    (and (bobp) (looking-at "\\s-*#!"))))
-
-(defun octave-comment-indent ()
-  (if (or (looking-at "\\s<\\s<\\s<")
-         (octave-before-magic-comment-p))
-      0
-    (if (looking-at "\\s<\\s<")
-       (calculate-octave-indent)
-      (skip-syntax-backward " ")
-      (max (if (bolp) 0 (+ 1 (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)
-  (beginning-of-line)
-  (if (looking-at "^\\s-*$")
-      (insert octave-block-comment-start)
-    (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.
@@ -767,13 +717,13 @@ The new line is properly indented."
     (error "Cannot split a code line inside a string"))
    (t
     (insert (concat " " octave-continuation-string))
-    (octave-reindent-then-newline-and-indent))))
+    (reindent-then-newline-and-indent))))
 
 (defun octave-indent-defun ()
   "Properly indent the Octave function which contains point."
   (interactive)
   (save-excursion
-    (octave-mark-defun)
+    (mark-defun)
     (message "Indenting function...")
     (indent-region (point) (mark) nil))
   (message "Indenting function...done."))
@@ -853,193 +803,33 @@ does not end in `...' or `\\' or is inside an open parenthesis list."
                    (zerop (forward-line 1)))))
     (end-of-line)))
 
-(defun octave-scan-blocks (count depth)
-  "Scan from point 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 (octave-re-search-forward-kw
-                     octave-block-begin-or-end-regexp 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 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 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 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")
-              (octave-looking-at-kw 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 (line-end-position)
-               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))))))
+  (unless (or (looking-at "\\s(")
+              (save-excursion
+                (let* ((token (funcall smie-forward-token-function))
+                       (level (assoc token smie-grammar)))
+                  (and level (null (cadr level))))))
+    (backward-up-list 1))
+  (mark-sexp))
 
 (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))
+        (found nil)
+         (case-fold-search nil))
     (and (not (eobp))
-        (not (and (> arg 0) (octave-looking-at-kw "\\<function\\>")))
+        (not (and (> arg 0) (looking-at "\\<function\\>")))
         (skip-syntax-forward "w"))
     (while (and (/= arg 0)
                (setq found
-                     (octave-re-search-backward-kw "\\<function\\>" inc)))
+                     (re-search-backward "\\<function\\>" inc)))
       (if (octave-not-in-string-or-comment-p)
          (setq arg (- arg inc))))
     (if found
@@ -1047,40 +837,6 @@ Returns t unless search stops at the beginning or end of the buffer."
          (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 ()
@@ -1145,81 +901,73 @@ otherwise."
       (not give-up))))
 
 (defun octave-fill-paragraph (&optional arg)
- "Fill paragraph of Octave code, handling Octave comments."
- ;; FIXME: now that the default fill-paragraph takes care of similar issues,
- ;; this seems obsolete.  --Stef
- (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 a 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))))
-        ;; We might also try to combine continued code lines>  Perhaps
-        ;; some other time ...
-        (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 " "))
-          (or (octave-auto-fill)
-              (forward-line 1)))))
-     t)))
+  "Fill paragraph of Octave code, handling Octave comments."
+  ;; FIXME: difference with generic fill-paragraph:
+  ;; - code lines are only split, never joined.
+  ;; - \n that end comments are never removed.
+  ;; - insert continuation marker when splitting code lines.
+  (interactive "P")
+  (save-excursion
+    (let ((end (progn (forward-paragraph) (copy-marker (point) t)))
+          (beg (progn
+                 (forward-paragraph -1)
+                 (skip-chars-forward " \t\n")
+                 (beginning-of-line)
+                 (point)))
+          (cfc (current-fill-column))
+          comment-prefix)
+      (goto-char beg)
+      (while (< (point) end)
+        (condition-case nil
+            (indent-according-to-mode)
+          (error nil))
+        (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 a 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))))
+        ;; We might also try to combine continued code lines>  Perhaps
+        ;; some other time ...
+        (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 " "))
+          (or (octave-auto-fill)
+              (forward-line 1))))
+      t)))
 
 \f
 ;;; Completions
@@ -1228,105 +976,28 @@ otherwise."
   (if octave-completion-alist
       ()
     (setq octave-completion-alist
-         (mapcar '(lambda (var) (cons var var))
-                 (append octave-reserved-words
-                         octave-text-functions
-                         octave-variables)))))
+          (append octave-reserved-words
+                  octave-text-functions
+                  octave-variables))))
+
+(defun octave-completion-at-point-function ()
+  "Find the text to complete and the corresponding table."
+  (let* ((beg (save-excursion (backward-sexp 1) (point)))
+         (end (point)))
+    (if (< beg (point))
+        ;; Extend region past point, if applicable.
+        (save-excursion (goto-char beg) (forward-sexp 1)
+                        (setq end (max end (point)))))
+    (list beg end octave-completion-alist)))
 
 (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 string))
-            (message "Hit space to flush")
-            (let (key first)
-              (if (with-current-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))))))))))
-
+  (apply 'completion-in-region (octave-completion-at-point-function)))
 \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.
-Maybe expand abbrevs and blink matching block open keywords.
-Reindent the line of `octave-auto-indent' is non-nil.
-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))
-    (if octave-auto-indent
-       (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.
-Reindent the line of `octave-auto-indent' is non-nil."
-  (interactive)
-  (setq last-command-char ? )
-  (if (and octave-auto-indent
-          (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 (and octave-auto-indent
-            (save-excursion
-              (skip-syntax-backward " ")
-              (not (bolp))))
-       (indent-according-to-mode))
-    (self-insert-command 1)))
 
 (defun octave-abbrev-start ()
   "Start entering an Octave abbreviation.
@@ -1338,7 +1009,7 @@ Note that all Octave mode abbrevs start with a grave accent."
   (if (not abbrev-mode)
       (self-insert-command 1)
     (let (c)
-      (insert last-command-char)
+      (insert last-command-event)
       (if (if (featurep 'xemacs)
              (or (eq (event-to-character (setq c (next-event))) ??)
                  (eq (event-to-character c) help-char))
@@ -1348,51 +1019,27 @@ Note that all Octave mode abbrevs start with a grave accent."
            (list-abbrevs))
        (setq unread-command-events (list c))))))
 
-(defun octave-insert-defun (name args vals)
+(define-skeleton octave-insert-defun
   "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 ()
-  "Add 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))
-
+  (let* ((defname (substring (buffer-name) 0 -2))
+         (name (read-string (format "Function name (default %s): " defname)
+                            nil nil defname))
+         (args (read-string "Arguments: "))
+         (vals (read-string "Return values: ")))
+    (format "%s%s (%s)"
+            (cond
+             ((string-equal vals "") vals)
+             ((string-match "[ ,]" vals) (concat "[" vals "] = "))
+             (t (concat vals " = ")))
+            name
+            args))
+  \n "function " > str \n \n
+  octave-block-comment-start "usage: " str \n
+  octave-block-comment-start \n octave-block-comment-start
+  \n _ \n
+  "endfunction" > \n)
 \f
 ;;; Communication with the inferior Octave process
 (defun octave-kill-process ()
@@ -1459,7 +1106,7 @@ entered without parens)."
   "Send current Octave function to the inferior Octave process."
   (interactive)
   (save-excursion
-    (octave-mark-defun)
+    (mark-defun)
     (octave-send-region (point) (mark))))
 
 (defun octave-send-line (&optional arg)
@@ -1508,8 +1155,6 @@ code line."
     octave-maintainer-address
     (concat "Emacs version " emacs-version)
     (list
-     'octave-auto-indent
-     'octave-auto-newline
      'octave-blink-matching-block
      'octave-block-offset
      'octave-comment-char
@@ -1523,5 +1168,4 @@ code line."
 
 (provide 'octave-mod)
 
-;; arch-tag: 05f1ce09-be87-4c00-803e-4919ffa26c23
 ;;; octave-mod.el ends here