]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/octave-mod.el
Merge from emacs-23
[gnu-emacs] / lisp / progmodes / octave-mod.el
index e467ca089295d0474f0e07e69409ba2f82fd7786..2911b97db898db337bd7a64a3117fb6a06712c28 100644 (file)
@@ -4,7 +4,7 @@
 ;; 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.")
@@ -161,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.
@@ -171,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
@@ -181,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
@@ -191,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)
@@ -234,7 +243,9 @@ 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"
       ["Previous Code Line"    octave-previous-code-line t]
@@ -243,16 +254,9 @@ parenthetical grouping.")
       ["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]
       ["Mark Block"            octave-mark-block t]
-      ["Close Block"           octave-close-block t])
+      ["Close Block"           smie-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]
       ["Indent Function"       octave-indent-defun t]
       ["Insert Function"       octave-insert-defun t])
     "-"
@@ -266,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)))
@@ -297,62 +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))
-(defvar octave-block-match-alist
-  '(("do" . ("until"))
-    ("for" . ("endfor" "end"))
-    ("function" . ("endfunction"))
-    ("if" . ("else" "elseif" "endif" "end"))
-    ("switch" . ("case" "otherwise" "endswitch" "end"))
-    ("try" . ("catch" "end_try_catch"))
-    ("unwind_protect" . ("unwind_protect_cleanup" "end_unwind_protect"))
-    ("while" . ("endwhile" "end")))
-  "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.")
@@ -361,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
@@ -400,8 +378,155 @@ 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
@@ -429,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.
@@ -484,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.
@@ -542,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
@@ -619,147 +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 (and (not (= bot (point)))
-                                ;; special case for `end' keyword,
-                                ;; applied to all keywords
-                                (not (octave-end-as-array-index-p)))
-                           (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))
-
-;; FIXME: this should probably also make sure we are actually looking
-;; at the "end" keyword.
-(defun octave-end-as-array-index-p ()
-  (save-excursion
-    (condition-case nil
-       ;; Check if point is between parens
-       (progn (up-list 1) t)
-      (error nil))))
-
-(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.
@@ -775,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."))
@@ -861,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
@@ -1055,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 ()
@@ -1153,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
@@ -1236,72 +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."
   (interactive)
-  (let* ((end (point))
-        (beg (save-excursion (backward-sexp 1) (point))))
-    (completion-in-region beg end octave-completion-alist)))
-
+  (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 if `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 if `octave-auto-indent' is non-nil."
-  (interactive)
-  (setq last-command-event ? )
-  (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.
@@ -1323,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 ()
@@ -1434,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)
@@ -1483,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
@@ -1498,5 +1168,4 @@ code line."
 
 (provide 'octave-mod)
 
-;; arch-tag: 05f1ce09-be87-4c00-803e-4919ffa26c23
 ;;; octave-mod.el ends here