cleanups.
* progmodes/octave.el: New file renamed from octave-mod.el.
* progmodes/octave-inf.el: Merged into octave.el.
* progmodes/octave-mod.el: Renamed to octave.el.
+2013-04-25 Leo Liu <sdl.web@gmail.com>
+
+ Merge octave-mod.el and octave-inf.el into octave.el with some
+ cleanups.
+ * progmodes/octave.el: New file renamed from octave-mod.el.
+ * progmodes/octave-inf.el: Merged into octave.el.
+ * progmodes/octave-mod.el: Renamed to octave.el.
+
2013-04-25 Tassilo Horn <tsdh@gnu.org>
* textmodes/reftex-vars.el
+++ /dev/null
-;;; octave-inf.el --- running Octave as an inferior Emacs process
-
-;; Copyright (C) 1997, 2001-2013 Free Software Foundation, Inc.
-
-;; Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
-;; John Eaton <jwe@bevo.che.wisc.edu>
-;; Maintainer: FSF
-;; Keywords: languages
-;; Package: octave-mod
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'octave-mod)
-(require 'comint)
-
-(defgroup octave-inferior nil
- "Running Octave as an inferior Emacs process."
- :group 'octave)
-
-(defcustom inferior-octave-program "octave"
- "Program invoked by `inferior-octave'."
- :type 'string
- :group 'octave-inferior)
-
-(defcustom inferior-octave-prompt
- "\\(^octave\\(\\|.bin\\|.exe\\)\\(-[.0-9]+\\)?\\(:[0-9]+\\)?\\|^debug\\|^\\)>+ "
- "Regexp to match prompts for the inferior Octave process."
- :type 'regexp
- :group 'octave-inferior)
-
-(defcustom inferior-octave-startup-file nil
- "Name of the inferior Octave startup file.
-The contents of this file are sent to the inferior Octave process on
-startup."
- :type '(choice (const :tag "None" nil)
- file)
- :group 'octave-inferior)
-
-(defcustom inferior-octave-startup-args nil
- "List of command line arguments for the inferior Octave process.
-For example, for suppressing the startup message and using `traditional'
-mode, set this to (\"-q\" \"--traditional\")."
- :type '(repeat string)
- :group 'octave-inferior)
-
-(defvar inferior-octave-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map comint-mode-map)
- (define-key map "\t" 'comint-dynamic-complete)
- (define-key map "\M-?" 'comint-dynamic-list-filename-completions)
- (define-key map "\C-c\C-l" 'inferior-octave-dynamic-list-input-ring)
- (define-key map [menu-bar inout list-history]
- '("List Input History" . inferior-octave-dynamic-list-input-ring))
- ;; FIXME: free C-h so it can do the describe-prefix-bindings.
- (define-key map "\C-c\C-h" 'info-lookup-symbol)
- map)
- "Keymap used in Inferior Octave mode.")
-
-(defvar inferior-octave-mode-syntax-table
- (let ((table (make-syntax-table octave-mode-syntax-table)))
- table)
- "Syntax table in use in inferior-octave-mode buffers.")
-
-(defcustom inferior-octave-mode-hook nil
- "Hook to be run when Inferior Octave mode is started."
- :type 'hook
- :group 'octave-inferior)
-
-(defvar inferior-octave-font-lock-keywords
- (list
- (cons inferior-octave-prompt 'font-lock-type-face))
- ;; Could certainly do more font locking in inferior Octave ...
- "Additional expressions to highlight in Inferior Octave mode.")
-
-
-;;; Compatibility functions
-(if (not (fboundp 'comint-line-beginning-position))
- ;; comint-line-beginning-position is defined in Emacs 21
- (defun comint-line-beginning-position ()
- "Returns the buffer position of the beginning of the line, after any prompt.
-The prompt is assumed to be any text at the beginning of the line matching
-the regular expression `comint-prompt-regexp', a buffer local variable."
- (save-excursion (comint-bol nil) (point))))
-
-
-(defvar inferior-octave-output-list nil)
-(defvar inferior-octave-output-string nil)
-(defvar inferior-octave-receive-in-progress nil)
-
-(defvar inferior-octave-startup-hook nil)
-
-(defvar inferior-octave-complete-impossible nil
- "Non-nil means that `inferior-octave-complete' is impossible.")
-
-(defvar inferior-octave-has-built-in-variables nil
- "Non-nil means that Octave has built-in variables.")
-
-(defvar inferior-octave-dynamic-complete-functions
- '(inferior-octave-completion-at-point comint-filename-completion)
- "List of functions called to perform completion for inferior Octave.
-This variable is used to initialize `comint-dynamic-complete-functions'
-in the Inferior Octave buffer.")
-
-(defvar info-lookup-mode)
-
-(define-derived-mode inferior-octave-mode comint-mode "Inferior Octave"
- "Major mode for interacting with an inferior Octave process.
-Runs Octave as a subprocess of Emacs, with Octave I/O through an Emacs
-buffer.
-
-Entry to this mode successively runs the hooks `comint-mode-hook' and
-`inferior-octave-mode-hook'."
- (setq comint-prompt-regexp inferior-octave-prompt
- mode-line-process '(":%s")
- local-abbrev-table octave-abbrev-table)
-
- (set (make-local-variable 'comment-start) octave-comment-start)
- (set (make-local-variable 'comment-end) "")
- (set (make-local-variable 'comment-column) 32)
- (set (make-local-variable 'comment-start-skip) octave-comment-start-skip)
-
- (set (make-local-variable 'font-lock-defaults)
- '(inferior-octave-font-lock-keywords nil nil))
-
- (set (make-local-variable 'info-lookup-mode) 'octave-mode)
-
- (setq comint-input-ring-file-name
- (or (getenv "OCTAVE_HISTFILE") "~/.octave_hist")
- comint-input-ring-size (or (getenv "OCTAVE_HISTSIZE") 1024))
- (set (make-local-variable 'comint-dynamic-complete-functions)
- inferior-octave-dynamic-complete-functions)
- (add-hook 'comint-input-filter-functions
- 'inferior-octave-directory-tracker nil t)
- (comint-read-input-ring t))
-
-;;;###autoload
-(defun inferior-octave (&optional arg)
- "Run an inferior Octave process, I/O via `inferior-octave-buffer'.
-This buffer is put in Inferior Octave mode. See `inferior-octave-mode'.
-
-Unless ARG is non-nil, switches to this buffer.
-
-The elements of the list `inferior-octave-startup-args' are sent as
-command line arguments to the inferior Octave process on startup.
-
-Additional commands to be executed on startup can be provided either in
-the file specified by `inferior-octave-startup-file' or by the default
-startup file, `~/.emacs-octave'."
- (interactive "P")
- (let ((buffer inferior-octave-buffer))
- (get-buffer-create buffer)
- (if (comint-check-proc buffer)
- ()
- (with-current-buffer buffer
- (comint-mode)
- (inferior-octave-startup)
- (inferior-octave-mode)))
- (if (not arg)
- (pop-to-buffer buffer))))
-
-;;;###autoload
-(defalias 'run-octave 'inferior-octave)
-
-(defun inferior-octave-startup ()
- "Start an inferior Octave process."
- (let ((proc (comint-exec-1
- (substring inferior-octave-buffer 1 -1)
- inferior-octave-buffer
- inferior-octave-program
- (append (list "-i" "--no-line-editing")
- inferior-octave-startup-args))))
- (set-process-filter proc 'inferior-octave-output-digest)
- (setq comint-ptyp process-connection-type
- inferior-octave-process proc
- inferior-octave-output-list nil
- inferior-octave-output-string nil
- inferior-octave-receive-in-progress t)
-
- ;; This may look complicated ... However, we need to make sure that
- ;; we additional startup code only AFTER Octave is ready (otherwise,
- ;; output may be mixed up). Hence, we need to digest the Octave
- ;; output to see when it issues a prompt.
- (while inferior-octave-receive-in-progress
- (accept-process-output inferior-octave-process))
- (goto-char (point-max))
- (set-marker (process-mark proc) (point))
- (insert-before-markers
- (concat
- (if (not (bobp)) "\f\n")
- (if inferior-octave-output-list
- (concat (mapconcat
- 'identity inferior-octave-output-list "\n")
- "\n"))))
-
- ;; Find out whether Octave has built-in variables.
- (inferior-octave-send-list-and-digest
- (list "exist \"LOADPATH\"\n"))
- (setq inferior-octave-has-built-in-variables
- (string-match "101$" (car inferior-octave-output-list)))
-
- ;; An empty secondary prompt, as e.g. obtained by '--braindead',
- ;; means trouble.
- (inferior-octave-send-list-and-digest (list "PS2\n"))
- (if (string-match "\\(PS2\\|ans\\) = *$" (car inferior-octave-output-list))
- (inferior-octave-send-list-and-digest
- (list (if inferior-octave-has-built-in-variables
- "PS2 = \"> \"\n"
- "PS2 (\"> \");\n"))))
-
- ;; O.k., now we are ready for the Inferior Octave startup commands.
- (let* (commands
- (program (file-name-nondirectory inferior-octave-program))
- (file (or inferior-octave-startup-file
- (concat "~/.emacs-" program))))
- (setq commands
- (list "more off;\n"
- (if (not (string-equal
- inferior-octave-output-string ">> "))
- (if inferior-octave-has-built-in-variables
- "PS1=\"\\\\s> \";\n"
- "PS1 (\"\\\\s> \");\n"))
- (if (file-exists-p file)
- (format "source (\"%s\");\n" file))))
- (inferior-octave-send-list-and-digest commands))
- (insert-before-markers
- (concat
- (if inferior-octave-output-list
- (concat (mapconcat
- 'identity inferior-octave-output-list "\n")
- "\n"))
- inferior-octave-output-string))
- ;; Next, we check whether Octave supports `completion_matches' ...
- (inferior-octave-send-list-and-digest
- (list "exist \"completion_matches\"\n"))
- (setq inferior-octave-complete-impossible
- (not (string-match "5$" (car inferior-octave-output-list))))
-
- ;; And finally, everything is back to normal.
- (set-process-filter proc 'inferior-octave-output-filter)
- (run-hooks 'inferior-octave-startup-hook)
- (run-hooks 'inferior-octave-startup-hook)
- ;; Just in case, to be sure a cd in the startup file
- ;; won't have detrimental effects.
- (inferior-octave-resync-dirs)))
-
-\f
-(defun inferior-octave-completion-at-point ()
- "Return the data to complete the Octave symbol at point."
- (let* ((end (point))
- (start
- (save-excursion
- (skip-syntax-backward "w_" (comint-line-beginning-position))
- (point))))
- (cond ((eq start end) nil)
- (inferior-octave-complete-impossible
- (message (concat
- "Your Octave does not have `completion_matches'. "
- "Please upgrade to version 2.X."))
- nil)
- (t
- (list
- start end
- (completion-table-dynamic
- (lambda (command)
- (inferior-octave-send-list-and-digest
- (list (concat "completion_matches (\"" command "\");\n")))
- (sort (delete-dups inferior-octave-output-list)
- 'string-lessp))))))))
-
-(define-obsolete-function-alias 'inferior-octave-complete
- 'completion-at-point "24.1")
-
-(defun inferior-octave-dynamic-list-input-ring ()
- "List the buffer's input history in a help buffer."
- ;; We cannot use `comint-dynamic-list-input-ring', because it replaces
- ;; "completion" by "history reference" ...
- (interactive)
- (if (or (not (ring-p comint-input-ring))
- (ring-empty-p comint-input-ring))
- (message "No history")
- (let ((history nil)
- (history-buffer " *Input History*")
- (index (1- (ring-length comint-input-ring)))
- (conf (current-window-configuration)))
- ;; We have to build up a list ourselves from the ring vector.
- (while (>= index 0)
- (setq history (cons (ring-ref comint-input-ring index) history)
- index (1- index)))
- ;; Change "completion" to "history reference"
- ;; to make the display accurate.
- (with-output-to-temp-buffer history-buffer
- (display-completion-list history)
- (set-buffer history-buffer))
- (message "Hit space to flush")
- (let ((ch (read-event)))
- (if (eq ch ?\ )
- (set-window-configuration conf)
- (setq unread-command-events (list ch)))))))
-
-(defun inferior-octave-strip-ctrl-g (string)
- "Strip leading `^G' character.
-If STRING starts with a `^G', ring the bell and strip it."
- (if (string-match "^\a" string)
- (progn
- (ding)
- (setq string (substring string 1))))
- string)
-
-(defun inferior-octave-output-filter (proc string)
- "Standard output filter for the inferior Octave process.
-Ring Emacs bell if process output starts with an ASCII bell, and pass
-the rest to `comint-output-filter'."
- (comint-output-filter proc (inferior-octave-strip-ctrl-g string)))
-
-(defun inferior-octave-output-digest (_proc string)
- "Special output filter for the inferior Octave process.
-Save all output between newlines into `inferior-octave-output-list', and
-the rest to `inferior-octave-output-string'."
- (setq string (concat inferior-octave-output-string string))
- (while (string-match "\n" string)
- (setq inferior-octave-output-list
- (append inferior-octave-output-list
- (list (substring string 0 (match-beginning 0))))
- string (substring string (match-end 0))))
- (if (string-match inferior-octave-prompt string)
- (setq inferior-octave-receive-in-progress nil))
- (setq inferior-octave-output-string string))
-
-(defun inferior-octave-send-list-and-digest (list)
- "Send LIST to the inferior Octave process and digest the output.
-The elements of LIST have to be strings and are sent one by one. All
-output is passed to the filter `inferior-octave-output-digest'."
- (let* ((proc inferior-octave-process)
- string)
- (add-function :override (process-filter proc)
- #'inferior-octave-output-digest)
- (setq inferior-octave-output-list nil)
- (unwind-protect
- (while (setq string (car list))
- (setq inferior-octave-output-string nil
- inferior-octave-receive-in-progress t)
- (comint-send-string proc string)
- (while inferior-octave-receive-in-progress
- (accept-process-output proc))
- (setq list (cdr list)))
- (remove-function (process-filter proc)
- #'inferior-octave-output-digest))))
-
-(defun inferior-octave-directory-tracker (string)
- "Tracks `cd' commands issued to the inferior Octave process.
-Use \\[inferior-octave-resync-dirs] to resync if Emacs gets confused."
- (cond
- ((string-match "^[ \t]*cd[ \t;]*$" string)
- (cd "~"))
- ((string-match "^[ \t]*cd[ \t]+\\([^ \t\n;]*\\)[ \t\n;]*" string)
- (cd (substring string (match-beginning 1) (match-end 1))))))
-
-(defun inferior-octave-resync-dirs ()
- "Resync the buffer's idea of the current directory.
-This command queries the inferior Octave process about its current
-directory and makes this the current buffer's default directory."
- (interactive)
- (inferior-octave-send-list-and-digest '("disp (pwd ())\n"))
- (cd (car inferior-octave-output-list)))
-
-;;; provide ourself
-
-(provide 'octave-inf)
-
-;;; octave-inf.el ends here
+++ /dev/null
-;;; octave-mod.el --- editing Octave source files under Emacs
-
-;; Copyright (C) 1997, 2001-2013 Free Software Foundation, Inc.
-
-;; Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
-;; John Eaton <jwe@octave.org>
-;; Maintainer: FSF
-;; Keywords: languages
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This package provides Emacs support for Octave.
-;; It defines Octave mode, a major mode for editing
-;; Octave code.
-
-;; The file octave-inf.el contains code for interacting with an inferior
-;; Octave process using comint.
-
-;; See the documentation of `octave-mode' and
-;; `run-octave' for further information on usage and customization.
-
-;;; Code:
-(require 'custom)
-
-(defgroup octave nil
- "Major mode for editing Octave source files."
- :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
- :group 'languages)
-
-(defvar inferior-octave-output-list nil)
-(defvar inferior-octave-output-string nil)
-(defvar inferior-octave-receive-in-progress nil)
-
-(declare-function inferior-octave-send-list-and-digest "octave-inf" (list))
-
-(defconst octave-maintainer-address
- "Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>, bug-gnu-emacs@gnu.org"
- "Current maintainer of the Emacs Octave package.")
-
-(define-abbrev-table 'octave-abbrev-table
- (mapcar (lambda (e) (append e '(nil 0 t)))
- '(("`a" "all_va_args")
- ("`b" "break")
- ("`cs" "case")
- ("`ca" "catch")
- ("`c" "continue")
- ("`el" "else")
- ("`eli" "elseif")
- ("`et" "end_try_catch")
- ("`eu" "end_unwind_protect")
- ("`ef" "endfor")
- ("`efu" "endfunction")
- ("`ei" "endif")
- ("`es" "endswitch")
- ("`ew" "endwhile")
- ("`f" "for")
- ("`fu" "function")
- ("`gl" "global")
- ("`gp" "gplot")
- ("`gs" "gsplot")
- ("`if" "if ()")
- ("`o" "otherwise")
- ("`rp" "replot")
- ("`r" "return")
- ("`s" "switch")
- ("`t" "try")
- ("`u" "until ()")
- ("`up" "unwind_protect")
- ("`upc" "unwind_protect_cleanup")
- ("`w" "while ()")))
- "Abbrev table for Octave's reserved words.
-Used in `octave-mode' and inferior-octave-mode buffers.
-All Octave abbrevs start with a grave accent (`)."
- :regexp "\\(?:[^`]\\|^\\)\\(\\(?:\\<\\|`\\)\\w+\\)\\W*")
-
-(defvar octave-comment-char ?#
- "Character to start an Octave comment.")
-(defvar octave-comment-start
- (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.")
-
-(defvar octave-begin-keywords
- '("do" "for" "function" "if" "switch" "try" "unwind_protect" "while"))
-(defvar octave-else-keywords
- '("case" "catch" "else" "elseif" "otherwise" "unwind_protect_cleanup"))
-(defvar octave-end-keywords
- '("endfor" "endfunction" "endif" "endswitch" "end_try_catch"
- "end_unwind_protect" "endwhile" "until" "end"))
-
-(defvar octave-reserved-words
- (append octave-begin-keywords
- octave-else-keywords
- octave-end-keywords
- '("break" "continue" "end" "global" "persistent" "return"))
- "Reserved words in Octave.")
-
-(defvar octave-text-functions
- '("casesen" "cd" "chdir" "clear" "diary" "dir" "document" "echo"
- "edit_history" "format" "help" "history" "hold"
- "load" "ls" "more" "run_history" "save" "type"
- "which" "who" "whos")
- "Text functions in Octave.")
-
-(defvar octave-variables
- '("DEFAULT_EXEC_PATH" "DEFAULT_LOADPATH"
- "EDITOR" "EXEC_PATH" "F_DUPFD" "F_GETFD" "F_GETFL" "F_SETFD"
- "F_SETFL" "I" "IMAGE_PATH" "Inf" "J"
- "NaN" "OCTAVE_VERSION" "O_APPEND" "O_CREAT" "O_EXCL"
- "O_NONBLOCK" "O_RDONLY" "O_RDWR" "O_TRUNC" "O_WRONLY" "PAGER" "PS1"
- "PS2" "PS4" "PWD" "SEEK_CUR" "SEEK_END" "SEEK_SET" "__F_DUPFD__"
- "__F_GETFD__" "__F_GETFL__" "__F_SETFD__" "__F_SETFL__" "__I__"
- "__Inf__" "__J__" "__NaN__" "__OCTAVE_VERSION__" "__O_APPEND__"
- "__O_CREAT__" "__O_EXCL__" "__O_NONBLOCK__" "__O_RDONLY__"
- "__O_RDWR__" "__O_TRUNC__" "__O_WRONLY__" "__PWD__" "__SEEK_CUR__"
- "__SEEK_END__" "__SEEK_SET__" "__argv__" "__e__" "__eps__"
- "__i__" "__inf__" "__j__" "__nan__" "__pi__"
- "__program_invocation_name__" "__program_name__" "__realmax__"
- "__realmin__" "__stderr__" "__stdin__" "__stdout__" "ans" "argv"
- "beep_on_error" "completion_append_char"
- "crash_dumps_octave_core" "default_save_format"
- "e" "echo_executing_commands" "eps"
- "error_text" "gnuplot_binary" "history_file"
- "history_size" "ignore_function_time_stamp"
- "inf" "nan" "nargin" "output_max_field_width" "output_precision"
- "page_output_immediately" "page_screen_output" "pi"
- "print_answer_id_name" "print_empty_dimensions"
- "program_invocation_name" "program_name"
- "realmax" "realmin" "return_last_computed_value" "save_precision"
- "saving_history" "sighup_dumps_octave_core" "sigterm_dumps_octave_core"
- "silent_functions" "split_long_rows" "stderr" "stdin" "stdout"
- "string_fill_char" "struct_levels_to_print"
- "suppress_verbose_help_message")
- "Builtin variables in Octave.")
-
-(defvar octave-function-header-regexp
- (concat "^\\s-*\\_<\\(function\\)\\_>"
- "\\([^=;\n]*=[ \t]*\\|[ \t]*\\)\\(\\(?:\\w\\|\\s_\\)+\\)\\_>")
- "Regexp to match an Octave function header.
-The string `function' and its name are given by the first and third
-parenthetical grouping.")
-
-(defvar octave-font-lock-keywords
- (list
- ;; Fontify all builtin keywords.
- (cons (concat "\\_<\\("
- (regexp-opt (append octave-reserved-words
- octave-text-functions))
- "\\)\\_>")
- 'font-lock-keyword-face)
- ;; Fontify all builtin operators.
- (cons "\\(&\\||\\|<=\\|>=\\|==\\|<\\|>\\|!=\\|!\\)"
- (if (boundp 'font-lock-builtin-face)
- 'font-lock-builtin-face
- 'font-lock-preprocessor-face))
- ;; Fontify all builtin variables.
- (cons (concat "\\_<" (regexp-opt octave-variables) "\\_>")
- 'font-lock-variable-name-face)
- ;; Fontify all function declarations.
- (list octave-function-header-regexp
- '(1 font-lock-keyword-face)
- '(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
- :group 'octave-inferior)
-
-(defvar inferior-octave-process nil)
-\f
-(defvar octave-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "`" 'octave-abbrev-start)
- (define-key map "\e\n" 'octave-indent-new-comment-line)
- (define-key map "\M-\C-q" 'octave-indent-defun)
- (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 [remap down-list] 'smie-down-list)
- (define-key map "\C-c\M-\C-h" 'octave-mark-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-il" 'octave-send-line)
- (define-key map "\C-c\C-ib" 'octave-send-block)
- (define-key map "\C-c\C-if" 'octave-send-defun)
- (define-key map "\C-c\C-ir" 'octave-send-region)
- (define-key map "\C-c\C-is" 'octave-show-process-buffer)
- (define-key map "\C-c\C-iq" 'octave-hide-process-buffer)
- (define-key map "\C-c\C-ik" 'octave-kill-process)
- (define-key map "\C-c\C-i\C-l" 'octave-send-line)
- (define-key map "\C-c\C-i\C-b" 'octave-send-block)
- (define-key map "\C-c\C-i\C-f" 'octave-send-defun)
- (define-key map "\C-c\C-i\C-r" 'octave-send-region)
- (define-key map "\C-c\C-i\C-s" 'octave-show-process-buffer)
- (define-key map "\C-c\C-i\C-q" 'octave-hide-process-buffer)
- (define-key map "\C-c\C-i\C-k" 'octave-kill-process)
- map)
- "Keymap used in Octave mode.")
-
-
-
-(easy-menu-define octave-mode-menu octave-mode-map
- "Menu for Octave mode."
- '("Octave"
- ("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"
- ["Mark Block" octave-mark-block t]
- ["Close Block" smie-close-block t])
- ("Functions"
- ["Indent Function" octave-indent-defun t]
- ["Insert Function" octave-insert-defun t])
- "-"
- ("Debug"
- ["Send Current Line" octave-send-line t]
- ["Send Current Block" octave-send-block t]
- ["Send Current Function" octave-send-defun t]
- ["Send Region" octave-send-region t]
- ["Show Process Buffer" octave-show-process-buffer t]
- ["Hide Process Buffer" octave-hide-process-buffer t]
- ["Kill Process" octave-kill-process t])
- "-"
- ["Indent Line" indent-according-to-mode t]
- ["Complete Symbol" completion-at-point 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" describe-mode t]
- ["Lookup Octave Index" info-lookup-symbol t]))
-
-(defvar octave-mode-syntax-table
- (let ((table (make-syntax-table)))
- (modify-syntax-entry ?\r " " table)
- (modify-syntax-entry ?+ "." table)
- (modify-syntax-entry ?- "." table)
- (modify-syntax-entry ?= "." table)
- (modify-syntax-entry ?* "." table)
- (modify-syntax-entry ?/ "." table)
- (modify-syntax-entry ?> "." table)
- (modify-syntax-entry ?< "." table)
- (modify-syntax-entry ?& "." table)
- (modify-syntax-entry ?| "." table)
- (modify-syntax-entry ?! "." table)
- (modify-syntax-entry ?\\ "\\" table)
- (modify-syntax-entry ?\' "." table)
- ;; Was "w" for abbrevs, but now that it's not necessary any more,
- (modify-syntax-entry ?\` "." table)
- (modify-syntax-entry ?\" "\"" 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-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-comment-start
- (concat (make-string 2 octave-comment-char) " ")
- "String to insert to start a new Octave comment on an empty line.")
-
-(defcustom octave-continuation-offset 4
- "Extra indentation applied to Octave continuation lines."
- :type 'integer
- :group 'octave)
-(eval-and-compile
- (defconst octave-continuation-marker-regexp "\\\\\\|\\.\\.\\."))
-(defvar octave-continuation-regexp
- (concat "[^#%\n]*\\(" octave-continuation-marker-regexp
- "\\)\\s-*\\(\\s<.*\\)?$"))
-(defcustom octave-continuation-string "\\"
- "Character string used for Octave continuation lines. Normally \\."
- :type 'string
- :group 'octave)
-
-(defvar octave-completion-alist nil
- "Alist of Octave symbols for completion in Octave mode.
-Each element looks like (VAR . VAR), where the car and cdr are the same
-symbol (an Octave command or variable name).
-Currently, only builtin variables can be completed.")
-
-(defvar octave-mode-imenu-generic-expression
- (list
- ;; Functions
- (list nil octave-function-header-regexp 3))
- "Imenu expression for Octave mode. See `imenu-generic-expression'.")
-
-(defcustom octave-mode-hook nil
- "Hook to be run when Octave mode is started."
- :type 'hook
- :group 'octave)
-
-(defcustom octave-send-show-buffer t
- "Non-nil means display `inferior-octave-buffer' after sending to it."
- :type 'boolean
- :group 'octave)
-(defcustom octave-send-line-auto-forward t
- "Control auto-forward after sending to the inferior Octave process.
-Non-nil means always go to the next Octave code line after sending."
- :type 'boolean
- :group 'octave)
-(defcustom octave-send-echo-input t
- "Non-nil means echo input sent to the inferior Octave process."
- :type 'boolean
- :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 "$\\|[%#]")
- (not (smie-rule-bolp))
- ;; 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
-(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
-Font Lock mode on terminals that support it).
-
-Octave itself is a high-level language, primarily intended for numerical
-computations. It provides a convenient command line interface for
-solving linear and nonlinear problems numerically. Function definitions
-can also be stored in files, and it can be used in a batch mode (which
-is why you need this mode!).
-
-The latest released version of Octave is always available via anonymous
-ftp from ftp.octave.org in the directory `/pub/octave'. Complete
-source and binaries for several popular systems are available.
-
-Type \\[list-abbrevs] to display the built-in abbrevs for Octave keywords.
-
-Keybindings
-===========
-
-\\{octave-mode-map}
-
-Variables you can use to customize Octave mode
-==============================================
-
-`octave-blink-matching-block'
- Non-nil means show matching begin of block when inserting a space,
- newline or semicolon after an else or end keyword. Default is t.
-
-`octave-block-offset'
- Extra indentation applied to statements in block structures.
- Default is 2.
-
-`octave-continuation-offset'
- Extra indentation applied to Octave continuation lines.
- Default is 4.
-
-`octave-continuation-string'
- String used for Octave continuation lines.
- Default is a backslash.
-
-`octave-send-echo-input'
- Non-nil means always display `inferior-octave-buffer' after sending a
- command to the inferior Octave process.
-
-`octave-send-line-auto-forward'
- Non-nil means always go to the next unsent line of Octave code after
- sending a line to the inferior Octave process.
-
-`octave-send-echo-input'
- Non-nil means echo input sent to the inferior Octave process.
-
-Turning on Octave mode runs the hook `octave-mode-hook'.
-
-To begin using this mode for all `.m' files that you edit, add the
-following lines to your init file:
-
- (add-to-list 'auto-mode-alist '(\"\\\\.m\\\\'\" . octave-mode))
-
-To automatically turn on the abbrev and auto-fill features,
-add the following lines to your init file as well:
-
- (add-hook 'octave-mode-hook
- (lambda ()
- (abbrev-mode 1)
- (auto-fill-mode 1)))
-
-To submit a problem report, enter \\[octave-submit-bug-report] from \
-an Octave mode buffer.
-This automatically sets up a mail buffer with version information
-already added. You just need to add a description of the problem,
-including a reproducible test case and send the message."
- (setq local-abbrev-table octave-abbrev-table)
-
- (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))
-\f
-;;; Miscellaneous useful functions
-
-(defsubst octave-in-comment-p ()
- "Return t if point is inside an Octave comment."
- (nth 4 (syntax-ppss)))
-
-(defsubst octave-in-string-p ()
- "Return t if point is inside an Octave string."
- (nth 3 (syntax-ppss)))
-
-(defsubst octave-not-in-string-or-comment-p ()
- "Return t if point is not inside an Octave string or comment."
- (let ((pps (syntax-ppss)))
- (not (or (nth 3 pps) (nth 4 pps)))))
-
-
-(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-maybe-insert-continuation-string ()
- (if (or (octave-in-comment-p)
- (save-excursion
- (beginning-of-line)
- (looking-at octave-continuation-regexp)))
- nil
- (delete-horizontal-space)
- (insert (concat " " octave-continuation-string))))
-\f
-;;; Indentation
-
-(defun octave-indent-new-comment-line ()
- "Break Octave line at point, continuing comment if within one.
-If within code, insert `octave-continuation-string' before breaking the
-line. If within a string, signal an error.
-The new line is properly indented."
- (interactive)
- (delete-horizontal-space)
- (cond
- ((octave-in-comment-p)
- (indent-new-comment-line))
- ((octave-in-string-p)
- (error "Cannot split a code line inside a string"))
- (t
- (insert (concat " " octave-continuation-string))
- (reindent-then-newline-and-indent))))
-
-(defun octave-indent-defun ()
- "Properly indent the Octave function which contains point."
- (interactive)
- (save-excursion
- (mark-defun)
- (message "Indenting function...")
- (indent-region (point) (mark) nil))
- (message "Indenting function...done."))
-
-\f
-;;; Motion
-(defun octave-next-code-line (&optional arg)
- "Move ARG lines of Octave code forward (backward if ARG is negative).
-Skips past all empty and comment lines. Default for ARG is 1.
-
-On success, return 0. Otherwise, go as far as possible and return -1."
- (interactive "p")
- (or arg (setq arg 1))
- (beginning-of-line)
- (let ((n 0)
- (inc (if (> arg 0) 1 -1)))
- (while (and (/= arg 0) (= n 0))
- (setq n (forward-line inc))
- (while (and (= n 0)
- (looking-at "\\s-*\\($\\|\\s<\\)"))
- (setq n (forward-line inc)))
- (setq arg (- arg inc)))
- n))
-
-(defun octave-previous-code-line (&optional arg)
- "Move ARG lines of Octave code backward (forward if ARG is negative).
-Skips past all empty and comment lines. Default for ARG is 1.
-
-On success, return 0. Otherwise, go as far as possible and return -1."
- (interactive "p")
- (or arg (setq arg 1))
- (octave-next-code-line (- arg)))
-
-(defun octave-beginning-of-line ()
- "Move point to beginning of current Octave line.
-If on an empty or comment line, go to the beginning of that line.
-Otherwise, move backward to the beginning of the first Octave code line
-which is not inside a continuation statement, i.e., which does not
-follow a code line ending in `...' or `\\', or is inside an open
-parenthesis list."
- (interactive)
- (beginning-of-line)
- (if (not (looking-at "\\s-*\\($\\|\\s<\\)"))
- (while (or (condition-case nil
- (progn
- (up-list -1)
- (beginning-of-line)
- t)
- (error nil))
- (and (or (looking-at "\\s-*\\($\\|\\s<\\)")
- (save-excursion
- (if (zerop (octave-previous-code-line))
- (looking-at octave-continuation-regexp))))
- (zerop (forward-line -1)))))))
-
-(defun octave-end-of-line ()
- "Move point to end of current Octave line.
-If on an empty or comment line, go to the end of that line.
-Otherwise, move forward to the end of the first Octave code line which
-does not end in `...' or `\\' or is inside an open parenthesis list."
- (interactive)
- (end-of-line)
- (if (save-excursion
- (beginning-of-line)
- (looking-at "\\s-*\\($\\|\\s<\\)"))
- ()
- (while (or (condition-case nil
- (progn
- (up-list 1)
- (end-of-line)
- t)
- (error nil))
- (and (save-excursion
- (beginning-of-line)
- (or (looking-at "\\s-*\\($\\|\\s<\\)")
- (looking-at octave-continuation-regexp)))
- (zerop (forward-line 1)))))
- (end-of-line)))
-
-(defun octave-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)
- (if (and (looking-at "\\sw\\|\\s_")
- (looking-back "\\sw\\|\\s_" (1- (point))))
- (skip-syntax-forward "w_"))
- (unless (or (looking-at "\\s(")
- (save-excursion
- (let* ((token (funcall smie-forward-token-function))
- (level (assoc token smie-grammar)))
- (and level (not (numberp (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."
- (let* ((arg (or arg 1))
- (inc (if (> arg 0) 1 -1))
- (found nil)
- (case-fold-search nil))
- (and (not (eobp))
- (not (and (> arg 0) (looking-at "\\_<function\\_>")))
- (skip-syntax-forward "w"))
- (while (and (/= arg 0)
- (setq found
- (re-search-backward "\\_<function\\_>" inc)))
- (if (octave-not-in-string-or-comment-p)
- (setq arg (- arg inc))))
- (if found
- (progn
- (and (< inc 0) (goto-char (match-beginning 0)))
- t))))
-
-\f
-;;; Filling
-(defun octave-auto-fill ()
- "Perform auto-fill in Octave mode.
-Returns nil if no feasible place to break the line could be found, and t
-otherwise."
- (let (fc give-up)
- (if (or (null (setq fc (current-fill-column)))
- (save-excursion
- (beginning-of-line)
- (and auto-fill-inhibit-regexp
- (octave-looking-at-kw auto-fill-inhibit-regexp))))
- nil ; Can't do anything
- (if (and (not (octave-in-comment-p))
- (> (current-column) fc))
- (setq fc (- fc (+ (length octave-continuation-string) 1))))
- (while (and (not give-up) (> (current-column) fc))
- (let* ((opoint (point))
- (fpoint
- (save-excursion
- (move-to-column (+ fc 1))
- (skip-chars-backward "^ \t\n")
- ;; If we're at the beginning of the line, break after
- ;; the first word
- (if (bolp)
- (re-search-forward "[ \t]" opoint t))
- ;; If we're in a comment line, don't break after the
- ;; comment chars
- (if (save-excursion
- (skip-syntax-backward " <")
- (bolp))
- (re-search-forward "[ \t]" (line-end-position)
- 'move))
- ;; If we're not in a comment line and just ahead the
- ;; continuation string, don't break here.
- (if (and (not (octave-in-comment-p))
- (looking-at
- (concat "\\s-*"
- (regexp-quote
- octave-continuation-string)
- "\\s-*$")))
- (end-of-line))
- (skip-chars-backward " \t")
- (point))))
- (if (save-excursion
- (goto-char fpoint)
- (not (or (bolp) (eolp))))
- (let ((prev-column (current-column)))
- (if (save-excursion
- (skip-chars-backward " \t")
- (= (point) fpoint))
- (progn
- (octave-maybe-insert-continuation-string)
- (indent-new-comment-line t))
- (save-excursion
- (goto-char fpoint)
- (octave-maybe-insert-continuation-string)
- (indent-new-comment-line t)))
- (if (>= (current-column) prev-column)
- (setq give-up t)))
- (setq give-up t))))
- (not give-up))))
-
-(defun octave-fill-paragraph (&optional _arg)
- "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
-(defun octave-initialize-completions ()
- "Create an alist for Octave completions."
- (if octave-completion-alist
- ()
- (setq octave-completion-alist
- (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 (skip-syntax-backward "w_") (point)))
- (end (point)))
- (if (< beg (point))
- ;; Extend region past point, if applicable.
- (save-excursion (skip-syntax-forward "w_")
- (setq end (point))))
- (list beg end octave-completion-alist)))
-
-(define-obsolete-function-alias 'octave-complete-symbol
- 'completion-at-point "24.1")
-\f
-;;; Electric characters && friends
-
-(defun octave-abbrev-start ()
- "Start entering an Octave abbreviation.
-If Abbrev mode is turned on, typing ` (grave accent) followed by ? or
-\\[help-command] lists all Octave abbrevs. Any other key combination is
-executed normally.
-Note that all Octave mode abbrevs start with a grave accent."
- (interactive)
- (self-insert-command 1)
- (when abbrev-mode
- (set-temporary-overlay-map
- (let ((map (make-sparse-keymap)))
- (define-key map [??] 'list-abbrevs)
- (define-key map (vector help-char) 'list-abbrevs)
- map))))
-
-(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)."
- (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 ()
- "Kill inferior Octave process and its buffer."
- (interactive)
- (if inferior-octave-process
- (progn
- (process-send-string inferior-octave-process "quit;\n")
- (accept-process-output inferior-octave-process)))
- (if inferior-octave-buffer
- (kill-buffer inferior-octave-buffer)))
-
-(defun octave-show-process-buffer ()
- "Make sure that `inferior-octave-buffer' is displayed."
- (interactive)
- (if (get-buffer inferior-octave-buffer)
- (display-buffer inferior-octave-buffer)
- (message "No buffer named %s" inferior-octave-buffer)))
-
-(defun octave-hide-process-buffer ()
- "Delete all windows that display `inferior-octave-buffer'."
- (interactive)
- (if (get-buffer inferior-octave-buffer)
- (delete-windows-on inferior-octave-buffer)
- (message "No buffer named %s" inferior-octave-buffer)))
-
-(defun octave-send-region (beg end)
- "Send current region to the inferior Octave process."
- (interactive "r")
- (inferior-octave t)
- (let ((proc inferior-octave-process)
- (string (buffer-substring-no-properties beg end))
- line)
- (with-current-buffer inferior-octave-buffer
- (setq inferior-octave-output-list nil)
- (while (not (string-equal string ""))
- (if (string-match "\n" string)
- (setq line (substring string 0 (match-beginning 0))
- string (substring string (match-end 0)))
- (setq line string string ""))
- (setq inferior-octave-receive-in-progress t)
- (inferior-octave-send-list-and-digest (list (concat line "\n")))
- (while inferior-octave-receive-in-progress
- (accept-process-output proc))
- (insert-before-markers
- (mapconcat 'identity
- (append
- (if octave-send-echo-input (list line) (list ""))
- (mapcar 'inferior-octave-strip-ctrl-g
- inferior-octave-output-list)
- (list inferior-octave-output-string))
- "\n")))))
- (if octave-send-show-buffer
- (display-buffer inferior-octave-buffer)))
-
-(defun octave-send-block ()
- "Send current Octave block to the inferior Octave process."
- (interactive)
- (save-excursion
- (octave-mark-block)
- (octave-send-region (point) (mark))))
-
-(defun octave-send-defun ()
- "Send current Octave function to the inferior Octave process."
- (interactive)
- (save-excursion
- (mark-defun)
- (octave-send-region (point) (mark))))
-
-(defun octave-send-line (&optional arg)
- "Send current Octave code line to the inferior Octave process.
-With positive prefix ARG, send that many lines.
-If `octave-send-line-auto-forward' is non-nil, go to the next unsent
-code line."
- (interactive "P")
- (or arg (setq arg 1))
- (if (> arg 0)
- (let (beg end)
- (beginning-of-line)
- (setq beg (point))
- (octave-next-code-line (- arg 1))
- (end-of-line)
- (setq end (point))
- (if octave-send-line-auto-forward
- (octave-next-code-line 1))
- (octave-send-region beg end))))
-
-(defun octave-eval-print-last-sexp ()
- "Evaluate Octave sexp before point and print value into current buffer."
- (interactive)
- (inferior-octave t)
- (let ((standard-output (current-buffer))
- (print-escape-newlines nil)
- (opoint (point)))
- (terpri)
- (prin1
- (save-excursion
- (forward-sexp -1)
- (inferior-octave-send-list-and-digest
- (list (concat (buffer-substring-no-properties (point) opoint)
- "\n")))
- (mapconcat 'identity inferior-octave-output-list "\n")))
- (terpri)))
-\f
-;;; Bug reporting
-(defun octave-submit-bug-report ()
- "Submit a bug report on the Emacs Octave package via mail."
- (interactive)
- (require 'reporter)
- (and
- (y-or-n-p "Do you want to submit a bug report? ")
- (reporter-submit-bug-report
- octave-maintainer-address
- (concat "Emacs version " emacs-version)
- (list
- 'octave-blink-matching-block
- 'octave-block-offset
- 'octave-comment-char
- 'octave-continuation-offset
- 'octave-continuation-string
- 'octave-send-echo-input
- 'octave-send-line-auto-forward
- 'octave-send-show-buffer))))
-
-;; provide ourself
-
-(provide 'octave-mod)
-
-;;; octave-mod.el ends here
--- /dev/null
+;;; octave.el --- editing octave source files under emacs
+
+;; Copyright (C) 1997, 2001-2013 Free Software Foundation, Inc.
+
+;; Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
+;; John Eaton <jwe@octave.org>
+;; Maintainer: FSF
+;; Keywords: languages
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package provides emacs support for octave. It defines a major
+;; mode for editing octave code and contains code for interacting with
+;; an inferior octave process using comint.
+
+;; See the documentation of `octave-mode' and `run-octave' for further
+;; information on usage and customization.
+
+;;; Code:
+(require 'comint)
+
+(defgroup octave nil
+ "Editing Octave code."
+ :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
+ :group 'languages)
+
+(defconst octave-maintainer-address
+ "Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>, bug-gnu-emacs@gnu.org"
+ "Current maintainer of the Emacs Octave package.")
+
+(define-abbrev-table 'octave-abbrev-table
+ (mapcar (lambda (e) (append e '(nil 0 t)))
+ '(("`a" "all_va_args")
+ ("`b" "break")
+ ("`cs" "case")
+ ("`ca" "catch")
+ ("`c" "continue")
+ ("`el" "else")
+ ("`eli" "elseif")
+ ("`et" "end_try_catch")
+ ("`eu" "end_unwind_protect")
+ ("`ef" "endfor")
+ ("`efu" "endfunction")
+ ("`ei" "endif")
+ ("`es" "endswitch")
+ ("`ew" "endwhile")
+ ("`f" "for")
+ ("`fu" "function")
+ ("`gl" "global")
+ ("`gp" "gplot")
+ ("`gs" "gsplot")
+ ("`if" "if ()")
+ ("`o" "otherwise")
+ ("`rp" "replot")
+ ("`r" "return")
+ ("`s" "switch")
+ ("`t" "try")
+ ("`u" "until ()")
+ ("`up" "unwind_protect")
+ ("`upc" "unwind_protect_cleanup")
+ ("`w" "while ()")))
+ "Abbrev table for Octave's reserved words.
+Used in `octave-mode' and `inferior-octave-mode' buffers.
+All Octave abbrevs start with a grave accent (`)."
+ :regexp "\\(?:[^`]\\|^\\)\\(\\(?:\\<\\|`\\)\\w+\\)\\W*")
+
+(defvar octave-comment-char ?#
+ "Character to start an Octave comment.")
+(defvar octave-comment-start
+ (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.")
+
+(defvar octave-begin-keywords
+ '("do" "for" "function" "if" "switch" "try" "unwind_protect" "while"))
+(defvar octave-else-keywords
+ '("case" "catch" "else" "elseif" "otherwise" "unwind_protect_cleanup"))
+(defvar octave-end-keywords
+ '("endfor" "endfunction" "endif" "endswitch" "end_try_catch"
+ "end_unwind_protect" "endwhile" "until" "end"))
+
+(defvar octave-reserved-words
+ (append octave-begin-keywords
+ octave-else-keywords
+ octave-end-keywords
+ '("break" "continue" "end" "global" "persistent" "return"))
+ "Reserved words in Octave.")
+
+(defvar octave-text-functions
+ '("casesen" "cd" "chdir" "clear" "diary" "dir" "document" "echo"
+ "edit_history" "format" "help" "history" "hold"
+ "load" "ls" "more" "run_history" "save" "type"
+ "which" "who" "whos")
+ "Text functions in Octave.")
+
+(defvar octave-variables
+ '("DEFAULT_EXEC_PATH" "DEFAULT_LOADPATH"
+ "EDITOR" "EXEC_PATH" "F_DUPFD" "F_GETFD" "F_GETFL" "F_SETFD"
+ "F_SETFL" "I" "IMAGE_PATH" "Inf" "J"
+ "NaN" "OCTAVE_VERSION" "O_APPEND" "O_CREAT" "O_EXCL"
+ "O_NONBLOCK" "O_RDONLY" "O_RDWR" "O_TRUNC" "O_WRONLY" "PAGER" "PS1"
+ "PS2" "PS4" "PWD" "SEEK_CUR" "SEEK_END" "SEEK_SET" "__F_DUPFD__"
+ "__F_GETFD__" "__F_GETFL__" "__F_SETFD__" "__F_SETFL__" "__I__"
+ "__Inf__" "__J__" "__NaN__" "__OCTAVE_VERSION__" "__O_APPEND__"
+ "__O_CREAT__" "__O_EXCL__" "__O_NONBLOCK__" "__O_RDONLY__"
+ "__O_RDWR__" "__O_TRUNC__" "__O_WRONLY__" "__PWD__" "__SEEK_CUR__"
+ "__SEEK_END__" "__SEEK_SET__" "__argv__" "__e__" "__eps__"
+ "__i__" "__inf__" "__j__" "__nan__" "__pi__"
+ "__program_invocation_name__" "__program_name__" "__realmax__"
+ "__realmin__" "__stderr__" "__stdin__" "__stdout__" "ans" "argv"
+ "beep_on_error" "completion_append_char"
+ "crash_dumps_octave_core" "default_save_format"
+ "e" "echo_executing_commands" "eps"
+ "error_text" "gnuplot_binary" "history_file"
+ "history_size" "ignore_function_time_stamp"
+ "inf" "nan" "nargin" "output_max_field_width" "output_precision"
+ "page_output_immediately" "page_screen_output" "pi"
+ "print_answer_id_name" "print_empty_dimensions"
+ "program_invocation_name" "program_name"
+ "realmax" "realmin" "return_last_computed_value" "save_precision"
+ "saving_history" "sighup_dumps_octave_core" "sigterm_dumps_octave_core"
+ "silent_functions" "split_long_rows" "stderr" "stdin" "stdout"
+ "string_fill_char" "struct_levels_to_print"
+ "suppress_verbose_help_message")
+ "Builtin variables in Octave.")
+
+(defvar octave-function-header-regexp
+ (concat "^\\s-*\\_<\\(function\\)\\_>"
+ "\\([^=;\n]*=[ \t]*\\|[ \t]*\\)\\(\\(?:\\w\\|\\s_\\)+\\)\\_>")
+ "Regexp to match an Octave function header.
+The string `function' and its name are given by the first and third
+parenthetical grouping.")
+
+\f
+(defvar octave-font-lock-keywords
+ (list
+ ;; Fontify all builtin keywords.
+ (cons (concat "\\_<\\("
+ (regexp-opt (append octave-reserved-words
+ octave-text-functions))
+ "\\)\\_>")
+ 'font-lock-keyword-face)
+ ;; Fontify all builtin operators.
+ (cons "\\(&\\||\\|<=\\|>=\\|==\\|<\\|>\\|!=\\|!\\)"
+ (if (boundp 'font-lock-builtin-face)
+ 'font-lock-builtin-face
+ 'font-lock-preprocessor-face))
+ ;; Fontify all builtin variables.
+ (cons (concat "\\_<" (regexp-opt octave-variables) "\\_>")
+ 'font-lock-variable-name-face)
+ ;; Fontify all function declarations.
+ (list octave-function-header-regexp
+ '(1 font-lock-keyword-face)
+ '(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 "\"'")))))
+
+\f
+(defvar octave-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "`" 'octave-abbrev-start)
+ (define-key map "\e\n" 'octave-indent-new-comment-line)
+ (define-key map "\M-\C-q" 'octave-indent-defun)
+ (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 [remap down-list] 'smie-down-list)
+ (define-key map "\C-c\M-\C-h" 'octave-mark-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-il" 'octave-send-line)
+ (define-key map "\C-c\C-ib" 'octave-send-block)
+ (define-key map "\C-c\C-if" 'octave-send-defun)
+ (define-key map "\C-c\C-ir" 'octave-send-region)
+ (define-key map "\C-c\C-is" 'octave-show-process-buffer)
+ (define-key map "\C-c\C-iq" 'octave-hide-process-buffer)
+ (define-key map "\C-c\C-ik" 'octave-kill-process)
+ (define-key map "\C-c\C-i\C-l" 'octave-send-line)
+ (define-key map "\C-c\C-i\C-b" 'octave-send-block)
+ (define-key map "\C-c\C-i\C-f" 'octave-send-defun)
+ (define-key map "\C-c\C-i\C-r" 'octave-send-region)
+ (define-key map "\C-c\C-i\C-s" 'octave-show-process-buffer)
+ (define-key map "\C-c\C-i\C-q" 'octave-hide-process-buffer)
+ (define-key map "\C-c\C-i\C-k" 'octave-kill-process)
+ map)
+ "Keymap used in Octave mode.")
+
+
+
+(easy-menu-define octave-mode-menu octave-mode-map
+ "Menu for Octave mode."
+ '("Octave"
+ ("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"
+ ["Mark Block" octave-mark-block t]
+ ["Close Block" smie-close-block t])
+ ("Functions"
+ ["Indent Function" octave-indent-defun t]
+ ["Insert Function" octave-insert-defun t])
+ "-"
+ ("Debug"
+ ["Send Current Line" octave-send-line t]
+ ["Send Current Block" octave-send-block t]
+ ["Send Current Function" octave-send-defun t]
+ ["Send Region" octave-send-region t]
+ ["Show Process Buffer" octave-show-process-buffer t]
+ ["Hide Process Buffer" octave-hide-process-buffer t]
+ ["Kill Process" octave-kill-process t])
+ "-"
+ ["Indent Line" indent-according-to-mode t]
+ ["Complete Symbol" completion-at-point 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" describe-mode t]
+ ["Lookup Octave Index" info-lookup-symbol t]))
+
+(defvar octave-mode-syntax-table
+ (let ((table (make-syntax-table)))
+ (modify-syntax-entry ?\r " " table)
+ (modify-syntax-entry ?+ "." table)
+ (modify-syntax-entry ?- "." table)
+ (modify-syntax-entry ?= "." table)
+ (modify-syntax-entry ?* "." table)
+ (modify-syntax-entry ?/ "." table)
+ (modify-syntax-entry ?> "." table)
+ (modify-syntax-entry ?< "." table)
+ (modify-syntax-entry ?& "." table)
+ (modify-syntax-entry ?| "." table)
+ (modify-syntax-entry ?! "." table)
+ (modify-syntax-entry ?\\ "\\" table)
+ (modify-syntax-entry ?\' "." table)
+ ;; Was "w" for abbrevs, but now that it's not necessary any more,
+ (modify-syntax-entry ?\` "." table)
+ (modify-syntax-entry ?\" "\"" 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-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-comment-start
+ (concat (make-string 2 octave-comment-char) " ")
+ "String to insert to start a new Octave comment on an empty line.")
+
+(defcustom octave-continuation-offset 4
+ "Extra indentation applied to Octave continuation lines."
+ :type 'integer
+ :group 'octave)
+(eval-and-compile
+ (defconst octave-continuation-marker-regexp "\\\\\\|\\.\\.\\."))
+(defvar octave-continuation-regexp
+ (concat "[^#%\n]*\\(" octave-continuation-marker-regexp
+ "\\)\\s-*\\(\\s<.*\\)?$"))
+(defcustom octave-continuation-string "\\"
+ "Character string used for Octave continuation lines. Normally \\."
+ :type 'string
+ :group 'octave)
+
+(defvar octave-completion-alist nil
+ "Alist of Octave symbols for completion in Octave mode.
+Each element looks like (VAR . VAR), where the car and cdr are the same
+symbol (an Octave command or variable name).
+Currently, only builtin variables can be completed.")
+
+(defvar octave-mode-imenu-generic-expression
+ (list
+ ;; Functions
+ (list nil octave-function-header-regexp 3))
+ "Imenu expression for Octave mode. See `imenu-generic-expression'.")
+
+(defcustom octave-mode-hook nil
+ "Hook to be run when Octave mode is started."
+ :type 'hook
+ :group 'octave)
+
+(defcustom octave-send-show-buffer t
+ "Non-nil means display `inferior-octave-buffer' after sending to it."
+ :type 'boolean
+ :group 'octave)
+(defcustom octave-send-line-auto-forward t
+ "Control auto-forward after sending to the inferior Octave process.
+Non-nil means always go to the next Octave code line after sending."
+ :type 'boolean
+ :group 'octave)
+(defcustom octave-send-echo-input t
+ "Non-nil means echo input sent to the inferior Octave process."
+ :type 'boolean
+ :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 "$\\|[%#]")
+ (not (smie-rule-bolp))
+ ;; 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
+(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
+Font Lock mode on terminals that support it).
+
+Octave itself is a high-level language, primarily intended for numerical
+computations. It provides a convenient command line interface for
+solving linear and nonlinear problems numerically. Function definitions
+can also be stored in files, and it can be used in a batch mode (which
+is why you need this mode!).
+
+The latest released version of Octave is always available via anonymous
+ftp from ftp.octave.org in the directory `/pub/octave'. Complete
+source and binaries for several popular systems are available.
+
+Type \\[list-abbrevs] to display the built-in abbrevs for Octave keywords.
+
+Keybindings
+===========
+
+\\{octave-mode-map}
+
+Variables you can use to customize Octave mode
+==============================================
+
+`octave-blink-matching-block'
+ Non-nil means show matching begin of block when inserting a space,
+ newline or semicolon after an else or end keyword. Default is t.
+
+`octave-block-offset'
+ Extra indentation applied to statements in block structures.
+ Default is 2.
+
+`octave-continuation-offset'
+ Extra indentation applied to Octave continuation lines.
+ Default is 4.
+
+`octave-continuation-string'
+ String used for Octave continuation lines.
+ Default is a backslash.
+
+`octave-send-echo-input'
+ Non-nil means always display `inferior-octave-buffer' after sending a
+ command to the inferior Octave process.
+
+`octave-send-line-auto-forward'
+ Non-nil means always go to the next unsent line of Octave code after
+ sending a line to the inferior Octave process.
+
+`octave-send-echo-input'
+ Non-nil means echo input sent to the inferior Octave process.
+
+Turning on Octave mode runs the hook `octave-mode-hook'.
+
+To begin using this mode for all `.m' files that you edit, add the
+following lines to your init file:
+
+ (add-to-list 'auto-mode-alist '(\"\\\\.m\\\\'\" . octave-mode))
+
+To automatically turn on the abbrev and auto-fill features,
+add the following lines to your init file as well:
+
+ (add-hook 'octave-mode-hook
+ (lambda ()
+ (abbrev-mode 1)
+ (auto-fill-mode 1)))
+
+To submit a problem report, enter \\[octave-submit-bug-report] from \
+an Octave mode buffer.
+This automatically sets up a mail buffer with version information
+already added. You just need to add a description of the problem,
+including a reproducible test case and send the message."
+ (setq local-abbrev-table octave-abbrev-table)
+
+ (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))
+
+\f
+(defcustom inferior-octave-program "octave"
+ "Program invoked by `inferior-octave'."
+ :type 'string
+ :group 'octave)
+
+(defcustom inferior-octave-buffer "*Inferior Octave*"
+ "Name of buffer for running an inferior Octave process."
+ :type 'string
+ :group 'octave)
+
+(defcustom inferior-octave-prompt
+ "\\(^octave\\(\\|.bin\\|.exe\\)\\(-[.0-9]+\\)?\\(:[0-9]+\\)?\\|^debug\\|^\\)>+ "
+ "Regexp to match prompts for the inferior Octave process."
+ :type 'regexp
+ :group 'octave)
+
+(defcustom inferior-octave-startup-file nil
+ "Name of the inferior Octave startup file.
+The contents of this file are sent to the inferior Octave process on
+startup."
+ :type '(choice (const :tag "None" nil)
+ file)
+ :group 'octave)
+
+(defcustom inferior-octave-startup-args nil
+ "List of command line arguments for the inferior Octave process.
+For example, for suppressing the startup message and using `traditional'
+mode, set this to (\"-q\" \"--traditional\")."
+ :type '(repeat string)
+ :group 'octave)
+
+(defcustom inferior-octave-mode-hook nil
+ "Hook to be run when Inferior Octave mode is started."
+ :type 'hook
+ :group 'octave)
+
+(defvar inferior-octave-process nil)
+
+(defvar inferior-octave-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map comint-mode-map)
+ (define-key map "\t" 'comint-dynamic-complete)
+ (define-key map "\M-?" 'comint-dynamic-list-filename-completions)
+ (define-key map "\C-c\C-l" 'inferior-octave-dynamic-list-input-ring)
+ (define-key map [menu-bar inout list-history]
+ '("List Input History" . inferior-octave-dynamic-list-input-ring))
+ map)
+ "Keymap used in Inferior Octave mode.")
+
+(defvar inferior-octave-mode-syntax-table
+ (let ((table (make-syntax-table octave-mode-syntax-table)))
+ table)
+ "Syntax table in use in inferior-octave-mode buffers.")
+
+(defvar inferior-octave-font-lock-keywords
+ (list
+ (cons inferior-octave-prompt 'font-lock-type-face))
+ ;; Could certainly do more font locking in inferior Octave ...
+ "Additional expressions to highlight in Inferior Octave mode.")
+
+
+;;; Compatibility functions
+(if (not (fboundp 'comint-line-beginning-position))
+ ;; comint-line-beginning-position is defined in Emacs 21
+ (defun comint-line-beginning-position ()
+ "Returns the buffer position of the beginning of the line, after any prompt.
+The prompt is assumed to be any text at the beginning of the line matching
+the regular expression `comint-prompt-regexp', a buffer local variable."
+ (save-excursion (comint-bol nil) (point))))
+
+
+(defvar inferior-octave-output-list nil)
+(defvar inferior-octave-output-string nil)
+(defvar inferior-octave-receive-in-progress nil)
+
+(defvar inferior-octave-startup-hook nil)
+
+(defvar inferior-octave-complete-impossible nil
+ "Non-nil means that `inferior-octave-complete' is impossible.")
+
+(defvar inferior-octave-has-built-in-variables nil
+ "Non-nil means that Octave has built-in variables.")
+
+(defvar inferior-octave-dynamic-complete-functions
+ '(inferior-octave-completion-at-point comint-filename-completion)
+ "List of functions called to perform completion for inferior Octave.
+This variable is used to initialize `comint-dynamic-complete-functions'
+in the Inferior Octave buffer.")
+
+(defvar info-lookup-mode)
+
+(define-derived-mode inferior-octave-mode comint-mode "Inferior Octave"
+ "Major mode for interacting with an inferior Octave process.
+Runs Octave as a subprocess of Emacs, with Octave I/O through an Emacs
+buffer.
+
+Entry to this mode successively runs the hooks `comint-mode-hook' and
+`inferior-octave-mode-hook'."
+ (setq comint-prompt-regexp inferior-octave-prompt
+ mode-line-process '(":%s")
+ local-abbrev-table octave-abbrev-table)
+
+ (set (make-local-variable 'comment-start) octave-comment-start)
+ (set (make-local-variable 'comment-end) "")
+ (set (make-local-variable 'comment-column) 32)
+ (set (make-local-variable 'comment-start-skip) octave-comment-start-skip)
+
+ (set (make-local-variable 'font-lock-defaults)
+ '(inferior-octave-font-lock-keywords nil nil))
+
+ (set (make-local-variable 'info-lookup-mode) 'octave-mode)
+
+ (setq comint-input-ring-file-name
+ (or (getenv "OCTAVE_HISTFILE") "~/.octave_hist")
+ comint-input-ring-size (or (getenv "OCTAVE_HISTSIZE") 1024))
+ (set (make-local-variable 'comint-dynamic-complete-functions)
+ inferior-octave-dynamic-complete-functions)
+ (add-hook 'comint-input-filter-functions
+ 'inferior-octave-directory-tracker nil t)
+ (comint-read-input-ring t))
+
+;;;###autoload
+(defun inferior-octave (&optional arg)
+ "Run an inferior Octave process, I/O via `inferior-octave-buffer'.
+This buffer is put in Inferior Octave mode. See `inferior-octave-mode'.
+
+Unless ARG is non-nil, switches to this buffer.
+
+The elements of the list `inferior-octave-startup-args' are sent as
+command line arguments to the inferior Octave process on startup.
+
+Additional commands to be executed on startup can be provided either in
+the file specified by `inferior-octave-startup-file' or by the default
+startup file, `~/.emacs-octave'."
+ (interactive "P")
+ (let ((buffer inferior-octave-buffer))
+ (get-buffer-create buffer)
+ (if (comint-check-proc buffer)
+ ()
+ (with-current-buffer buffer
+ (comint-mode)
+ (inferior-octave-startup)
+ (inferior-octave-mode)))
+ (if (not arg)
+ (pop-to-buffer buffer))))
+
+;;;###autoload
+(defalias 'run-octave 'inferior-octave)
+
+(defun inferior-octave-startup ()
+ "Start an inferior Octave process."
+ (let ((proc (comint-exec-1
+ (substring inferior-octave-buffer 1 -1)
+ inferior-octave-buffer
+ inferior-octave-program
+ (append (list "-i" "--no-line-editing")
+ inferior-octave-startup-args))))
+ (set-process-filter proc 'inferior-octave-output-digest)
+ (setq comint-ptyp process-connection-type
+ inferior-octave-process proc
+ inferior-octave-output-list nil
+ inferior-octave-output-string nil
+ inferior-octave-receive-in-progress t)
+
+ ;; This may look complicated ... However, we need to make sure that
+ ;; we additional startup code only AFTER Octave is ready (otherwise,
+ ;; output may be mixed up). Hence, we need to digest the Octave
+ ;; output to see when it issues a prompt.
+ (while inferior-octave-receive-in-progress
+ (accept-process-output inferior-octave-process))
+ (goto-char (point-max))
+ (set-marker (process-mark proc) (point))
+ (insert-before-markers
+ (concat
+ (if (not (bobp)) "\f\n")
+ (if inferior-octave-output-list
+ (concat (mapconcat
+ 'identity inferior-octave-output-list "\n")
+ "\n"))))
+
+ ;; Find out whether Octave has built-in variables.
+ (inferior-octave-send-list-and-digest
+ (list "exist \"LOADPATH\"\n"))
+ (setq inferior-octave-has-built-in-variables
+ (string-match "101$" (car inferior-octave-output-list)))
+
+ ;; An empty secondary prompt, as e.g. obtained by '--braindead',
+ ;; means trouble.
+ (inferior-octave-send-list-and-digest (list "PS2\n"))
+ (if (string-match "\\(PS2\\|ans\\) = *$" (car inferior-octave-output-list))
+ (inferior-octave-send-list-and-digest
+ (list (if inferior-octave-has-built-in-variables
+ "PS2 = \"> \"\n"
+ "PS2 (\"> \");\n"))))
+
+ ;; O.k., now we are ready for the Inferior Octave startup commands.
+ (let* (commands
+ (program (file-name-nondirectory inferior-octave-program))
+ (file (or inferior-octave-startup-file
+ (concat "~/.emacs-" program))))
+ (setq commands
+ (list "more off;\n"
+ (if (not (string-equal
+ inferior-octave-output-string ">> "))
+ (if inferior-octave-has-built-in-variables
+ "PS1=\"\\\\s> \";\n"
+ "PS1 (\"\\\\s> \");\n"))
+ (if (file-exists-p file)
+ (format "source (\"%s\");\n" file))))
+ (inferior-octave-send-list-and-digest commands))
+ (insert-before-markers
+ (concat
+ (if inferior-octave-output-list
+ (concat (mapconcat
+ 'identity inferior-octave-output-list "\n")
+ "\n"))
+ inferior-octave-output-string))
+ ;; Next, we check whether Octave supports `completion_matches' ...
+ (inferior-octave-send-list-and-digest
+ (list "exist \"completion_matches\"\n"))
+ (setq inferior-octave-complete-impossible
+ (not (string-match "5$" (car inferior-octave-output-list))))
+
+ ;; And finally, everything is back to normal.
+ (set-process-filter proc 'inferior-octave-output-filter)
+ (run-hooks 'inferior-octave-startup-hook)
+ (run-hooks 'inferior-octave-startup-hook)
+ ;; Just in case, to be sure a cd in the startup file
+ ;; won't have detrimental effects.
+ (inferior-octave-resync-dirs)))
+
+(defun inferior-octave-completion-at-point ()
+ "Return the data to complete the Octave symbol at point."
+ (let* ((end (point))
+ (start
+ (save-excursion
+ (skip-syntax-backward "w_" (comint-line-beginning-position))
+ (point))))
+ (cond ((eq start end) nil)
+ (inferior-octave-complete-impossible
+ (message (concat
+ "Your Octave does not have `completion_matches'. "
+ "Please upgrade to version 2.X."))
+ nil)
+ (t
+ (list
+ start end
+ (completion-table-dynamic
+ (lambda (command)
+ (inferior-octave-send-list-and-digest
+ (list (concat "completion_matches (\"" command "\");\n")))
+ (sort (delete-dups inferior-octave-output-list)
+ 'string-lessp))))))))
+
+(define-obsolete-function-alias 'inferior-octave-complete
+ 'completion-at-point "24.1")
+
+(defun inferior-octave-dynamic-list-input-ring ()
+ "List the buffer's input history in a help buffer."
+ ;; We cannot use `comint-dynamic-list-input-ring', because it replaces
+ ;; "completion" by "history reference" ...
+ (interactive)
+ (if (or (not (ring-p comint-input-ring))
+ (ring-empty-p comint-input-ring))
+ (message "No history")
+ (let ((history nil)
+ (history-buffer " *Input History*")
+ (index (1- (ring-length comint-input-ring)))
+ (conf (current-window-configuration)))
+ ;; We have to build up a list ourselves from the ring vector.
+ (while (>= index 0)
+ (setq history (cons (ring-ref comint-input-ring index) history)
+ index (1- index)))
+ ;; Change "completion" to "history reference"
+ ;; to make the display accurate.
+ (with-output-to-temp-buffer history-buffer
+ (display-completion-list history)
+ (set-buffer history-buffer))
+ (message "Hit space to flush")
+ (let ((ch (read-event)))
+ (if (eq ch ?\ )
+ (set-window-configuration conf)
+ (setq unread-command-events (list ch)))))))
+
+(defun inferior-octave-strip-ctrl-g (string)
+ "Strip leading `^G' character.
+If STRING starts with a `^G', ring the bell and strip it."
+ (if (string-match "^\a" string)
+ (progn
+ (ding)
+ (setq string (substring string 1))))
+ string)
+
+(defun inferior-octave-output-filter (proc string)
+ "Standard output filter for the inferior Octave process.
+Ring Emacs bell if process output starts with an ASCII bell, and pass
+the rest to `comint-output-filter'."
+ (comint-output-filter proc (inferior-octave-strip-ctrl-g string)))
+
+(defun inferior-octave-output-digest (_proc string)
+ "Special output filter for the inferior Octave process.
+Save all output between newlines into `inferior-octave-output-list', and
+the rest to `inferior-octave-output-string'."
+ (setq string (concat inferior-octave-output-string string))
+ (while (string-match "\n" string)
+ (setq inferior-octave-output-list
+ (append inferior-octave-output-list
+ (list (substring string 0 (match-beginning 0))))
+ string (substring string (match-end 0))))
+ (if (string-match inferior-octave-prompt string)
+ (setq inferior-octave-receive-in-progress nil))
+ (setq inferior-octave-output-string string))
+
+(defun inferior-octave-send-list-and-digest (list)
+ "Send LIST to the inferior Octave process and digest the output.
+The elements of LIST have to be strings and are sent one by one. All
+output is passed to the filter `inferior-octave-output-digest'."
+ (let* ((proc inferior-octave-process)
+ (filter (process-filter proc))
+ string)
+ (set-process-filter proc 'inferior-octave-output-digest)
+ (setq inferior-octave-output-list nil)
+ (unwind-protect
+ (while (setq string (car list))
+ (setq inferior-octave-output-string nil
+ inferior-octave-receive-in-progress t)
+ (comint-send-string proc string)
+ (while inferior-octave-receive-in-progress
+ (accept-process-output proc))
+ (setq list (cdr list)))
+ (set-process-filter proc filter))))
+
+(defun inferior-octave-directory-tracker (string)
+ "Tracks `cd' commands issued to the inferior Octave process.
+Use \\[inferior-octave-resync-dirs] to resync if Emacs gets confused."
+ (cond
+ ((string-match "^[ \t]*cd[ \t;]*$" string)
+ (cd "~"))
+ ((string-match "^[ \t]*cd[ \t]+\\([^ \t\n;]*\\)[ \t\n;]*" string)
+ (cd (substring string (match-beginning 1) (match-end 1))))))
+
+(defun inferior-octave-resync-dirs ()
+ "Resync the buffer's idea of the current directory.
+This command queries the inferior Octave process about its current
+directory and makes this the current buffer's default directory."
+ (interactive)
+ (inferior-octave-send-list-and-digest '("disp (pwd ())\n"))
+ (cd (car inferior-octave-output-list)))
+
+\f
+;;; Miscellaneous useful functions
+
+(defsubst octave-in-comment-p ()
+ "Return t if point is inside an Octave comment."
+ (nth 4 (syntax-ppss)))
+
+(defsubst octave-in-string-p ()
+ "Return t if point is inside an Octave string."
+ (nth 3 (syntax-ppss)))
+
+(defsubst octave-not-in-string-or-comment-p ()
+ "Return t if point is not inside an Octave string or comment."
+ (let ((pps (syntax-ppss)))
+ (not (or (nth 3 pps) (nth 4 pps)))))
+
+
+(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-maybe-insert-continuation-string ()
+ (if (or (octave-in-comment-p)
+ (save-excursion
+ (beginning-of-line)
+ (looking-at octave-continuation-regexp)))
+ nil
+ (delete-horizontal-space)
+ (insert (concat " " octave-continuation-string))))
+\f
+;;; Indentation
+
+(defun octave-indent-new-comment-line ()
+ "Break Octave line at point, continuing comment if within one.
+If within code, insert `octave-continuation-string' before breaking the
+line. If within a string, signal an error.
+The new line is properly indented."
+ (interactive)
+ (delete-horizontal-space)
+ (cond
+ ((octave-in-comment-p)
+ (indent-new-comment-line))
+ ((octave-in-string-p)
+ (error "Cannot split a code line inside a string"))
+ (t
+ (insert (concat " " octave-continuation-string))
+ (reindent-then-newline-and-indent))))
+
+(defun octave-indent-defun ()
+ "Properly indent the Octave function which contains point."
+ (interactive)
+ (save-excursion
+ (mark-defun)
+ (message "Indenting function...")
+ (indent-region (point) (mark) nil))
+ (message "Indenting function...done."))
+
+\f
+;;; Motion
+(defun octave-next-code-line (&optional arg)
+ "Move ARG lines of Octave code forward (backward if ARG is negative).
+Skips past all empty and comment lines. Default for ARG is 1.
+
+On success, return 0. Otherwise, go as far as possible and return -1."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (beginning-of-line)
+ (let ((n 0)
+ (inc (if (> arg 0) 1 -1)))
+ (while (and (/= arg 0) (= n 0))
+ (setq n (forward-line inc))
+ (while (and (= n 0)
+ (looking-at "\\s-*\\($\\|\\s<\\)"))
+ (setq n (forward-line inc)))
+ (setq arg (- arg inc)))
+ n))
+
+(defun octave-previous-code-line (&optional arg)
+ "Move ARG lines of Octave code backward (forward if ARG is negative).
+Skips past all empty and comment lines. Default for ARG is 1.
+
+On success, return 0. Otherwise, go as far as possible and return -1."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (octave-next-code-line (- arg)))
+
+(defun octave-beginning-of-line ()
+ "Move point to beginning of current Octave line.
+If on an empty or comment line, go to the beginning of that line.
+Otherwise, move backward to the beginning of the first Octave code line
+which is not inside a continuation statement, i.e., which does not
+follow a code line ending in `...' or `\\', or is inside an open
+parenthesis list."
+ (interactive)
+ (beginning-of-line)
+ (if (not (looking-at "\\s-*\\($\\|\\s<\\)"))
+ (while (or (condition-case nil
+ (progn
+ (up-list -1)
+ (beginning-of-line)
+ t)
+ (error nil))
+ (and (or (looking-at "\\s-*\\($\\|\\s<\\)")
+ (save-excursion
+ (if (zerop (octave-previous-code-line))
+ (looking-at octave-continuation-regexp))))
+ (zerop (forward-line -1)))))))
+
+(defun octave-end-of-line ()
+ "Move point to end of current Octave line.
+If on an empty or comment line, go to the end of that line.
+Otherwise, move forward to the end of the first Octave code line which
+does not end in `...' or `\\' or is inside an open parenthesis list."
+ (interactive)
+ (end-of-line)
+ (if (save-excursion
+ (beginning-of-line)
+ (looking-at "\\s-*\\($\\|\\s<\\)"))
+ ()
+ (while (or (condition-case nil
+ (progn
+ (up-list 1)
+ (end-of-line)
+ t)
+ (error nil))
+ (and (save-excursion
+ (beginning-of-line)
+ (or (looking-at "\\s-*\\($\\|\\s<\\)")
+ (looking-at octave-continuation-regexp)))
+ (zerop (forward-line 1)))))
+ (end-of-line)))
+
+(defun octave-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)
+ (if (and (looking-at "\\sw\\|\\s_")
+ (looking-back "\\sw\\|\\s_" (1- (point))))
+ (skip-syntax-forward "w_"))
+ (unless (or (looking-at "\\s(")
+ (save-excursion
+ (let* ((token (funcall smie-forward-token-function))
+ (level (assoc token smie-grammar)))
+ (and level (not (numberp (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."
+ (let* ((arg (or arg 1))
+ (inc (if (> arg 0) 1 -1))
+ (found nil)
+ (case-fold-search nil))
+ (and (not (eobp))
+ (not (and (> arg 0) (looking-at "\\_<function\\_>")))
+ (skip-syntax-forward "w"))
+ (while (and (/= arg 0)
+ (setq found
+ (re-search-backward "\\_<function\\_>" inc)))
+ (if (octave-not-in-string-or-comment-p)
+ (setq arg (- arg inc))))
+ (if found
+ (progn
+ (and (< inc 0) (goto-char (match-beginning 0)))
+ t))))
+
+\f
+;;; Filling
+(defun octave-auto-fill ()
+ "Perform auto-fill in Octave mode.
+Returns nil if no feasible place to break the line could be found, and t
+otherwise."
+ (let (fc give-up)
+ (if (or (null (setq fc (current-fill-column)))
+ (save-excursion
+ (beginning-of-line)
+ (and auto-fill-inhibit-regexp
+ (octave-looking-at-kw auto-fill-inhibit-regexp))))
+ nil ; Can't do anything
+ (if (and (not (octave-in-comment-p))
+ (> (current-column) fc))
+ (setq fc (- fc (+ (length octave-continuation-string) 1))))
+ (while (and (not give-up) (> (current-column) fc))
+ (let* ((opoint (point))
+ (fpoint
+ (save-excursion
+ (move-to-column (+ fc 1))
+ (skip-chars-backward "^ \t\n")
+ ;; If we're at the beginning of the line, break after
+ ;; the first word
+ (if (bolp)
+ (re-search-forward "[ \t]" opoint t))
+ ;; If we're in a comment line, don't break after the
+ ;; comment chars
+ (if (save-excursion
+ (skip-syntax-backward " <")
+ (bolp))
+ (re-search-forward "[ \t]" (line-end-position)
+ 'move))
+ ;; If we're not in a comment line and just ahead the
+ ;; continuation string, don't break here.
+ (if (and (not (octave-in-comment-p))
+ (looking-at
+ (concat "\\s-*"
+ (regexp-quote
+ octave-continuation-string)
+ "\\s-*$")))
+ (end-of-line))
+ (skip-chars-backward " \t")
+ (point))))
+ (if (save-excursion
+ (goto-char fpoint)
+ (not (or (bolp) (eolp))))
+ (let ((prev-column (current-column)))
+ (if (save-excursion
+ (skip-chars-backward " \t")
+ (= (point) fpoint))
+ (progn
+ (octave-maybe-insert-continuation-string)
+ (indent-new-comment-line t))
+ (save-excursion
+ (goto-char fpoint)
+ (octave-maybe-insert-continuation-string)
+ (indent-new-comment-line t)))
+ (if (>= (current-column) prev-column)
+ (setq give-up t)))
+ (setq give-up t))))
+ (not give-up))))
+
+(defun octave-fill-paragraph (&optional _arg)
+ "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
+(defun octave-initialize-completions ()
+ "Create an alist for Octave completions."
+ (if octave-completion-alist
+ ()
+ (setq octave-completion-alist
+ (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 (skip-syntax-backward "w_") (point)))
+ (end (point)))
+ (if (< beg (point))
+ ;; Extend region past point, if applicable.
+ (save-excursion (skip-syntax-forward "w_")
+ (setq end (point))))
+ (list beg end octave-completion-alist)))
+
+(define-obsolete-function-alias 'octave-complete-symbol
+ 'completion-at-point "24.1")
+\f
+;;; Electric characters && friends
+
+(defun octave-abbrev-start ()
+ "Start entering an Octave abbreviation.
+If Abbrev mode is turned on, typing ` (grave accent) followed by ? or
+\\[help-command] lists all Octave abbrevs. Any other key combination is
+executed normally.
+Note that all Octave mode abbrevs start with a grave accent."
+ (interactive)
+ (self-insert-command 1)
+ (when abbrev-mode
+ (set-temporary-overlay-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [??] 'list-abbrevs)
+ (define-key map (vector help-char) 'list-abbrevs)
+ map))))
+
+(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)."
+ (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 ()
+ "Kill inferior Octave process and its buffer."
+ (interactive)
+ (if inferior-octave-process
+ (progn
+ (process-send-string inferior-octave-process "quit;\n")
+ (accept-process-output inferior-octave-process)))
+ (if inferior-octave-buffer
+ (kill-buffer inferior-octave-buffer)))
+
+(defun octave-show-process-buffer ()
+ "Make sure that `inferior-octave-buffer' is displayed."
+ (interactive)
+ (if (get-buffer inferior-octave-buffer)
+ (display-buffer inferior-octave-buffer)
+ (message "No buffer named %s" inferior-octave-buffer)))
+
+(defun octave-hide-process-buffer ()
+ "Delete all windows that display `inferior-octave-buffer'."
+ (interactive)
+ (if (get-buffer inferior-octave-buffer)
+ (delete-windows-on inferior-octave-buffer)
+ (message "No buffer named %s" inferior-octave-buffer)))
+
+(defun octave-send-region (beg end)
+ "Send current region to the inferior Octave process."
+ (interactive "r")
+ (inferior-octave t)
+ (let ((proc inferior-octave-process)
+ (string (buffer-substring-no-properties beg end))
+ line)
+ (with-current-buffer inferior-octave-buffer
+ (setq inferior-octave-output-list nil)
+ (while (not (string-equal string ""))
+ (if (string-match "\n" string)
+ (setq line (substring string 0 (match-beginning 0))
+ string (substring string (match-end 0)))
+ (setq line string string ""))
+ (setq inferior-octave-receive-in-progress t)
+ (inferior-octave-send-list-and-digest (list (concat line "\n")))
+ (while inferior-octave-receive-in-progress
+ (accept-process-output proc))
+ (insert-before-markers
+ (mapconcat 'identity
+ (append
+ (if octave-send-echo-input (list line) (list ""))
+ (mapcar 'inferior-octave-strip-ctrl-g
+ inferior-octave-output-list)
+ (list inferior-octave-output-string))
+ "\n")))))
+ (if octave-send-show-buffer
+ (display-buffer inferior-octave-buffer)))
+
+(defun octave-send-block ()
+ "Send current Octave block to the inferior Octave process."
+ (interactive)
+ (save-excursion
+ (octave-mark-block)
+ (octave-send-region (point) (mark))))
+
+(defun octave-send-defun ()
+ "Send current Octave function to the inferior Octave process."
+ (interactive)
+ (save-excursion
+ (mark-defun)
+ (octave-send-region (point) (mark))))
+
+(defun octave-send-line (&optional arg)
+ "Send current Octave code line to the inferior Octave process.
+With positive prefix ARG, send that many lines.
+If `octave-send-line-auto-forward' is non-nil, go to the next unsent
+code line."
+ (interactive "P")
+ (or arg (setq arg 1))
+ (if (> arg 0)
+ (let (beg end)
+ (beginning-of-line)
+ (setq beg (point))
+ (octave-next-code-line (- arg 1))
+ (end-of-line)
+ (setq end (point))
+ (if octave-send-line-auto-forward
+ (octave-next-code-line 1))
+ (octave-send-region beg end))))
+
+(defun octave-eval-print-last-sexp ()
+ "Evaluate Octave sexp before point and print value into current buffer."
+ (interactive)
+ (inferior-octave t)
+ (let ((standard-output (current-buffer))
+ (print-escape-newlines nil)
+ (opoint (point)))
+ (terpri)
+ (prin1
+ (save-excursion
+ (forward-sexp -1)
+ (inferior-octave-send-list-and-digest
+ (list (concat (buffer-substring-no-properties (point) opoint)
+ "\n")))
+ (mapconcat 'identity inferior-octave-output-list "\n")))
+ (terpri)))
+\f
+;;; Bug reporting
+(defun octave-submit-bug-report ()
+ "Submit a bug report on the Emacs Octave package via mail."
+ (interactive)
+ (require 'reporter)
+ (and
+ (y-or-n-p "Do you want to submit a bug report? ")
+ (reporter-submit-bug-report
+ octave-maintainer-address
+ (concat "Emacs version " emacs-version)
+ (list
+ 'octave-blink-matching-block
+ 'octave-block-offset
+ 'octave-comment-char
+ 'octave-continuation-offset
+ 'octave-continuation-string
+ 'octave-send-echo-input
+ 'octave-send-line-auto-forward
+ 'octave-send-show-buffer))))
+
+(provide 'octave)
+;;; octave.el ends here