Mercurial > hg > octave-lojdl
changeset 2617:a27986cc4177
[project @ 1997-01-22 17:07:23 by jwe]
author | jwe |
---|---|
date | Wed, 22 Jan 1997 17:07:23 +0000 |
parents | 4cd6d8d8ac29 |
children | aa667ac18d12 |
files | emacs/octave-hlp.el emacs/octave-inf.el emacs/octave-mod.el emacs/octave.el |
diffstat | 4 files changed, 1878 insertions(+), 1786 deletions(-) [+] |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/emacs/octave-hlp.el @@ -0,0 +1,133 @@ +;; octave-hlp.el --- getting help on Octave symbols using info + +;;; Copyright (C) 1997 Free Software Foundation, Inc. + +;; Author: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at> +;; Author: John Eaton <jwe@bevo.che.wisc.edu> +;; Maintainer: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at> +;; Keywords: languages + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Provides the command `octave-help' which allows index lookup of a +;; symbol in the Octave-related info files, as specified by the list +;; `octave-help-files'. + +;; Other features may be added in future versions. + +;;; Code: + +(require 'octave-mod) +(require 'info) + +(defvar octave-help-files '("octave") + "List of info files with documentation for Octave. +Default is (\"octave\").") + +(defvar octave-help-lookup-alist nil + "Alist of Octave index entries for lookup.") + +(defvar octave-help-completion-alist nil + "Alist of Octave index entries for completion. +The entries are of the form (VAR . VAR), where VAR runs through all +different keys in `octave-help-lookup-alist'.") + +;;;###autoload +(defun octave-help (key) + "Get help on Octave symbols from the Octave info files. +Look up KEY in the function, operator and variable indices of the files +specified by `octave-help-files'. +If KEY is not a string, prompt for it with completion." + (interactive + (list + (completing-read (format "Describe Octave symbol: ") + (octave-help-get-completion-alist) + nil t))) + (if (get-buffer "*info*") + (set-buffer "*info*")) + (if (zerop (length key)) + (Info-find-node (car octave-help-files) "Top") + (let ((alist (copy-alist (octave-help-get-lookup-alist))) + entry matches) + (while (setq entry (car alist)) + (if (string-match key (car entry)) + (add-to-list 'matches entry)) + (setq alist (cdr alist))) + (if matches + (progn + (setq Info-index-alternatives matches) + (Info-index-next 0)))))) + +(defun octave-help-get-lookup-alist () + "Build the index lookup alist from all Octave info files. +The files specified by `octave-help-files' are searched." + (if octave-help-lookup-alist + () + (message "Building help lookup alist...") + (let ((files octave-help-files) file key node) + (save-window-excursion + (while files + (setq file (car files)) + (Info-goto-node (concat "(" file ")")) + (condition-case nil + (progn + (Info-index "") + (while + (progn + (while (re-search-forward + "^\\* \\([^(:]+\\)[^:]*: *\\(.+\\)\\.$" + nil t) + (setq key (match-string 1) + node (concat "(" file ")" (match-string 2))) + (and (string-match "\\(.*\\>\\) *$" key) + (setq key (replace-match "\\1" t nil key))) + (add-to-list 'octave-help-lookup-alist + (list key + node + (concat (concat "(" file ")") + Info-current-node) + 0))) + (and (setq node (Info-extract-pointer "next" t)) + (string-match + (concat "\\(Function\\|Operator\\|Variable\\) " + "\\<Index\\>") + node))) + (Info-goto-node node))) + (error nil)) + (setq files (cdr files))))) + (message "Building help lookup alist...done")) + octave-help-lookup-alist) + +(defun octave-help-get-completion-alist () + "Build the index completion alist from all Octave info files. +The files specified by `octave-help-files' are searched." + (if octave-help-completion-alist + () + (message "Building help completion alist...") + (let ((alist (octave-help-get-lookup-alist)) entry) + (while alist + (setq entry (car alist)) + (add-to-list 'octave-help-completion-alist + (cons (car entry) (car entry))) + (setq alist (cdr alist)))) + (message "Building help completion alist...done")) + octave-help-completion-alist) + +;;; octave-hlp.el ends here
new file mode 100644 --- /dev/null +++ b/emacs/octave-inf.el @@ -0,0 +1,350 @@ +;; octave-inf.el --- running Octave as an inferior Emacs process + +;;; Copyright (C) 1997 Free Software Foundation, Inc. + +;; Author: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at> +;; Author: John Eaton <jwe@bevo.che.wisc.edu> +;; Maintainer: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at> +;; Keywords: languages + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Code: + +(require 'octave-mod) +(require 'comint) + +(defvar inferior-octave-program "octave" + "*Program invoked by `inferior-octave'.") + +(defvar inferior-octave-prompt "\\(^octave\\(:[0-9]+\\)?\\|^\\)>+ " + "*Regexp to match prompts for the inferior Octave process.") + +(defvar 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.") + +(defvar 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\").") + +(defvar inferior-octave-mode-map nil + "Keymap used in Inferior Octave mode.") +(if inferior-octave-mode-map + () + (let ((map (copy-keymap 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)) + (define-key map "\C-c\C-h" 'octave-help) + (setq inferior-octave-mode-map map))) + +(defvar inferior-octave-mode-syntax-table nil + "Syntax table in use in inferior-octave-mode buffers.") +(if inferior-octave-mode-syntax-table + () + (let ((table (make-syntax-table))) + (modify-syntax-entry ?\` "w" table) + (modify-syntax-entry ?\# "<" table) + (modify-syntax-entry ?\n ">" table) + (setq inferior-octave-mode-syntax-table table))) + +(defvar inferior-octave-mode-hook nil + "*Hook to be run when Inferior Octave mode is started.") + +(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.") + +(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-dynamic-complete-functions + '(inferior-octave-complete comint-dynamic-complete-filename) + "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.") + +(defun inferior-octave-mode () + "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'." + (interactive) + (comint-mode) + (setq comint-prompt-regexp inferior-octave-prompt + major-mode 'inferior-octave-mode + mode-name "Inferior Octave" + mode-line-process '(":%s") + local-abbrev-table octave-abbrev-table) + (use-local-map inferior-octave-mode-map) + (set-syntax-table inferior-octave-mode-syntax-table) + + (make-local-variable 'comment-start) + (setq comment-start octave-comment-start) + (make-local-variable 'comment-end) + (setq comment-end "") + (make-local-variable 'comment-column) + (setq comment-column 32) + (make-local-variable 'comment-start-skip) + (setq comment-start-skip octave-comment-start-skip) + + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(inferior-octave-font-lock-keywords nil nil)) + + (setq comint-input-ring-file-name + (or (getenv "OCTAVE_HISTFILE") "~/.octave_hist") + comint-input-ring-size (or (getenv "OCTAVE_HISTSIZE") 1024) + comint-input-filter-functions '(inferior-octave-directory-tracker) + comint-dynamic-complete-functions + inferior-octave-dynamic-complete-functions) + (comint-read-input-ring t) + + (run-hooks 'inferior-octave-mode-hook)) + +;;;###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) + () + (save-excursion + (set-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 + 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)) "\n") + (if inferior-octave-output-list + (concat (mapconcat + 'identity inferior-octave-output-list "\n") + "\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 "page_screen_output = 0;\n" + (if (not (string-equal + inferior-octave-output-string ">> ")) + "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))) + + +(defun inferior-octave-complete () + "Perform completion on the Octave symbol preceding point. +This is implemented using the Octave command `completion_matches' which +is NOT available with versions of Octave prior to 2.0." + (interactive) + (let* ((end (point)) + (command (save-excursion + (skip-syntax-backward "w_") + (and (looking-at comint-prompt-regexp) + (goto-char (match-end 0))) + (buffer-substring-no-properties (point) end))) + (proc (get-buffer-process inferior-octave-buffer)) + (filter (process-filter proc))) + (cond (inferior-octave-complete-impossible + (error (concat + "Your Octave does not have `completion_matches'. " + "Please upgrade to version 2.X."))) + ((string-equal command "") + (message "Cannot complete an empty string")) + (t + (inferior-octave-send-list-and-digest + (list (concat "completion_matches (\"" command "\");\n"))) + ;; Sort the list + (setq inferior-octave-output-list + (sort inferior-octave-output-list 'string-lessp)) + ;; Remove duplicates + (let* ((x inferior-octave-output-list) + (y (cdr x))) + (while y + (if (string-equal (car x) (car y)) + (setcdr x (setq y (cdr y))) + (setq x y + y (cdr y))))) + ;; And let comint handle the rest + (comint-dynamic-simple-complete + command inferior-octave-output-list))))) + +(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." + (if (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 '("pwd\n")) + (cd (car inferior-octave-output-list))) + +;;; octave-inf.el ends here
new file mode 100644 --- /dev/null +++ b/emacs/octave-mod.el @@ -0,0 +1,1395 @@ +;; octave-mod.el --- editing Octave source files under Emacs + +;;; Copyright (C) 1997 Free Software Foundation, Inc. + +;; Author: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at> +;; Author: John Eaton <jwe@bevo.che.wisc.edu> +;; Maintainer: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at> +;; Keywords: languages + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This package provides Emacs support for Octave. +;; It defines Octave mode, a major mode for editing +;; Octave code. + +;; The file octave-hlp.el provides `octave-help', a facility for looking up +;; documentation on a symbol in the Octave info files. + +;; The file octave-inf.el contains code for interacting with an inferior +;; Octave process using comint. + +;; See the documentation of `octave-mode', `octave-help' and +;; `run-octave' for further information on usage and customization. + +;;; Code: + +(defconst octave-maintainer-address + "Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at>, bug-gnu-emacs@prep.ai.mit.edu" + "Current maintainer of the Emacs Octave package.") + +(defvar octave-abbrev-table nil + "Abbrev table for Octave's reserved words. +Used in octave-mode and inferior-octave-mode buffers. +All Octave abbrevs start with a grave accent (`).") +(if octave-abbrev-table + () + (let ((ac abbrevs-changed)) + (define-abbrev-table 'octave-abbrev-table ()) + (define-abbrev octave-abbrev-table "`a" "all_va_args" nil) + (define-abbrev octave-abbrev-table "`b" "break" nil) + (define-abbrev octave-abbrev-table "`ca" "catch" nil) + (define-abbrev octave-abbrev-table "`c" "continue" nil) + (define-abbrev octave-abbrev-table "`el" "else" nil) + (define-abbrev octave-abbrev-table "`eli" "elseif" nil) + (define-abbrev octave-abbrev-table "`et" "end_try_catch" nil) + (define-abbrev octave-abbrev-table "`eu" "end_unwind_protect" nil) + (define-abbrev octave-abbrev-table "`ef" "endfor" nil) + (define-abbrev octave-abbrev-table "`efu" "endfunction" nil) + (define-abbrev octave-abbrev-table "`ei" "endif" nil) + (define-abbrev octave-abbrev-table "`ew" "endwhile" nil) + (define-abbrev octave-abbrev-table "`f" "for" nil) + (define-abbrev octave-abbrev-table "`fu" "function" nil) + (define-abbrev octave-abbrev-table "`gl" "global" nil) + (define-abbrev octave-abbrev-table "`gp" "gplot" nil) + (define-abbrev octave-abbrev-table "`gs" "gsplot" nil) + (define-abbrev octave-abbrev-table "`if" "if ()" nil) + (define-abbrev octave-abbrev-table "`rp" "replot" nil) + (define-abbrev octave-abbrev-table "`r" "return" nil) + (define-abbrev octave-abbrev-table "`t" "try" nil) + (define-abbrev octave-abbrev-table "`up" "unwind_protect" nil) + (define-abbrev octave-abbrev-table "`upc" "unwind_protect_cleanup" nil) + (define-abbrev octave-abbrev-table "`w" "while ()" nil) + (setq abbrevs-changed ac))) + +(defvar octave-comment-char ?# + "Character to start an Octave comment.") +(defvar octave-comment-start + (concat (make-string 1 octave-comment-char) " ") + "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 + '("for" "function" "if" "try" "unwind_protect" "while")) +(defvar octave-else-keywords + '("catch" "else" "elseif" "unwind_protect_cleanup")) +(defvar octave-end-keywords + '("end" "endfor" "endfunction" "endif" "end_try_catch" + "end_unwind_protect" "endwhile")) + +(defvar octave-reserved-words + (append octave-begin-keywords octave-else-keywords octave-end-keywords + '("all_va_args" "break" "continue" "global" "gplot" "gsplot" + "replot" "return")) + "Reserved words in Octave.") + +(defvar octave-text-functions + '("casesen" "cd" "chdir" "clear" "diary" "dir" "document" "echo" + "edit_history" "format" "gset" "gshow" "help" "history" "hold" + "load" "ls" "more" "run_history" "save" "set" "show" "type" + "which" "who" "whos") + "Text functions in Octave (these names are also reserved).") + +(defvar octave-variables + '("EDITOR" "EXEC_PATH" "F_DUPFD" "F_GETFD" "F_GETFL" "F_SETFD" + "F_SETFL" "I" "IMAGEPATH" "INFO_FILE" "INFO_PROGRAM" "Inf" "J" + "LOADPATH" "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__" + "__error_text__" "__i__" "__inf__" "__j__" "__nan__" "__pi__" + "__program_invocation_name__" "__program_name__" "__realmax__" + "__realmin__" "__stderr__" "__stdin__" "__stdout__" "ans" "argv" + "automatic_replot" "beep_on_error" "completion_append_char" + "default_return_value" "default_save_format" + "define_all_return_values" "do_fortran_indexing" "e" + "echo_executing_commands" "empty_list_elements_ok" "eps" + "error_text" "gnuplot_binary" "gnuplot_has_multiplot" "history_file" + "history_size" "ignore_function_time_stamp" "implicit_str_to_num_ok" + "inf" "nan" "nargin" "ok_to_lose_imaginary_part" + "output_max_field_width" "output_precision" + "page_output_immediately" "page_screen_output" "pi" + "prefer_column_vectors" "prefer_zero_one_indexing" + "print_answer_id_name" "print_empty_dimensions" + "program_invocation_name" "program_name" "propagate_empty_matrices" + "realmax" "realmin" "resize_on_range_error" + "return_last_computed_value" "save_precision" "saving_history" + "silent_functions" "split_long_rows" "stderr" "stdin" "stdout" + "string_fill_char" "struct_levels_to_print" + "suppress_verbose_help_message" "treat_neg_dim_as_zero" + "warn_assign_as_truth_value" "warn_comma_in_global_decl" + "warn_divide_by_zero" "warn_function_name_clash" + "warn_missing_semicolon" "whitespace_in_literal_matrix") + "Builtin variables in Octave.") + +(defvar octave-function-header-regexp + (concat "^\\s-*\\<\\(function\\)\\>" + "\\([^=;\n]*=[ \t]*\\|[ \t]*\\)\\(\\w+\\)\\>") + "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 "\\<\\(" + (mapconcat 'identity octave-reserved-words "\\|") + (mapconcat 'identity octave-text-functions "\\|") + "\\)\\>") + 'font-lock-keyword-face) + ;; Fontify all builtin operators. + (cons "\\(&\\||\\|<=\\|>=\\|==\\|<\\|>\\|!=\\|!\\)" + 'font-lock-reference-face) + ;; Fontify all builtin variables. + (cons (concat "\\<\\(" + (mapconcat 'identity 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.") + +(defvar inferior-octave-buffer "*Inferior Octave*" + "*Name of buffer for running an inferior Octave process.") + +(defvar inferior-octave-process nil) + +(defvar octave-mode-map nil + "Keymap used in Octave mode.") +(if octave-mode-map + () + (let ((map (make-sparse-keymap))) + (define-key map "`" 'octave-abbrev-start) + (define-key map ";" 'octave-electric-semi) + (define-key map " " 'octave-electric-space) + (define-key map "\n" 'octave-reindent-then-newline-and-indent) + (define-key map "\t" 'indent-according-to-mode) + (define-key map "\e;" 'octave-indent-for-comment) + (define-key map "\e\n" 'octave-indent-new-comment-line) + (define-key map "\e\t" 'octave-complete-symbol) + (define-key map "\M-\C-a" 'octave-beginning-of-defun) + (define-key map "\M-\C-e" 'octave-end-of-defun) + (define-key map "\M-\C-h" 'octave-mark-defun) + (define-key map "\M-\C-q" 'octave-indent-defun) + (define-key map "\C-c;" 'octave-comment-region) + (define-key map "\C-c:" 'octave-uncomment-region) + (define-key map "\C-c\C-b" 'octave-submit-bug-report) + (define-key map "\C-c\C-p" 'octave-previous-code-line) + (define-key map "\C-c\C-n" 'octave-next-code-line) + (define-key map "\C-c\C-a" 'octave-beginning-of-line) + (define-key map "\C-c\C-e" 'octave-end-of-line) + (define-key map "\C-c\M-\C-n" 'octave-forward-block) + (define-key map "\C-c\M-\C-p" 'octave-backward-block) + (define-key map "\C-c\M-\C-u" 'octave-backward-up-block) + (define-key map "\C-c\M-\C-d" 'octave-down-block) + (define-key map "\C-c\M-\C-h" 'octave-mark-block) + (define-key map "\C-c]" 'octave-close-block) + (define-key map "\C-cf" 'octave-insert-defun) + (define-key map "\C-c\C-h" 'octave-help) + (define-key map "\C-cil" 'octave-send-line) + (define-key map "\C-cib" 'octave-send-block) + (define-key map "\C-cif" 'octave-send-defun) + (define-key map "\C-cir" 'octave-send-region) + (define-key map "\C-cis" 'octave-show-process-buffer) + (define-key map "\C-cih" 'octave-hide-process-buffer) + (define-key map "\C-cik" 'octave-kill-process) + (setq octave-mode-map map))) + +(defvar octave-mode-menu + (list "Octave" + (list "Lines" + ["Previous Code Line" octave-previous-code-line t] + ["Next Code Line" octave-next-code-line t] + ["Begin of Continuation" octave-beginning-of-line t] + ["End of Continuation" octave-end-of-line t] + ["Split Line at Point" octave-indent-new-comment-line t]) + (list "Blocks" + ["Next Block" octave-forward-block t] + ["Previous Block" octave-backward-block t] + ["Down Block" octave-down-block t] + ["Up Block" octave-backward-up-block t] + ["Mark Block" octave-mark-block t] + ["Close Block" octave-close-block t]) + (list "Functions" + ["Begin of Function" octave-beginning-of-defun t] + ["End of Function" octave-end-of-defun t] + ["Mark Function" octave-mark-defun t] + ["Indent Function" octave-indent-defun t] + ["Insert Function" octave-insert-defun t]) + "-" + (list "Debug" + ["Send Current Line" octave-send-line t] + ["Send Current Block" octave-send-block t] + ["Send Current Function" octave-send-defun t] + ["Send Region" octave-send-region t] + ["Show Process Buffer" octave-show-process-buffer t] + ["Hide Process Buffer" octave-hide-process-buffer t] + ["Kill Process" octave-kill-process t]) + "-" + ["Indent Line" indent-according-to-mode t] + ["Complete Symbol" octave-complete-symbol t] + "-" + ["Toggle Abbrev Mode" abbrev-mode t] + ["Toggle Auto-Fill Mode" auto-fill-mode t] + "-" + ["Submit Bug Report" octave-submit-bug-report t] + "-" + ["Describe Octave Mode" octave-describe-major-mode t] + ["Lookup Octave Index" octave-help t]) + "Menu for Octave mode.") + +(defvar octave-mode-syntax-table nil + "Syntax table in use in octave-mode buffers.") +(if octave-mode-syntax-table + () + (let ((table (make-syntax-table))) + (modify-syntax-entry ?\r " " table) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?* "." table) + (modify-syntax-entry ?/ "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?| "." table) + (modify-syntax-entry ?! "." table) + (modify-syntax-entry ?\\ "\\" table) + (modify-syntax-entry ?\' "." table) + (modify-syntax-entry ?\` "w" table) + (modify-syntax-entry ?\" "\"" table) + (modify-syntax-entry ?. "w" table) + (modify-syntax-entry ?_ "w" table) + (modify-syntax-entry ?\% "." table) + (modify-syntax-entry ?\# "<" table) + (modify-syntax-entry ?\n ">" table) + (setq octave-mode-syntax-table table))) + +(defvar octave-auto-newline nil + "*Non-nil means automatically newline after a semicolon in Octave mode.") + +(defvar octave-blink-matching-block t + "*Control the blinking of matching Octave block keywords. +Non-nil means show matching begin of block when inserting a space, +newline or semicolon after an else or end keyword.") +(defvar octave-block-offset 2 + "*Extra indentation applied to statements in Octave block structures.") + +(defvar octave-block-begin-regexp + (concat "\\<\\(" + (mapconcat 'identity octave-begin-keywords "\\|") + "\\)\\>")) +(defvar octave-block-else-regexp + (concat "\\<\\(" + (mapconcat 'identity octave-else-keywords "\\|") + "\\)\\>")) +(defvar octave-block-end-regexp + (concat "\\<\\(" + (mapconcat 'identity octave-end-keywords "\\|") + "\\)\\>")) +(defvar octave-block-begin-or-end-regexp + (concat octave-block-begin-regexp "\\|" octave-block-end-regexp)) +(defvar octave-block-else-or-end-regexp + (concat octave-block-else-regexp "\\|" octave-block-end-regexp)) +(defvar octave-block-match-alist + '(("for" . ("end" "endfor")) + ("function" . ("end" "endfunction")) + ("if" . ("else" "elseif" "end" "endif")) + ("try" . ("catch" "end" "end_try_catch")) + ("unwind_protect" . ("unwind_protect_cleanup" "end" + "end_unwind_protect")) + ("while" . ("end" "endwhile"))) + "Alist with Octave's matching block keywords. +Has Octave's begin keywords as keys and a list of the matching else or +end keywords as associated values.") + +(defvar octave-block-comment-start + (concat (make-string 2 octave-comment-char) " ") + "String to insert to start a new Octave comment on an empty line.") + +(defvar octave-continuation-offset 4 + "*Extra indentation applied to Octave continuation lines.") +(defvar octave-continuation-regexp + "[^#%\n]*\\(\\\\\\|\\.\\.\\.\\)\\s-*\\(\\s<.*\\)?$") +(defvar octave-continuation-string "\\" + "*Character string used for Octave continuation lines. Normally \\.") + +(defvar octave-completion-alist nil + "Alist of Octave symbols for completion in Octave mode. +Each element looks like (VAR . VAR), where the car and cdr are the same +symbol (an Octave command or variable name). +Currently, only builtin variables can be completed.") + +(defvar octave-mode-imenu-generic-expression + (list + ;; Functions + (list nil octave-function-header-regexp 3)) + "Imenu expression for Octave mode. See `imenu-generic-expression'.") + +(defvar octave-mode-startup-message t + "*Nil means do not display the Octave mode startup message.") + +(defvar octave-mode-hook nil + "*Hook to be run when Octave mode is started.") + +(defvar octave-send-show-buffer t + "*Non-nil means display `inferior-octave-buffer' after sending to it.") +(defvar octave-send-line-auto-forward t + "*Control auto-forward after sending to the inferior Octave process. +Non-nil means always go to the next Octave code line after sending.") +(defvar octave-send-echo-input t + "*Non-nil means echo input sent to the inferior Octave process.") + + +;;;###autoload +(defun octave-mode () + "Major mode for editing Octave code. + +This mode makes it easier to write Octave code by helping with +indentation, doing some of the typing for you (with Abbrev mode) and by +showing keywords, comments, strings, etc. in different faces (with +Font Lock mode on terminals that support it). + +Octave itself is a high-level language, primarily intended for numerical +computations. It provides a convenient command line interface for +solving linear and nonlinear problems numerically. Function definitions +can also be stored in files, and it can be used in a batch mode (which +is why you need this mode!). + +The latest released version of Octave is always available via anonymous +ftp from bevo.che.wisc.edu in the directory `/pub/octave'. Complete +source and binaries for several popular systems are available. + +Type \\[list-abbrevs] to display the built-in abbrevs for Octave keywords. + +Keybindings +=========== + +\\{octave-mode-map} + +Variables you can use to customize Octave mode +============================================== + +octave-auto-newline + Non-nil means auto-insert a newline and indent after a semicolon. + Default is nil. + +octave-blink-matching-block + Non-nil means show matching begin of block when inserting a space, + newline or semicolon after an else or end keyword. Default is t. + +octave-block-offset + Extra indentation applied to statements in block structures. + Default is 2. + +octave-continuation-offset + Extra indentation applied to Octave continuation lines. + Default is 4. + +octave-continuation-string + String used for Octave continuation lines. + Default is a backslash. + +octave-mode-startup-message + Nil means do not display the Octave mode startup message. + Default is t. + +octave-send-echo-input + Non-nil means always display `inferior-octave-buffer' after sending a + command to the inferior Octave process. + +octave-send-line-auto-forward + Non-nil means always go to the next unsent line of Octave code after + sending a line to the inferior Octave process. + +octave-send-echo-input + Non-nil means echo input sent to the inferior Octave process. + +Turning on Octave mode runs the hook `octave-mode-hook'. + +To begin using this mode for all `.m' files that you edit, add the +following lines to your `.emacs' file: + + (autoload 'octave-mode \"octave-mod\" nil t) + (setq auto-mode-alist + (cons '(\"\\\\.m$\" . octave-mode) auto-mode-alist)) + +To automatically turn on the abbrev, auto-fill and font-lock features, +add the following lines to your `.emacs' file as well: + + (add-hook 'octave-mode-hook + (lambda () + (abbrev-mode 1) + (auto-fill-mode 1) + (if (eq window-system 'x) + (font-lock-mode 1)))) + +To submit a problem report, enter \\[octave-submit-bug-report] from \ +an Octave mode buffer. +This automatically sets up a mail buffer with version information +already added. You just need to add a description of the problem, +including a reproducible test case and send the message." + (interactive) + (kill-all-local-variables) + + (use-local-map octave-mode-map) + (setq major-mode 'octave-mode) + (setq mode-name "Octave") + (setq local-abbrev-table octave-abbrev-table) + (set-syntax-table octave-mode-syntax-table) + + (make-local-variable 'indent-line-function) + (setq indent-line-function 'octave-indent-line) + + (make-local-variable 'comment-start) + (setq comment-start octave-comment-start) + (make-local-variable 'comment-end) + (setq comment-end "") + (make-local-variable 'comment-column) + (setq comment-column 32) + (make-local-variable 'comment-start-skip) + (setq comment-start-skip "\\s<+\\s-*") + (make-local-variable 'comment-indent-function) + (setq comment-indent-function 'octave-comment-indent) + + (make-local-variable 'parse-sexp-ignore-comments) + (setq parse-sexp-ignore-comments t) + (make-local-variable 'paragraph-start) + (setq paragraph-start (concat "\\s-*$\\|" page-delimiter)) + (make-local-variable 'paragraph-separate) + (setq paragraph-separate paragraph-start) + (make-local-variable 'paragraph-ignore-fill-prefix) + (setq paragraph-ignore-fill-prefix t) + (make-local-variable 'fill-paragraph-function) + (setq fill-paragraph-function 'octave-fill-paragraph) + (make-local-variable 'adaptive-fill-regexp) + (setq adaptive-fill-regexp nil) + (make-local-variable 'fill-column) + (setq fill-column 72) + (make-local-variable 'normal-auto-fill-function) + (setq normal-auto-fill-function 'octave-auto-fill) + + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(octave-font-lock-keywords nil nil)) + + (make-local-variable 'imenu-generic-expression) + (setq imenu-generic-expression octave-mode-imenu-generic-expression) + + (octave-add-octave-menu) + (octave-initialize-completions) + (run-hooks 'octave-mode-hook)) + +;;; Miscellaneous useful functions +(defun octave-describe-major-mode () + "Describe the current major mode." + (interactive) + (describe-function major-mode)) + +(defun octave-point (position) + "Returns the value of point at certain positions." + (save-excursion + (cond + ((eq position 'bol) (beginning-of-line)) + ((eq position 'eol) (end-of-line)) + ((eq position 'boi) (back-to-indentation)) + ((eq position 'bonl) (forward-line 1)) + ((eq position 'bopl) (forward-line -1)) + (t (error "unknown buffer position requested: %s" position))) + (point))) + +(defsubst octave-in-comment-p () + "Returns t if point is inside an Octave comment, nil otherwise." + (interactive) + (save-excursion + (nth 4 (parse-partial-sexp (octave-point 'bol) (point))))) + +(defsubst octave-in-string-p () + "Returns t if point is inside an Octave string, nil otherwise." + (interactive) + (save-excursion + (nth 3 (parse-partial-sexp (octave-point 'bol) (point))))) + +(defsubst octave-not-in-string-or-comment-p () + "Returns t iff point is not inside an Octave string or comment." + (let ((pps (parse-partial-sexp (octave-point 'bol) (point)))) + (not (or (nth 3 pps) (nth 4 pps))))) + +(defun octave-in-block-p () + "Returns t if point is inside an Octave block, nil otherwise. +The block is taken to start at the first letter of the begin keyword and +to end after the end keyword." + (let ((pos (point))) + (save-excursion + (condition-case nil + (progn + (skip-syntax-forward "w") + (octave-up-block -1) + (octave-forward-block) + t) + (error nil)) + (< pos (point))))) + +(defun octave-in-defun-p () + "Returns t iff point is inside an Octave function declaration. +The function is taken to start at the `f' of `function' and to end after +the end keyword." + (let ((pos (point))) + (save-excursion + (or (and (looking-at "\\<function\\>") + (octave-not-in-string-or-comment-p)) + (and (octave-beginning-of-defun) + (condition-case nil + (progn + (octave-forward-block) + t) + (error nil)) + (< pos (point))))))) + +;;; Comments +(defun octave-comment-region (beg end &optional arg) + "Comment or uncomment each line in the region as Octave code. +See `comment-region'." + (interactive "r\nP") + (let ((comment-start (char-to-string octave-comment-char))) + (comment-region beg end arg))) + +(defun octave-uncomment-region (beg end &optional arg) + "Uncomment each line in the region as Octave code." + (interactive "r\nP") + (or arg (setq arg 1)) + (octave-comment-region beg end (- arg))) + + +;;; Indentation +(defun calculate-octave-indent () + "Return appropriate indentation for current line as Octave code. +Returns an integer (the column to indent to) unless the line is a +comment line with fixed goal golumn. In that case, returns a list whose +car is the column to indent to, and whose cdr is the current indentation +level." + (let ((is-continuation-line + (save-excursion + (if (zerop (octave-previous-code-line)) + (looking-at octave-continuation-regexp)))) + (icol 0)) + (save-excursion + (beginning-of-line) + ;; If we can move backward out one level of parentheses, take 1 + ;; plus the indentation of that parenthesis. Otherwise, go back + ;; to the beginning of the previous code line, and compute the + ;; offset this line gives. + (if (condition-case nil + (progn + (up-list -1) + t) + (error nil)) + (setq icol (+ 1 (current-column))) + (if (zerop (octave-previous-code-line)) + (progn + (octave-beginning-of-line) + (back-to-indentation) + (setq icol (current-column)) + (let ((bot (point)) + (eol (octave-point 'eol))) + (while (< (point) eol) + (if (octave-not-in-string-or-comment-p) + (cond + ((looking-at octave-block-begin-regexp) + (setq icol (+ icol octave-block-offset))) + ((looking-at octave-block-else-regexp) + (if (= bot (point)) + (setq icol (+ icol octave-block-offset)))) + ((looking-at octave-block-end-regexp) + (if (not (= bot (point))) + (setq icol (- icol octave-block-offset)))))) + (forward-char))) + (if is-continuation-line + (setq icol (+ icol octave-continuation-offset))))))) + (save-excursion + (back-to-indentation) + (cond + ((and (or (looking-at octave-block-else-regexp) + (looking-at octave-block-end-regexp)) + (octave-not-in-string-or-comment-p)) + (setq icol (- icol octave-block-offset))) + ((looking-at "\\s<\\s<\\s<\\S<") + (setq icol (list 0 icol))) + ((looking-at "\\s<\\S<") + (setq icol (list comment-column icol))))) + icol)) + +(defun octave-comment-indent () + (if (looking-at "\\s<\\s<\\s<") + 0 + (if (looking-at "\\s<\\s<") + (calculate-octave-indent) + (skip-syntax-backward " ") + (max (if (bolp) 0 (+ (current-column))) + comment-column)))) + +(defun octave-indent-for-comment () + "Maybe insert and indent an Octave comment. +If there is no comment already on this line, create a code-level comment +(started by two comment characters) if the line is empty, or an in-line +comment (started by one comment character) otherwise. +Point is left after the start of the comment which is properly aligned." + (interactive) + (indent-for-comment) + (indent-according-to-mode)) + +(defun octave-indent-line (&optional arg) + "Indent current line as Octave code. +With optional ARG, use this as offset unless this line is a comment with +fixed goal column." + (interactive) + (or arg (setq arg 0)) + (let ((icol (calculate-octave-indent)) + (relpos (- (current-column) (current-indentation)))) + (if (listp icol) + (setq icol (car icol)) + (setq icol (+ icol arg))) + (if (< icol 0) + (error "Unmatched end keyword") + (indent-line-to icol) + (if (> relpos 0) + (move-to-column (+ icol relpos)))))) + +(defun octave-indent-new-comment-line () + "Break Octave line at point, continuing comment if within one. +If within code, insert `octave-continuation-string' before breaking the +line. If within a string, signal an error. +The new line is properly indented." + (interactive) + (delete-horizontal-space) + (cond + ((octave-in-comment-p) + (indent-new-comment-line)) + ((octave-in-string-p) + (error "Cannot split a code line inside a string")) + (t + (insert (concat " " octave-continuation-string)) + (octave-reindent-then-newline-and-indent)))) + +(defun octave-indent-defun () + "Properly indents the Octave function which contains point." + (interactive) + (save-excursion + (octave-mark-defun) + (message "Indenting function...") + (indent-region (point) (mark) nil)) + (message "Indenting function...done.")) + + +;;; Motion +(defun octave-next-code-line (&optional arg) + "Move ARG lines of Octave code forward (backward if ARG is negative). +Skips past all empty and comment lines. Default for ARG is 1. + +On success, return 0. Otherwise, go as far as possible and return -1." + (interactive "p") + (or arg (setq arg 1)) + (beginning-of-line) + (let ((n 0) + (inc (if (> arg 0) 1 -1))) + (while (and (/= arg 0) (= n 0)) + (setq n (forward-line inc)) + (while (and (= n 0) + (looking-at "\\s-*\\($\\|\\s<\\)")) + (setq n (forward-line inc))) + (setq arg (- arg inc))) + n)) + +(defun octave-previous-code-line (&optional arg) + "Move ARG lines of Octave code backward (forward if ARG is negative). +Skips past all empty and comment lines. Default for ARG is 1. + +On success, return 0. Otherwise, go as far as possible and return -1." + (interactive "p") + (or arg (setq arg 1)) + (octave-next-code-line (- arg))) + +(defun octave-beginning-of-line () + "Move point to beginning of current Octave line. +If on an empty or comment line, go to the beginning of that line. +Otherwise, move backward to the beginning of the first Octave code line +which is not inside a continuation statement, i.e., which does not +follow a code line ending in `...' or `\\', or is inside an open +parenthesis list." + (interactive) + (beginning-of-line) + (if (not (looking-at "\\s-*\\($\\|\\s<\\)")) + (while (or (condition-case nil + (progn + (up-list -1) + (beginning-of-line) + t) + (error nil)) + (and (or (looking-at "\\s-*\\($\\|\\s<\\)") + (save-excursion + (if (zerop (octave-previous-code-line)) + (looking-at octave-continuation-regexp)))) + (zerop (forward-line -1))))))) + +(defun octave-end-of-line () + "Move point to end of current Octave line. +If on an empty or comment line, go to the end of that line. +Otherwise, move forward to the end of the first Octave code line which +does not end in `...' or `\\' or is inside an open parenthesis list." + (interactive) + (end-of-line) + (if (save-excursion + (beginning-of-line) + (looking-at "\\s-*\\($\\|\\s<\\)")) + () + (while (or (condition-case nil + (progn + (up-list 1) + (end-of-line) + t) + (error nil)) + (and (save-excursion + (beginning-of-line) + (or (looking-at "\\s-*\\($\\|\\s<\\)") + (looking-at octave-continuation-regexp))) + (zerop (forward-line 1))))) + (end-of-line))) + +(defun octave-scan-blocks (from count depth) + "Scan from character number FROM by COUNT Octave begin-end blocks. +Returns the character number of the position thus found. + +If DEPTH is nonzero, block depth begins counting from that value. +Only places where the depth in blocks becomes zero are candidates for +stopping; COUNT such places are counted. + +If the beginning or end of the buffer is reached and the depth is wrong, +an error is signaled." + (let ((min-depth (if (> depth 0) 0 depth)) + (inc (if (> count 0) 1 -1))) + (save-excursion + (while (/= count 0) + (catch 'foo + (while (or (re-search-forward + octave-block-begin-or-end-regexp nil 'move inc) + (if (/= depth 0) + (error "Unbalanced block"))) + (if (octave-not-in-string-or-comment-p) + (progn + (cond + ((match-end 1) + (setq depth (+ depth inc))) + ((match-end 2) + (setq depth (- depth inc)))) + (if (< depth min-depth) + (error "Containing expression ends prematurely")) + (if (= depth 0) + (throw 'foo nil)))))) + (setq count (- count inc))) + (point)))) + +(defun octave-forward-block (&optional arg) + "Move forward across one balanced Octave begin-end block. +With argument, do it that many times. +Negative arg -N means move backward across N blocks." + (interactive "p") + (or arg (setq arg 1)) + (goto-char (or (octave-scan-blocks (point) arg 0) (buffer-end arg)))) + +(defun octave-backward-block (&optional arg) + "Move backward across one balanced Octave begin-end block. +With argument, do it that many times. +Negative arg -N means move forward across N blocks." + (interactive "p") + (or arg (setq arg 1)) + (octave-forward-block (- arg))) + +(defun octave-down-block (arg) + "Move forward down one begin-end block level of Octave code. +With argument, do this that many times. +A negative argument means move backward but still go down a level. +In Lisp programs, an argument is required." + (interactive "p") + (let ((inc (if (> arg 0) 1 -1))) + (while (/= arg 0) + (goto-char (or (octave-scan-blocks (point) inc -1) + (buffer-end arg))) + (setq arg (- arg inc))))) + +(defun octave-backward-up-block (arg) + "Move backward out of one begin-end block level of Octave code. +With argument, do this that many times. +A negative argument means move forward but still to a less deep spot. +In Lisp programs, an argument is required." + (interactive "p") + (octave-up-block (- arg))) + +(defun octave-up-block (arg) + "Move forward out of one begin-end block level of Octave code. +With argument, do this that many times. +A negative argument means move backward but still to a less deep spot. +In Lisp programs, an argument is required." + (interactive "p") + (let ((inc (if (> arg 0) 1 -1))) + (while (/= arg 0) + (goto-char (or (octave-scan-blocks (point) inc 1) + (buffer-end arg))) + (setq arg (- arg inc))))) + +(defun octave-mark-block () + "Put point at the beginning of this Octave block, mark at the end. +The block marked is the one that contains point or follows point." + (interactive) + (let ((pos (point))) + (if (or (and (octave-in-block-p) + (skip-syntax-forward "w")) + (condition-case nil + (progn + (octave-down-block 1) + (octave-in-block-p)) + (error nil))) + (progn + (octave-up-block -1) + (push-mark (point)) + (octave-forward-block) + (exchange-point-and-mark)) + (goto-char pos) + (message "No block to mark found")))) + +(defun octave-close-block () + "Close the current Octave block on a separate line. +An error is signaled if no block to close is found." + (interactive) + (let (bb-keyword) + (condition-case nil + (progn + (save-excursion + (octave-backward-up-block 1) + (setq bb-keyword (buffer-substring-no-properties + (match-beginning 1) (match-end 1)))) + (if (save-excursion + (beginning-of-line) + (looking-at "^\\s-*$")) + (indent-according-to-mode) + (octave-reindent-then-newline-and-indent)) + (insert (car (reverse + (assoc bb-keyword + octave-block-match-alist)))) + (octave-reindent-then-newline-and-indent) + t) + (error (message "No block to close found"))))) + +(defun octave-blink-matching-block-open () + "Blink the matching Octave begin block keyword. +If point is right after an Octave else or end type block keyword, move +cursor momentarily to the corresponding begin keyword. +Signal an error if the keywords are incompatible." + (interactive) + (let (bb-keyword bb-arg eb-keyword pos eol) + (if (and (octave-not-in-string-or-comment-p) + (looking-at "\\>") + (save-excursion + (skip-syntax-backward "w") + (looking-at octave-block-else-or-end-regexp))) + (save-excursion + (cond + ((match-end 1) + (setq eb-keyword + (buffer-substring-no-properties + (match-beginning 1) (match-end 1))) + (octave-backward-up-block 1)) + ((match-end 2) + (setq eb-keyword + (buffer-substring-no-properties + (match-beginning 2) (match-end 2))) + (octave-backward-block))) + (setq pos (match-end 0) + bb-keyword + (buffer-substring-no-properties + (match-beginning 0) pos) + pos (+ pos 1) + eol (octave-point 'eol) + bb-arg + (save-excursion + (save-restriction + (goto-char pos) + (while (and (skip-syntax-forward "^<" eol) + (octave-in-string-p) + (not (forward-char 1)))) + (skip-syntax-backward " ") + (buffer-substring-no-properties pos (point))))) + (if (member eb-keyword + (cdr (assoc bb-keyword octave-block-match-alist))) + (progn + (message "Matches `%s %s'" bb-keyword bb-arg) + (if (pos-visible-in-window-p) + (sit-for blink-matching-delay))) + (error "Block keywords `%s' and `%s' do not match" + bb-keyword eb-keyword)))))) + +(defun octave-beginning-of-defun (&optional arg) + "Move backward to the beginning of an Octave function. +With positive ARG, do it that many times. Negative argument -N means +move forward to Nth following beginning of a function. +Returns t unless search stops at the beginning or end of the buffer." + (interactive "p") + (let* ((arg (or arg 1)) + (inc (if (> arg 0) 1 -1)) + (found)) + (and (not (eobp)) + (not (and (> arg 0) (looking-at "\\<function\\>"))) + (skip-syntax-forward "w")) + (while (and (/= arg 0) + (setq found + (re-search-backward "\\<function\\>" nil 'move inc))) + (if (octave-not-in-string-or-comment-p) + (setq arg (- arg inc)))) + (if found + (progn + (and (< inc 0) (goto-char (match-beginning 0))) + t)))) + +(defun octave-end-of-defun (&optional arg) + "Move forward to the end of an Octave function. +With positive ARG, do it that many times. Negative argument -N means +move back to Nth preceding end of a function. + +An end of a function occurs right after the end keyword matching the +`function' keyword that starts the function." + (interactive "p") + (or arg (setq arg 1)) + (and (< arg 0) (skip-syntax-backward "w")) + (and (> arg 0) (skip-syntax-forward "w")) + (if (octave-in-defun-p) + (setq arg (- arg 1))) + (if (= arg 0) (setq arg -1)) + (if (octave-beginning-of-defun (- arg)) + (octave-forward-block))) + +(defun octave-mark-defun () + "Put point at the beginning of this Octave function, mark at its end. +The function marked is the one containing point or following point." + (interactive) + (let ((pos (point))) + (if (or (octave-in-defun-p) + (and (octave-beginning-of-defun -1) + (octave-in-defun-p))) + (progn + (skip-syntax-forward "w") + (octave-beginning-of-defun) + (push-mark (point)) + (octave-end-of-defun) + (exchange-point-and-mark)) + (goto-char pos) + (message "No function to mark found")))) + + +;;; Filling +(defun octave-auto-fill () + "Perform auto-fill in Octave mode." + (if (> (current-column) (current-fill-column)) + (if (octave-in-comment-p) + (do-auto-fill) + (if (> (current-column) (current-fill-column)) + (let ((fill-column (- (current-fill-column) + (length octave-continuation-string)))) + (do-auto-fill) + (save-excursion + (forward-line -1) + (end-of-line) + (insert (concat " " octave-continuation-string))) + (indent-according-to-mode)))))) + +(defun octave-fill-paragraph (&optional arg) + "Fill paragraph of Octave code, handling Octave comments." + (interactive "P") + (save-excursion + (let ((end (progn (forward-paragraph) (point))) + (beg (progn + (forward-paragraph -1) + (skip-chars-forward " \t\n") + (beginning-of-line) + (point))) + (cfc (current-fill-column)) + (ind (calculate-octave-indent)) + comment-prefix) + (save-restriction + (goto-char beg) + (narrow-to-region beg end) + (if (listp ind) (setq ind (nth 1 ind))) + (while (not (eobp)) + (condition-case nil + (octave-indent-line ind) + (error nil)) + (if (and (> ind 0) + (not + (save-excursion + (beginning-of-line) + (looking-at "^\\s-*\\($\\|\\s<+\\)")))) + (setq ind 0)) + (move-to-column cfc) + ;; First check whether we need to combine non-empty comment lines + (if (and (< (current-column) cfc) + (octave-in-comment-p) + (not (save-excursion + (beginning-of-line) + (looking-at "^\\s-*\\s<+\\s-*$")))) + ;; This is a nonempty comment line which does not extend + ;; past the fill column. If it is followed by an nonempty + ;; comment line with the same comment prefix, try to + ;; combine them, and repeat this until either we reach the + ;; fill-column or there is nothing more to combine. + (progn + ;; Get the comment prefix + (save-excursion + (beginning-of-line) + (while (and (re-search-forward "\\s<+") + (not (octave-in-comment-p)))) + (setq comment-prefix (match-string 0))) + ;; And keep combining ... + (while (and (< (current-column) cfc) + (save-excursion + (forward-line 1) + (and (looking-at + (concat "^\\s-*" + comment-prefix + "\\S<")) + (not (looking-at + (concat "^\\s-*" + comment-prefix + "\\s-*$")))))) + (delete-char 1) + (re-search-forward comment-prefix) + (delete-region (match-beginning 0) (match-end 0)) + (fixup-whitespace) + (move-to-column cfc)))) + (skip-chars-forward "^ \t\n") + (delete-horizontal-space) + (if (or (< (current-column) cfc) + (and (= (current-column) cfc) (eolp))) + (forward-line 1) + (if (not (eolp)) (insert " ")) + (octave-auto-fill)))) + t))) + + +;;; Completions +(defun octave-initialize-completions () + "Create an alist for Octave completions." + (if octave-completion-alist + () + (setq octave-completion-alist + (mapcar '(lambda (var) (cons var var)) + (append octave-reserved-words + octave-text-functions + octave-variables))))) + +(defun octave-complete-symbol () + "Perform completion on Octave symbol preceding point. +Compare that symbol against Octave's reserved words and builtin +variables." + ;; This code taken from lisp-complete-symbol + (interactive) + (let* ((end (point)) + (beg (save-excursion (backward-sexp 1) (point))) + (string (buffer-substring-no-properties beg end)) + (completion (try-completion string octave-completion-alist))) + (cond ((eq completion t)) ; ??? + ((null completion) + (message "Can't find completion for \"%s\"" string) + (ding)) + ((not (string= string completion)) + (delete-region beg end) + (insert completion)) + (t + (let ((list (all-completions string octave-completion-alist)) + (conf (current-window-configuration))) + ;; Taken from comint.el + (message "Making completion list...") + (with-output-to-temp-buffer "*Completions*" + (display-completion-list list)) + (message "Hit space to flush") + (let (key first) + (if (save-excursion + (set-buffer (get-buffer "*Completions*")) + (setq key (read-key-sequence nil) + first (aref key 0)) + (and (consp first) (consp (event-start first)) + (eq (window-buffer (posn-window (event-start + first))) + (get-buffer "*Completions*")) + (eq (key-binding key) 'mouse-choose-completion))) + (progn + (mouse-choose-completion first) + (set-window-configuration conf)) + (if (eq first ?\ ) + (set-window-configuration conf) + (setq unread-command-events + (listify-key-sequence key)))))))))) + + +;;; Electric characters && friends +(defun octave-reindent-then-newline-and-indent () + "Reindent current Octave line, insert newline, and indent the new line. +If Abbrev mode is on, expand abbrevs first." + (interactive) + (if abbrev-mode (expand-abbrev)) + (if octave-blink-matching-block + (octave-blink-matching-block-open)) + (save-excursion + (delete-region (point) (progn (skip-chars-backward " \t") (point))) + (indent-according-to-mode)) + (insert "\n") + (indent-according-to-mode)) + +(defun octave-electric-semi () + "Insert a semicolon in Octave mode. +Always reindent the line. Insert a newline if `octave-auto-newline' is +non-nil." + (interactive) + (if (not (octave-not-in-string-or-comment-p)) + (insert ";") + (if abbrev-mode (expand-abbrev)) + (if octave-blink-matching-block + (octave-blink-matching-block-open)) + (indent-according-to-mode) + (insert ";") + (if octave-auto-newline + (newline-and-indent)))) + +(defun octave-electric-space () + "Insert a space in Octave mode. +Maybe expand abbrevs and blink matching block open keywords." + (interactive) + (setq last-command-char ? ) + (if (not (octave-not-in-string-or-comment-p)) + (progn + (indent-according-to-mode) + (self-insert-command 1)) + (if abbrev-mode (expand-abbrev)) + (if octave-blink-matching-block + (octave-blink-matching-block-open)) + (if (save-excursion + (skip-syntax-backward " ") + (not (bolp))) + (indent-according-to-mode)) + (self-insert-command 1))) + +(defun octave-abbrev-start () + "Start entering an Octave abbreviation. +If Abbrev mode is turned on, typing ` (grave accent) followed by ? or +\\[help-command] lists all Octave abbrevs. Any other key combination is +executed normally. +Note that all Octave mode abbrevs start with a grave accent." + (interactive) + (if (not abbrev-mode) + (self-insert-command 1) + (let (c) + (insert last-command-char) + (if (or (eq (setq c (read-event)) ??) + (eq c help-char)) + (let ((abbrev-table-name-list '(octave-mode-abbrev-table))) + (list-abbrevs)) + (setq unread-command-events (list c)))))) + +(defun octave-insert-defun (name args vals) + "Insert an Octave function skeleton. +Prompt for the function's name, arguments and return values (to be +entered without parens)." + (interactive + (list + (read-from-minibuffer "Function name: " + (substring (buffer-name) 0 -2)) + (read-from-minibuffer "Arguments: ") + (read-from-minibuffer "Return values: "))) + (let ((string (format "%s %s (%s)" + (cond + ((string-equal vals "") + vals) + ((string-match "[ ,]" vals) + (concat " [" vals "] =")) + (t + (concat " " vals " ="))) + name + args)) + (prefix octave-block-comment-start)) + (if (not (bobp)) (newline)) + (insert "function" string) + (indent-according-to-mode) + (newline 2) + (insert prefix "usage: " string) + (reindent-then-newline-and-indent) + (insert prefix) + (reindent-then-newline-and-indent) + (insert prefix) + (indent-according-to-mode) + (save-excursion + (newline 2) + (insert "endfunction") + (indent-according-to-mode)))) + + +;;; Menu +(defun octave-add-octave-menu () + "Adds the `Octave' menu to the menu bar in Octave mode." + (require 'easymenu) + (easy-menu-define octave-mode-menu-map octave-mode-map + "Menu keymap for Octave mode." octave-mode-menu) + (easy-menu-add octave-mode-menu-map octave-mode-map)) + + +;;; Communication with the inferior Octave process +(defun octave-kill-process () + "Kill inferior Octave process and its buffer." + (interactive) + (if inferior-octave-process + (progn + (process-send-string inferior-octave-process "quit;\n") + (accept-process-output inferior-octave-process))) + (if inferior-octave-buffer + (kill-buffer inferior-octave-buffer))) + +(defun octave-show-process-buffer () + "Make sure that `inferior-octave-buffer' is displayed." + (interactive) + (if (get-buffer inferior-octave-buffer) + (display-buffer inferior-octave-buffer) + (message "No buffer named %s" inferior-octave-buffer))) + +(defun octave-hide-process-buffer () + "Delete all windows that display `inferior-octave-buffer'." + (interactive) + (if (get-buffer inferior-octave-buffer) + (delete-windows-on inferior-octave-buffer) + (message "No buffer named %s" inferior-octave-buffer))) + +(defun octave-send-region (beg end) + "Send current region to the inferior Octave process." + (interactive "r") + (inferior-octave t) + (let ((proc inferior-octave-process) + (string (buffer-substring-no-properties beg end)) + line) + (save-excursion + (set-buffer inferior-octave-buffer) + (setq inferior-octave-output-list nil) + (while (not (string-equal string "")) + (if (string-match "\n" string) + (setq line (substring string 0 (match-beginning 0)) + string (substring string (match-end 0))) + (setq line string string "")) + (setq inferior-octave-receive-in-progress t) + (inferior-octave-send-list-and-digest (list (concat line "\n"))) + (while inferior-octave-receive-in-progress + (accept-process-output proc)) + (insert-before-markers + (mapconcat 'identity + (append + (if octave-send-echo-input (list line) (list "")) + (mapcar 'inferior-octave-strip-ctrl-g + inferior-octave-output-list) + (list inferior-octave-output-string)) + "\n"))))) + (if octave-send-show-buffer + (display-buffer inferior-octave-buffer))) + +(defun octave-send-block () + "Send current Octave block to the inferior Octave process." + (interactive) + (save-excursion + (octave-mark-block) + (octave-send-region (point) (mark)))) + +(defun octave-send-defun () + "Send current Octave function to the inferior Octave process." + (interactive) + (save-excursion + (octave-mark-defun) + (octave-send-region (point) (mark)))) + +(defun octave-send-line (&optional arg) + "Send current Octave code line to the inferior Octave process. +With positive prefix ARG, send that many lines. +If `octave-send-line-auto-forward' is non-nil, go to the next unsent +code line." + (interactive "P") + (or arg (setq arg 1)) + (if (> arg 0) + (let (beg end) + (beginning-of-line) + (setq beg (point)) + (octave-next-code-line (- arg 1)) + (end-of-line) + (setq end (point)) + (if octave-send-line-auto-forward + (octave-next-code-line 1)) + (octave-send-region beg end)))) + +(defun octave-eval-print-last-sexp () + "Evaluate Octave sexp before point and print value into current buffer." + (interactive) + (inferior-octave t) + (let ((standard-output (current-buffer)) + (print-escape-newlines nil) + (opoint (point))) + (terpri) + (prin1 + (save-excursion + (forward-sexp -1) + (inferior-octave-send-list-and-digest + (list (concat (buffer-substring-no-properties (point) opoint) + "\n"))) + (mapconcat 'identity inferior-octave-output-list "\n"))) + (terpri))) + +;;; 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-auto-newline + 'octave-blink-matching-block + 'octave-block-offset + 'octave-comment-char + 'octave-continuation-offset + 'octave-continuation-string + 'octave-help-files + 'octave-mode-startup-message + 'octave-send-echo-input + 'octave-send-line-auto-forward + 'octave-send-show-buffer)))) + +;;; provide ourself + +(provide 'octave-mod) + +;;; octave-mod.el ends here
deleted file mode 100644 --- a/emacs/octave.el +++ /dev/null @@ -1,1786 +0,0 @@ -;; octave.el --- Octave mode for GNU Emacs - -;;; Copyright (C) 1996 Free Software Foundation, Inc. - -;; Author: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at> -;; Author: John Eaton <jwe@bevo.che.wisc.edu> -;; Maintainer: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at> -;; Version: 0.8.7 -;; Keywords: languages - -;; This file is not yet a part of GNU Emacs. It is part of Octave. - -;; Octave is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; Octave is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA -;; 02111-1307, USA. - -;;; Commentary: - -;; This package provides a major mode for editing Octave code. It knows -;; about Octave syntax and comments. It also provides a major mode for -;; interacting with an inferior Octave process using comint, both -;; directly and by sending parts of a file with Octave code. - -;;; Code: - -(defconst octave-version "0.8.7") -(defconst octave-help-address - "Kurt.Hornik@ci.tuwien.ac.at" - "Address for Octave mode bug reports") - - -(defvar octave-mode-map nil - "Keymap used in Octave mode.") -(if octave-mode-map - () - (let ((map (make-sparse-keymap))) - (define-key map "`" 'octave-abbrev-start) - (define-key map ";" 'octave-electric-semi) - (define-key map " " 'octave-electric-space) - (define-key map "\n" 'octave-reindent-then-newline-and-indent) - (define-key map "\t" 'indent-according-to-mode) - (define-key map "\e;" 'octave-indent-for-comment) - (define-key map "\e\n" 'octave-indent-new-comment-line) - (define-key map "\e\t" 'octave-complete-symbol) - (define-key map "\M-\C-a" 'octave-beginning-of-defun) - (define-key map "\M-\C-e" 'octave-end-of-defun) - (define-key map "\M-\C-h" 'octave-mark-defun) - (define-key map "\M-\C-q" 'octave-indent-defun) - (define-key map "\C-c;" 'octave-comment-region) - (define-key map "\C-c:" 'octave-uncomment-region) - (define-key map "\C-c\C-b" 'octave-submit-bug-report) - (define-key map "\C-c\C-p" 'octave-previous-code-line) - (define-key map "\C-c\C-n" 'octave-next-code-line) - (define-key map "\C-c\C-a" 'octave-beginning-of-line) - (define-key map "\C-c\C-e" 'octave-end-of-line) - (define-key map "\C-c\M-\C-n" 'octave-forward-block) - (define-key map "\C-c\M-\C-p" 'octave-backward-block) - (define-key map "\C-c\M-\C-u" 'octave-backward-up-block) - (define-key map "\C-c\M-\C-d" 'octave-down-block) - (define-key map "\C-c\M-\C-h" 'octave-mark-block) - (define-key map "\C-c]" 'octave-close-block) - (define-key map "\C-cf" 'octave-insert-defun) - (define-key map "\C-c\C-h" 'octave-help) - (define-key map "\C-cil" 'octave-send-line) - (define-key map "\C-cib" 'octave-send-block) - (define-key map "\C-cif" 'octave-send-defun) - (define-key map "\C-cir" 'octave-send-region) - (define-key map "\C-cis" 'octave-show-process-buffer) - (define-key map "\C-cih" 'octave-hide-process-buffer) - (define-key map "\C-cik" 'octave-kill-process) - (setq octave-mode-map map))) - -(defvar octave-mode-menu - (list "Octave" - (list "Lines" - ["Previous Code Line" octave-previous-code-line t] - ["Next Code Line" octave-next-code-line t] - ["Begin of Continuation" octave-beginning-of-line t] - ["End of Continuation" octave-end-of-line t] - ["Split Line at Point" octave-indent-new-comment-line t]) - (list "Blocks" - ["Next Block" octave-forward-block t] - ["Previous Block" octave-backward-block t] - ["Down Block" octave-down-block t] - ["Up Block" octave-backward-up-block t] - ["Mark Block" octave-mark-block t] - ["Close Block" octave-close-block t]) - (list "Functions" - ["Begin of Function" octave-beginning-of-defun t] - ["End of Function" octave-end-of-defun t] - ["Mark Function" octave-mark-defun t] - ["Indent Function" octave-indent-defun t] - ["Insert Function" octave-insert-defun t]) - "-" - (list "Debug" - ["Send Current Line" octave-send-line t] - ["Send Current Block" octave-send-block t] - ["Send Current Function" octave-send-defun t] - ["Send Region" octave-send-region t] - ["Show Process Buffer" octave-show-process-buffer t] - ["Hide Process Buffer" octave-hide-process-buffer t] - ["Kill Process" octave-kill-process t]) - "-" - ["Indent Line" indent-according-to-mode t] - ["Complete Symbol" octave-complete-symbol t] - "-" - ["Toggle Abbrev Mode" abbrev-mode t] - ["Toggle Auto-Fill Mode" auto-fill-mode t] - "-" - ["Submit Bug Report" octave-submit-bug-report t] - "-" - ["Describe Octave Mode" octave-describe-major-mode t] - ["Lookup Octave Index" octave-help t]) - "Menu for Octave mode.") - -(defvar octave-mode-abbrev-table nil - "Abbrev table in use in Octave mode buffers.") -(if octave-mode-abbrev-table - () - (let ((ac abbrevs-changed)) - (define-abbrev-table 'octave-mode-abbrev-table ()) - ;; By default, abbrevs are provided for all reserved words. - (define-abbrev octave-mode-abbrev-table "`a" "all_va_args" nil) - (define-abbrev octave-mode-abbrev-table "`b" "break" nil) - (define-abbrev octave-mode-abbrev-table "`ca" "catch" nil) - (define-abbrev octave-mode-abbrev-table "`c" "continue" nil) - (define-abbrev octave-mode-abbrev-table "`el" "else" nil) - (define-abbrev octave-mode-abbrev-table "`eli" "elseif" nil) - (define-abbrev octave-mode-abbrev-table "`et" "end_try_catch" nil) - (define-abbrev octave-mode-abbrev-table "`eu" "end_unwind_protect" - nil) - (define-abbrev octave-mode-abbrev-table "`ef" "endfor" nil) - (define-abbrev octave-mode-abbrev-table "`efu" "endfunction" nil) - (define-abbrev octave-mode-abbrev-table "`ei" "endif" nil) - (define-abbrev octave-mode-abbrev-table "`ew" "endwhile" nil) - (define-abbrev octave-mode-abbrev-table "`f" "for" nil) - (define-abbrev octave-mode-abbrev-table "`fu" "function" nil) - (define-abbrev octave-mode-abbrev-table "`gl" "global" nil) - (define-abbrev octave-mode-abbrev-table "`gp" "gplot" nil) - (define-abbrev octave-mode-abbrev-table "`gs" "gsplot" nil) - (define-abbrev octave-mode-abbrev-table "`if" "if ()" nil) - (define-abbrev octave-mode-abbrev-table "`rp" "replot" nil) - (define-abbrev octave-mode-abbrev-table "`r" "return" nil) - (define-abbrev octave-mode-abbrev-table "`t" "try" nil) - (define-abbrev octave-mode-abbrev-table "`up" "unwind_protect" nil) - (define-abbrev octave-mode-abbrev-table "`upc" - "unwind_protect_cleanup" nil) - (define-abbrev octave-mode-abbrev-table "`w" "while ()" nil) - (setq abbrevs-changed ac))) - -(defvar octave-comment-char ?# - "The character to start a comment.") -(defvar octave-comment-column 32 - "*Column to indent in-line comments to.") -(defvar octave-comment-start - (concat (make-string 1 octave-comment-char) " ") - "String to insert to start a new in-line Octave comment.") -(defvar octave-block-comment-start - (concat (make-string 2 octave-comment-char) " ") - "String to insert to start a new Octave comment on an empty line.") -(defvar octave-comment-start-skip "\\s<+\\s-*" - "Regexp to match the start of an Octave comment plus everything up to -its body.") -(defvar octave-fill-column 72 - "*Column beyond which automatic line-wrapping should happen.") - -(defvar octave-mode-syntax-table nil - "Syntax table in use in Octave mode buffers.") -(if octave-mode-syntax-table - () - (setq octave-mode-syntax-table (make-syntax-table)) - (modify-syntax-entry ?\r " " octave-mode-syntax-table) - (modify-syntax-entry ?+ "." octave-mode-syntax-table) - (modify-syntax-entry ?- "." octave-mode-syntax-table) - (modify-syntax-entry ?= "." octave-mode-syntax-table) - (modify-syntax-entry ?* "." octave-mode-syntax-table) - (modify-syntax-entry ?/ "." octave-mode-syntax-table) - (modify-syntax-entry ?> "." octave-mode-syntax-table) - (modify-syntax-entry ?< "." octave-mode-syntax-table) - (modify-syntax-entry ?& "." octave-mode-syntax-table) - (modify-syntax-entry ?| "." octave-mode-syntax-table) - (modify-syntax-entry ?! "." octave-mode-syntax-table) - (modify-syntax-entry ?\\ "\\" octave-mode-syntax-table) - (modify-syntax-entry ?\' "." octave-mode-syntax-table) - (modify-syntax-entry ?\` "w" octave-mode-syntax-table) - (modify-syntax-entry ?\" "\"" octave-mode-syntax-table) - (modify-syntax-entry ?. "w" octave-mode-syntax-table) - ;; Not sure if we should do this ... - (modify-syntax-entry ?_ "w" octave-mode-syntax-table) - (modify-syntax-entry ?\% "." octave-mode-syntax-table) - (modify-syntax-entry ?\# "<" octave-mode-syntax-table) - (modify-syntax-entry ?\n ">" octave-mode-syntax-table)) - -(defvar octave-begin-keywords - '("for" "function" "if" "try" "unwind_protect" "while")) -(defvar octave-else-keywords - '("catch" "else" "elseif" "unwind_protect_cleanup")) -(defvar octave-end-keywords - '("end" "endfor" "endfunction" "endif" "end_try_catch" - "end_unwind_protect" "endwhile")) - -(defvar octave-blink-matching-block t - "*Non-nil means show matching begin of block when inserting a space, -newline or `;' after an else or end keyword.") -(defvar octave-block-offset 2 - "*Extra indentation applied to statements in block structures.") -(defvar octave-block-begin-regexp - (concat "\\<\\(" - (mapconcat 'identity octave-begin-keywords "\\|") - "\\)\\>")) -(defvar octave-block-else-regexp - (concat "\\<\\(" - (mapconcat 'identity octave-else-keywords "\\|") - "\\)\\>")) -(defvar octave-block-end-regexp - (concat "\\<\\(" - (mapconcat 'identity octave-end-keywords "\\|") - "\\)\\>")) -(defvar octave-block-begin-or-end-regexp - (concat octave-block-begin-regexp "\\|" octave-block-end-regexp)) -(defvar octave-block-else-or-end-regexp - (concat octave-block-else-regexp "\\|" octave-block-end-regexp)) -(defvar octave-block-match-alist - '(("for" . ("end" "endfor")) - ("function" . ("end" "endfunction")) - ("if" . ("else" "elseif" "end" "endif")) - ("try" . ("catch" "end" "end_try_catch")) - ("unwind_protect" . ("unwind_protect_cleanup" "end" - "end_unwind_protect")) - ("while" . ("end" "endwhile"))) - "Alist with Octave's begin keywords as keys and a list of the matchin -else or end keywords as associated values.") - -(defvar octave-function-header-regexp - (concat "^\\s-*\\<\\(function\\)\\>" - "\\([^=;\n]*=[ \t]*\\|[ \t]*\\)\\(\\w+\\)\\>") - "Regexp to match a function header. The string `function' and its -name are given by the first and third parenthetical grouping.") - -(defvar octave-continuation-offset 4 - "*Extra indentation applied to Octave continuation lines.") -(defvar octave-continuation-regexp - "[^#%\n]*\\(\\\\\\|\\.\\.\\.\\)\\s-*\\(\\s<.*\\)?$") -(defvar octave-continuation-string "\\" - "*Character string used for Octave continuation lines. Normally \\.") - -(defvar octave-reserved-words - (append octave-begin-keywords octave-else-keywords octave-end-keywords - '("all_va_args" "break" "continue" "global" "gplot" "gsplot" - "replot" "return")) - "Reserved words in Octave.") - -(defvar octave-text-functions - '("casesen" "cd" "chdir" "clear" "diary" "dir" "document" "echo" - "edit_history" "format" "gset" "gshow" "help" "history" "hold" - "load" "ls" "more" "run_history" "save" "set" "show" "type" - "which" "who" "whos") - "Octave text functions (these names are also reserved.") - -(defvar octave-variables - '("EDITOR" "EXEC_PATH" "F_DUPFD" "F_GETFD" "F_GETFL" "F_SETFD" - "F_SETFL" "I" "IMAGEPATH" "INFO_FILE" "INFO_PROGRAM" "Inf" "J" - "LOADPATH" "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__" - "__error_text__" "__i__" "__inf__" "__j__" "__nan__" "__pi__" - "__program_invocation_name__" "__program_name__" "__realmax__" - "__realmin__" "__stderr__" "__stdin__" "__stdout__" "ans" "argv" - "automatic_replot" "beep_on_error" "completion_append_char" - "default_return_value" "default_save_format" - "define_all_return_values" "do_fortran_indexing" "e" - "echo_executing_commands" "empty_list_elements_ok" "eps" - "error_text" "gnuplot_binary" "gnuplot_has_multiplot" "history_file" - "history_size" "ignore_function_time_stamp" "implicit_str_to_num_ok" - "inf" "nan" "nargin" "ok_to_lose_imaginary_part" - "output_max_field_width" "output_precision" - "page_output_immediately" "page_screen_output" "pi" - "prefer_column_vectors" "prefer_zero_one_indexing" - "print_answer_id_name" "print_empty_dimensions" - "program_invocation_name" "program_name" "propagate_empty_matrices" - "realmax" "realmin" "resize_on_range_error" - "return_last_computed_value" "save_precision" "saving_history" - "silent_functions" "split_long_rows" "stderr" "stdin" "stdout" - "string_fill_char" "struct_levels_to_print" - "suppress_verbose_help_message" "treat_neg_dim_as_zero" - "warn_assign_as_truth_value" "warn_comma_in_global_decl" - "warn_divide_by_zero" "warn_function_name_clash" - "warn_missing_semicolon" "whitespace_in_literal_matrix") - "Builtin variables in Octave.") - -(defvar octave-completion-alist nil - "Alist of Octave command and variable names that should be included in -completion. Each element looks like (VAR . VAR), where the car and cdr -are the same symbol.") - -(defvar octave-font-lock-keywords - (list - ;; Fontify all builtin keywords. - (cons (concat "\\<\\(" - (mapconcat 'identity octave-reserved-words "\\|") - (mapconcat 'identity octave-text-functions "\\|") - "\\)\\>") - 'font-lock-keyword-face) - ;; Fontify all builtin operators. - (cons "\\(&\\||\\|<=\\|>=\\|==\\|<\\|>\\|!=\\|!\\)" - 'font-lock-reference-face) - ;; Fontify all builtin variables. - (cons (concat "\\<\\(" - (mapconcat 'identity 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 expressions to highlight in Octave mode.") - -(defvar octave-imenu-generic-expression - (list - ;; Functions - (list nil octave-function-header-regexp 3)) - "Imenu expression for Octave mode. See `imenu-generic-expression'.") - -(defvar octave-help-files - '("octave") - "List of info files with documentation for Octave. -Default is '(\"octave\").") - -(defvar octave-help-lookup-alist nil - "Alist of Octave index entries for lookup") - -(defvar octave-help-completion-alist nil - "Alist of Octave index entries for completion. -The entries are of the form (VAR . VAR), where the VAR runs through all -different keys in octave-help-lookup-alist.") - -(defvar octave-help-index-alternatives nil - "List of matches for last octave-help command.") - -(defvar octave-auto-newline nil - "*Non-nil means automatically insert a newline and indent after a -semicolon is typed.") - -(defvar octave-inhibit-startup-message nil - "*If non-nil, the startup message will not be displayed.") - -(defvar octave-mode-hook nil - "*Hook to be run when Octave Mode is started.") - - -;;;###autoload -(defun octave-mode () - "Major mode for editing Octave code. - -This mode makes it easier to write Octave code by helping with -indentation, doing some of the typing for you (with abbrevs-mode) and by -showing keywords, comments, strings, etc. in different faces (with -font-lock mode on terminals that support it). - -Octave itself is a high-level language, primarily intended for numerical -computations. It provides a convenient command line interface for -solving linear and nonlinear problems numerically. Function definitions -can also be stored in files, and it can be used in a batch mode (which -is why you need this mode!). - -The latest released version of Octave is always available via anonymous -ftp from bevo.che.wisc.edu in the directory /pub/octave. Complete -source and binaries for several popular systems are available. - -Type `? or `\\[help-command] to display a list of built-in abbrevs for \ -Octave keywords. - -Keybindings -=========== - -\\{octave-mode-map} - -Variables you can use to customize Octave mode -============================================== - -octave-auto-newline - Non-nil means auto-insert a newline and indent after a semicolon. - Default is nil. - -octave-blink-matching-block - Non-nil means show matching begin of block when inserting a space, - newline or `;' after an else or end keyword. Default is t. - -octave-block-offset - Extra indentation applied to statements in block structures. - Default is 2. - -octave-comment-column - Column to indent right-margin comments to. Default is 32. - -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-fill-column - Column beyond which automatic line-wrapping should happen. Default is - 72. - -octave-help-files - List of info files with documentation for Octave. - Default is '(\"octave\"). - -octave-inhibit-startup-message - If t, no startup message is displayed when Octave mode is called. - Default is nil. - -octave-send-echo-input - Non-nil means always display inferior-octave-buffer after sending a - command. - -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 process. - -octave-send-echo-input - Non-nil means echo input sent to the inferior Octave process. - -Turning on Octave mode runs the hook `octave-mode-hook'. - -To begin using this mode for all .m files that you edit, add the -following lines to your .emacs file: - - (autoload 'octave-mode \"octave\" nil t) - (setq auto-mode-alist - (cons '(\"\\\\.m$\" . octave-mode) auto-mode-alist)) - -To automatically turn on the abbrev, auto-fill and font-lock features, -add the following lines to your .emacs file as well: - - (add-hook 'octave-mode-hook - (lambda () - (abbrev-mode 1) - (auto-fill-mode 1) - (if (eq window-system 'x) - (font-lock-mode 1)))) - -To submit a problem report, enter `\\[octave-submit-bug-report]' from \ -an Octave mode buffer. -This automatically sets up a mail buffer with version information -already added. You just need to add a description of the problem, -including a reproducible test case and send the message." - (interactive) - (kill-all-local-variables) - - (use-local-map octave-mode-map) - (setq major-mode 'octave-mode) - (setq mode-name "Octave") - (setq local-abbrev-table octave-mode-abbrev-table) - (set-syntax-table octave-mode-syntax-table) - - (make-local-variable 'indent-line-function) - (setq indent-line-function 'octave-indent-line) - - (make-local-variable 'comment-start) - (setq comment-start octave-comment-start) - (make-local-variable 'comment-end) - (setq comment-end "") - (make-local-variable 'comment-column) - (setq comment-column octave-comment-column) - (make-local-variable 'comment-start-skip) - (setq comment-start-skip octave-comment-start-skip) - (make-local-variable 'comment-indent-function) - (setq comment-indent-function 'octave-comment-indent) - - (make-local-variable 'parse-sexp-ignore-comments) - (setq parse-sexp-ignore-comments t) - (make-local-variable 'paragraph-start) - (setq paragraph-start (concat "\\s-*$\\|" page-delimiter)) - (make-local-variable 'paragraph-separate) - (setq paragraph-separate paragraph-start) - (make-local-variable 'paragraph-ignore-fill-prefix) - (setq paragraph-ignore-fill-prefix t) - (make-local-variable 'fill-paragraph-function) - (setq fill-paragraph-function 'octave-fill-paragraph) - (make-local-variable 'adaptive-fill-regexp) - (setq adaptive-fill-regexp nil) - (make-local-variable 'fill-column) - (setq fill-column octave-fill-column) - - (make-local-variable 'font-lock-defaults) - (setq font-lock-defaults '(octave-font-lock-keywords nil nil)) - - (make-local-variable 'imenu-generic-expression) - (setq imenu-generic-expression octave-imenu-generic-expression) - - (octave-add-octave-menu) - (octave-initialize-completions) - (run-hooks 'octave-mode-hook) - (if (not octave-inhibit-startup-message) - (message "Octave mode %s. Bugs to %s" - octave-version octave-help-address))) - - -;;; Miscellaneous useful functions -(defun octave-point (position) - "Returns the value of point at certain positions." - (save-excursion - (cond - ((eq position 'bol) (beginning-of-line)) - ((eq position 'eol) (end-of-line)) - ((eq position 'boi) (back-to-indentation)) - ((eq position 'bonl) (forward-line 1)) - ((eq position 'bopl) (forward-line -1)) - (t (error "unknown buffer position requested: %s" position))) - (point))) - -(defsubst octave-in-comment-p () - "Returns t if point is inside an Octave comment, nil otherwise." - (interactive) - (save-excursion - (nth 4 (parse-partial-sexp (octave-point 'bol) (point))))) - -(defsubst octave-in-string-p () - "Returns t if point is inside an Octave string, nil otherwise." - (interactive) - (save-excursion - (nth 3 (parse-partial-sexp (octave-point 'bol) (point))))) - -(defsubst octave-not-in-string-or-comment-p () - "Returns t iff point is not inside an Octave string or comment." - (let ((pps (parse-partial-sexp (octave-point 'bol) (point)))) - (not (or (nth 3 pps) (nth 4 pps))))) - -(defun octave-in-block-p () - "Returns t iff point is inside a block, which is taken to start at the -first letter of the begin keyword and to end after the end keyword." - (let ((pos (point))) - (save-excursion - (condition-case nil - (progn - (skip-syntax-forward "\\w") - (octave-up-block -1) - (octave-forward-block) - t) - (error nil)) - (< pos (point))))) - -(defun octave-in-defun-p () - "Returns t iff point is inside a function declaration, which is taken -to start at the `f' of `function' and to end after the end keyword." - (let ((pos (point))) - (save-excursion - (or (and (looking-at "\\<function\\>") - (octave-not-in-string-or-comment-p)) - (and (octave-beginning-of-defun) - (condition-case nil - (progn - (octave-forward-block) - t) - (error nil)) - (< pos (point))))))) - -;;; Abbrevs -(defun octave-abbrev-start () - "Typing `\\[help-command] or `? lists all abbrevs. -Any other key combination is executed normally." - (interactive) - (let (c) - (insert last-command-char) - (if (or (eq (setq c (read-event)) ??) - (eq c help-char)) - (list-abbrevs) - (setq unread-command-events (list c))))) - - -;;; Comments -(defun octave-comment-region (beg end &optional arg) - "Comment or uncomment each line in the region. See `comment-region'." - (interactive "r\nP") - (let ((comment-start (char-to-string octave-comment-char))) - (comment-region beg end arg))) - -(defun octave-uncomment-region (beg end &optional arg) - "Uncomment each line in the region." - (interactive "r\nP") - (or arg (setq arg 1)) - (octave-comment-region beg end (- arg))) - - -;;; Indentation -(defun calculate-octave-indent () - "Return appropriate indentation for current line as Octave code. -Returns an integer (the column to indent to) unless the line is a -comment line with fixed goal golumn. In that case, returns a list whose -car is the column to indent to, and whose cdr is the current indentation -level." - (let ((is-continuation-line - (save-excursion - (if (zerop (octave-previous-code-line)) - (looking-at octave-continuation-regexp)))) - (icol 0)) - (save-excursion - (beginning-of-line) - ;; If we can move backward out one level of parentheses, take 1 - ;; plus the indentation of that parenthesis. Otherwise, go back - ;; to the beginning of the previous code line, and compute the - ;; offset this line gives. - (if (condition-case nil - (progn - (up-list -1) - t) - (error nil)) - (setq icol (+ 1 (current-column))) - (if (zerop (octave-previous-code-line)) - (progn - (octave-beginning-of-line) - (back-to-indentation) - (setq icol (current-column)) - (let ((bot (point)) - (eol (octave-point 'eol))) - (while (< (point) eol) - (if (octave-not-in-string-or-comment-p) - (cond - ((looking-at octave-block-begin-regexp) - (setq icol (+ icol octave-block-offset))) - ((looking-at octave-block-else-regexp) - (if (= bot (point)) - (setq icol (+ icol octave-block-offset)))) - ((looking-at octave-block-end-regexp) - (if (not (= bot (point))) - (setq icol (- icol octave-block-offset)))))) - (forward-char))) - (if is-continuation-line - (setq icol (+ icol octave-continuation-offset))))))) - (save-excursion - (back-to-indentation) - (cond - ((and (or (looking-at octave-block-else-regexp) - (looking-at octave-block-end-regexp)) - (octave-not-in-string-or-comment-p)) - (setq icol (- icol octave-block-offset))) - ((looking-at "\\s<\\s<\\s<\\S<") - (setq icol (list 0 icol))) - ((looking-at "\\s<\\S<") - (setq icol (list octave-comment-column icol))))) - icol)) - -(defun octave-comment-indent () - (if (looking-at "\\s<\\s<\\s<") - 0 - (if (looking-at "\\s<\\s<") - (calculate-octave-indent) - (skip-syntax-backward "\\s-") - (max (if (bolp) 0 (+ (current-column))) - comment-column)))) - -(defun octave-indent-for-comment () - "If there is no comment already on this line, create a code-level -comment (started by two comment characters) if the line is empty, or an -in-line comment (started by one comment character) otherwise. -Point is left after the start of the comment which is properly aligned." - (interactive) - (indent-for-comment) - (indent-according-to-mode)) - -(defun octave-indent-line (&optional arg) - "Indent current line as Octave code. -With optional ARG, use this as offset unless this line is a comment with -fixed goal column." - (interactive) - (or arg (setq arg 0)) - (let ((icol (calculate-octave-indent)) - (relpos (- (current-column) (current-indentation)))) - (if (listp icol) - (setq icol (car icol)) - (setq icol (+ icol arg))) - (if (< icol 0) - (error "Unmatched end keyword") - (indent-line-to icol) - (if (> relpos 0) - (move-to-column (+ icol relpos)))))) - -(defun octave-indent-new-comment-line () - "Break line at point and indent, continuing comment if within one and -signalling an error if within a string. Otherwise (if within code), -insert `octave-continuation-string' before breaking the line." - (interactive) - (delete-horizontal-space) - (cond - ((octave-in-comment-p) - (indent-new-comment-line)) - ((octave-in-string-p) - (error "Cannot split a code line inside a string")) - (t - (insert (concat " " octave-continuation-string)) - (octave-reindent-then-newline-and-indent)))) - -(defun octave-indent-defun () - "Properly indents the Octave function which contains point." - (interactive) - (save-excursion - (octave-mark-defun) - (message "Indenting function...") - (indent-region (point) (mark) nil)) - (message "Indenting function...done.")) - - -;;; Motion -(defun octave-next-code-line (&optional arg) - "Move ARG lines of Octave code forward (backward if ARG is negative), -skipping 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), -skipping 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 () - "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 () - "If on an empty or comment line, go to the end of that line. -Otherwise, move forward to the end of the first Octave code line which -does not end in `...' or `\\' or is inside an open parenthesis list." - (interactive) - (end-of-line) - (if (save-excursion - (beginning-of-line) - (looking-at "\\s-*\\($\\|\\s<\\)")) - () - (while (or (condition-case nil - (progn - (up-list 1) - (end-of-line) - t) - (error nil)) - (and (save-excursion - (beginning-of-line) - (or (looking-at "\\s-*\\($\\|\\s<\\)") - (looking-at octave-continuation-regexp))) - (zerop (forward-line 1))))) - (end-of-line))) - -(defun octave-scan-blocks (from count depth) - "Scan from character number FROM by COUNT begin-end blocks. -Returns the character number of the position thus found. - -If DEPTH is nonzero, block depth begins counting from that value. -Only places where the depth in blocks becomes zero are candidates for -stopping; COUNT such places are counted. - -If the beginning or end of the buffer is reached and the depth is wrong, -an error is signaled." - (let ((min-depth (if (> depth 0) 0 depth)) - (inc (if (> count 0) 1 -1))) - (save-excursion - (while (/= count 0) - (catch 'foo - (while (or (re-search-forward - octave-block-begin-or-end-regexp nil 'move inc) - (if (/= depth 0) - (error "Unbalanced block"))) - (if (octave-not-in-string-or-comment-p) - (progn - (cond - ((match-end 1) - (setq depth (+ depth inc))) - ((match-end 2) - (setq depth (- depth inc)))) - (if (< depth min-depth) - (error "Containing expression ends prematurely")) - (if (= depth 0) - (throw 'foo nil)))))) - (setq count (- count inc))) - (point)))) - -(defun octave-forward-block (&optional arg) - "Move forward across one balanced begin-end block of Octave code. -With argument, do it that many times. -Negative arg -N means move backward across N blocks." - (interactive "p") - (or arg (setq arg 1)) - (goto-char (or (octave-scan-blocks (point) arg 0) (buffer-end arg)))) - -(defun octave-backward-block (&optional arg) - "Move backward across one balanced begin-end block of Octave code. -With argument, do it that many times. -Negative arg -N means move forward across N blocks." - (interactive "p") - (or arg (setq arg 1)) - (octave-forward-block (- arg))) - -(defun octave-down-block (arg) - "Move forward down one begin-end block level of Octave code. -With argument, do this that many times. -A negative argument means move backward but still go down a level. -In Lisp programs, an argument is required." - (interactive "p") - (let ((inc (if (> arg 0) 1 -1))) - (while (/= arg 0) - (goto-char (or (octave-scan-blocks (point) inc -1) - (buffer-end arg))) - (setq arg (- arg inc))))) - -(defun octave-backward-up-block (arg) - "Move backward out of one begin-end block level of Octave code. -With argument, do this that many times. -A negative argument means move forward but still to a less deep spot. -In Lisp programs, an argument is required." - (interactive "p") - (octave-up-block (- arg))) - -(defun octave-up-block (arg) - "Move forward out of one begin-end block level of Octave code. -With argument, do this that many times. -A negative argument means move backward but still to a less deep spot. -In Lisp programs, an argument is required." - (interactive "p") - (let ((inc (if (> arg 0) 1 -1))) - (while (/= arg 0) - (goto-char (or (octave-scan-blocks (point) inc 1) - (buffer-end arg))) - (setq arg (- arg inc))))) - -(defun octave-mark-block () - "Put point at the beginning of this block, mark at the end. The block -marked is the one that contains point or follows point." - (interactive) - (let ((pos (point))) - (if (or (and (octave-in-block-p) - (skip-syntax-forward "\\w")) - (condition-case nil - (progn - (octave-down-block 1) - (octave-in-block-p)) - (error nil))) - (progn - (octave-up-block -1) - (push-mark (point)) - (octave-forward-block) - (exchange-point-and-mark)) - (goto-char pos) - (message "No block to mark found")))) - -(defun octave-close-block () - "Close the current block on a separate line. An error is signaled if -no block to close is found." - (interactive) - (let (bb-keyword) - (condition-case nil - (progn - (save-excursion - (octave-backward-up-block 1) - (setq bb-keyword (buffer-substring-no-properties - (match-beginning 1) (match-end 1)))) - (if (save-excursion - (beginning-of-line) - (looking-at "^\\s-*$")) - (indent-according-to-mode) - (octave-reindent-then-newline-and-indent)) - (insert (car (reverse - (assoc bb-keyword - octave-block-match-alist)))) - (octave-reindent-then-newline-and-indent) - t) - (error (message "No block to close found"))))) - -(defun octave-blink-matching-block-open () - "If point is right after an else or end type block keyword, move -cursor momentarily to the corresponding begin keyword. -Signal an error if the keywords are incompatible." - (interactive) - (let (bb-keyword bb-arg eb-keyword pos eol) - (if (and (octave-not-in-string-or-comment-p) - (looking-at "\\>") - (save-excursion - (skip-syntax-backward "\\w") - (looking-at octave-block-else-or-end-regexp))) - (save-excursion - (cond - ((match-end 1) - (setq eb-keyword - (buffer-substring-no-properties - (match-beginning 1) (match-end 1))) - (octave-backward-up-block 1)) - ((match-end 2) - (setq eb-keyword - (buffer-substring-no-properties - (match-beginning 2) (match-end 2))) - (octave-backward-block))) - (setq pos (match-end 0) - bb-keyword - (buffer-substring-no-properties - (match-beginning 0) pos) - pos (+ pos 1) - eol (octave-point 'eol) - bb-arg - (save-excursion - (save-restriction - (goto-char pos) - (while (and (skip-syntax-forward "^\\s<" eol) - (octave-in-string-p) - (not (forward-char 1)))) - (skip-syntax-backward "\\s-") - (buffer-substring-no-properties pos (point))))) - (if (member eb-keyword - (cdr (assoc bb-keyword octave-block-match-alist))) - (progn - (message "Matches `%s %s'" bb-keyword bb-arg) - (if (pos-visible-in-window-p) - (sit-for blink-matching-delay))) - (error "Block keywords `%s' and `%s' do not match" - bb-keyword eb-keyword)))))) - -(defun octave-beginning-of-defun (&optional arg) - "Move backward to the beginning of a function. With argument, do it -that many times. Negative arg -N means move forward to Nth following -beginning of a function. -Returns t unless search stops at the beginning or end of the buffer." - (interactive "p") - (let* ((arg (or arg 1)) - (inc (if (> arg 0) 1 -1)) - (found)) - (and (not (eobp)) - (not (and (> arg 0) (looking-at "\\<function\\>"))) - (skip-syntax-forward "\\w")) - (while (and (/= arg 0) - (setq found - (re-search-backward "\\<function\\>" nil 'move inc))) - (if (octave-not-in-string-or-comment-p) - (setq arg (- arg inc)))) - (if found - (progn - (and (< inc 0) (goto-char (match-beginning 0))) - t)))) - -(defun octave-end-of-defun (&optional arg) - "Move forward to the end of a function. With positive ARG, do it that -many times. Negative argument -N means move back to Nth preceding end -of a function. - -An end of a function occurs right after the end keyword matching the -`function' keyword that starts the function." - (interactive "p") - (or arg (setq arg 1)) - (and (< arg 0) (skip-syntax-backward "\\w")) - (and (> arg 0) (skip-syntax-forward "\\w")) - (if (octave-in-defun-p) - (setq arg (- arg 1))) - (if (= arg 0) (setq arg -1)) - (if (octave-beginning-of-defun (- arg)) - (octave-forward-block))) - -(defun octave-mark-defun () - "Put point at the beginning of this function, mark at its end. The -function marked is the one containing point or following point." - (interactive) - (let ((pos (point))) - (if (or (octave-in-defun-p) - (and (octave-beginning-of-defun -1) - (octave-in-defun-p))) - (progn - (skip-syntax-forward "\\w") - (octave-beginning-of-defun) - (push-mark (point)) - (octave-end-of-defun) - (exchange-point-and-mark)) - (goto-char pos) - (message "No function to mark found")))) - - -;;; Filling -(defun octave-auto-fill-mode (arg) - "Toggle octave-auto-fill mode. -With ARG, turn `octave-auto-fill' mode on iff ARG is positive. -In `octave-auto-fill' mode, inserting a space at a column beyond -`octave-fill-column' automatically breaks the line at a previous space, -inserting `octave-continuation-string' at the end of code lines." - (interactive "P") - (prog1 (setq auto-fill-function - (if (if (null arg) - (not auto-fill-function) - (> (prefix-numeric-value arg) 0)) - 'octave-auto-fill - nil)) - (force-mode-line-update))) - -(defadvice auto-fill-mode (around octave-auto-fill activate) - "If the current buffer is in Octave mode, toggle Octave-Auto-Fill mode. -In this mode, inserting a space at a column beyond `octave-fill-column' -automatically breaks the line at a previous space, inserting -`octave-continuation-string' at the end of code lines." - (if (eq major-mode 'octave-mode) - (octave-auto-fill-mode arg) - ad-do-it)) - -(defun octave-auto-fill () - "Function to perform auto-fill in Octave mode." - (if (> (current-column) (current-fill-column)) - (if (octave-in-comment-p) - (do-auto-fill) - ;; Try to remove continuation regexps before point before - ;; inserting another one. - ;; Need to think more about this ... -;; (let ((bol (octave-point 'bol))) -;; (while (re-search-backward "\\\\\\|\\.\\.\\." bol t) -;; (if (and (octave-not-in-string-or-comment-p) -;; (> (point) bol)) -;; (progn -;; (delete-region (match-beginning 0) (match-end 0)) -;; (fixup-whitespace))))) - (if (> (current-column) (current-fill-column)) - (let ((fill-column (- (current-fill-column) - (length octave-continuation-string)))) - (do-auto-fill) - (save-excursion - (forward-line -1) - (end-of-line) - (insert (concat " " octave-continuation-string))) - (indent-according-to-mode)))))) - -(defun octave-fill-paragraph (&optional arg) - "Fills paragraph, handling Octave comments." - (interactive "P") - (save-excursion - (let ((end (progn (forward-paragraph) (point))) - (beg (progn - (forward-paragraph -1) - (skip-chars-forward " \t\n") - (beginning-of-line) - (point))) - (cfc (current-fill-column)) - (ind (calculate-octave-indent)) - comment-prefix) - (save-restriction - (goto-char beg) - (narrow-to-region beg end) - (if (listp ind) (setq ind (nth 1 ind))) - (while (not (eobp)) - (condition-case nil - (octave-indent-line ind) - (error nil)) - (if (and (> ind 0) - (not - (save-excursion - (beginning-of-line) - (looking-at "^\\s-*\\($\\|\\s<+\\)")))) - (setq ind 0)) - (move-to-column cfc) - ;; First check whether we need to combine non-empty comment lines - (if (and (< (current-column) cfc) - (octave-in-comment-p) - (not (save-excursion - (beginning-of-line) - (looking-at "^\\s-*\\s<+\\s-*$")))) - ;; This is a nonempty comment line which does not extend - ;; past the fill column. If it is followed by an nonempty - ;; comment line with the same comment prefix, try to - ;; combine them, and repeat this until either we reach the - ;; fill-column or there is nothing more to combine. - (progn - ;; Get the comment prefix - (save-excursion - (beginning-of-line) - (while (and (re-search-forward "\\s<+") - (not (octave-in-comment-p)))) - (setq comment-prefix (match-string 0))) - ;; And keep combining ... - (while (and (< (current-column) cfc) - (save-excursion - (forward-line 1) - (and (looking-at - (concat "^\\s-*" - comment-prefix - "\\S<")) - (not (looking-at - (concat "^\\s-*" - comment-prefix - "\\s-*$")))))) - (delete-char 1) - (re-search-forward comment-prefix) - (delete-region (match-beginning 0) (match-end 0)) - (fixup-whitespace) - (move-to-column cfc)))) - (skip-chars-forward "^ \t\n") - (delete-horizontal-space) - (if (or (< (current-column) cfc) - (and (= (current-column) cfc) (eolp))) - (forward-line 1) - (if (not (eolp)) (insert " ")) - (octave-auto-fill)))) - t))) - - -;;; Completions -(defun octave-initialize-completions () - "Create an alist for completions." - (if octave-completion-alist - () - (setq octave-completion-alist - (mapcar '(lambda (var) (cons var var)) - (append octave-reserved-words - octave-text-functions - octave-variables))))) - -(defun octave-complete-symbol () - "Perform completion on Octave symbol preceding point, comparing that -symbol against Octave's reserved words and builtin variables." - ;; This code taken from lisp-complete-symbol - (interactive) - (let* ((end (point)) - (beg (save-excursion (backward-sexp 1) (point))) - (string (buffer-substring-no-properties beg end)) - (completion (try-completion string octave-completion-alist))) - (cond ((eq completion t)) ; ??? - ((null completion) - (message "Can't find completion for \"%s\" pattern") - (ding)) - ((not (string= string completion)) - (delete-region beg end) - (insert completion)) - (t - (let ((list (all-completions string octave-completion-alist)) - (conf (current-window-configuration))) - ;; Taken from comint.el - (message "Making completion list...") - (with-output-to-temp-buffer "*Completions*" - (display-completion-list list)) - (message "Hit space to flush") - (let (key first) - (if (save-excursion - (set-buffer (get-buffer "*Completions*")) - (setq key (read-key-sequence nil) - first (aref key 0)) - (and (consp first) (consp (event-start first)) - (eq (window-buffer (posn-window (event-start - first))) - (get-buffer "*Completions*")) - (eq (key-binding key) 'mouse-choose-completion))) - (progn - (mouse-choose-completion first) - (set-window-configuration conf)) - (if (eq first ?\ ) - (set-window-configuration conf) - (setq unread-command-events - (listify-key-sequence key)))))))))) - - -;;; Electric characters && friends -(defun octave-reindent-then-newline-and-indent () - "Reindent current line, insert newline, then indent the new line. -If Abbrev mode is on, expand abbrevs first." - (interactive) - (if abbrev-mode (expand-abbrev)) - (if octave-blink-matching-block - (octave-blink-matching-block-open)) - (save-excursion - (delete-region (point) (progn (skip-chars-backward " \t") (point))) - (indent-according-to-mode)) - (insert "\n") - (indent-according-to-mode)) - -(defun octave-electric-semi () - "Insert `;' character and reindent the line. Insert a newline if -`octave-auto-newline' is non-nil." - (interactive) - (if (not (octave-not-in-string-or-comment-p)) - (insert ";") - (if abbrev-mode (expand-abbrev)) - (if octave-blink-matching-block - (octave-blink-matching-block-open)) - (indent-according-to-mode) - (insert ";") - (if octave-auto-newline - (newline-and-indent)))) - -(defun octave-electric-space () - "Maybe expand abbrevs and blink matching block open keywords, and -insert a space." - (interactive) - (setq last-command-char ? ) - (if (not (octave-not-in-string-or-comment-p)) - (progn - (indent-according-to-mode) - (self-insert-command 1)) - (if abbrev-mode (expand-abbrev)) - (if octave-blink-matching-block - (octave-blink-matching-block-open)) - (if (save-excursion - (skip-syntax-backward "\\s-") - (not (bolp))) - (indent-according-to-mode)) - (self-insert-command 1))) - -(defun octave-insert-defun (name args vals) - "Insert a function skeleton, prompting for the function's name, -arguments and return values (to be entered without parens)." - (interactive - (list - (read-from-minibuffer "Function name: " - (substring (buffer-name) 0 -2)) - (read-from-minibuffer "Arguments: ") - (read-from-minibuffer "Return values: "))) - (let ((string (format "%s %s (%s)" - (cond - ((string-equal vals "") - vals) - ((string-match "[ ,]" vals) - (concat " [" vals "] =")) - (t - (concat " " vals " ="))) - name - args)) - (prefix octave-block-comment-start)) - (if (not (bobp)) (newline)) - (insert "function" string) - (indent-according-to-mode) - (newline 2) - (insert prefix "usage: " string) - (reindent-then-newline-and-indent) - (insert prefix) - (reindent-then-newline-and-indent) - (insert prefix) - (indent-according-to-mode) - (save-excursion - (newline 2) - (insert "endfunction") - (indent-according-to-mode)))) - - -;;; Menu -(defun octave-add-octave-menu () - "Adds the `Octave' menu to the menu bar in Octave mode." - (require 'easymenu) - (easy-menu-define octave-mode-menu-map octave-mode-map - "Menu keymap for Octave mode." octave-mode-menu) - (easy-menu-add octave-mode-menu-map octave-mode-map)) - - -;;; Help -(require 'info) - -(defun octave-describe-major-mode () - "Describe the current major mode." - (interactive) - (describe-function major-mode)) - -(defun octave-help (key) - "Look up KEY in the function, operator and variable indices of the -info files with documentation for Octave. -If KEY is not a string, prompt for it with completion." - (interactive - (list - (completing-read (format "Describe Octave entity: ") - (octave-help-get-completion-alist) - nil t))) - (setq octave-help-index-alternatives nil) - (if (get-buffer "*info*") - (set-buffer "*info*")) - (if (zerop (length key)) - (Info-find-node (car octave-help-files) "Top") - (let ((alist (copy-alist (octave-help-get-lookup-alist))) - entry matches) - (while (setq entry (car alist)) - (if (string-match key (car entry)) - (add-to-list 'matches entry)) - (setq alist (cdr alist))) -;; (while (setq entry (assoc key alist)) -;; (add-to-list 'matches entry) -;; (delete entry alist)) - (if matches - (progn - (setq octave-help-index-alternatives matches - Info-index-alternatives matches) - (Info-index-next 0)))))) - -;; The following three advices are really ugly. The problem is that -;; Info-index-next can only cycle through matches found in ONE info -;; file, because whenever it changes the info file, it does so using -;; Info-find-node which resets Info-index-alternatives to nil. Hence, -;; we save the current value before and restore it after calling this -;; function when necessary. - -(defadvice Info-find-node (before octave-help activate) - (and Info-index-alternatives - octave-help-index-alternatives - (setq octave-help-index-alternatives Info-index-alternatives))) - -(defadvice Info-find-node (after octave-help activate) - (and octave-help-index-alternatives - (not Info-index-alternatives) - (setq Info-index-alternatives octave-help-index-alternatives))) - -(defadvice Info-exit (before octave-help activate) - (setq octave-help-index-alternatives nil)) - -(defun octave-help-get-lookup-alist () - "Build the index lookup alist from all info files with documentation -for Octave." - (if octave-help-lookup-alist - () - (message "Building help lookup alist...") - (let ((files octave-help-files) file key node) - (save-window-excursion - (while files - (setq file (car files)) - (Info-goto-node (concat "(" file ")")) - (condition-case nil - (progn - (Info-index "") - (while - (progn - (while (re-search-forward - "^\\* \\([^(:]+\\)[^:]*: *\\(.+\\)\\.$" - nil t) - (setq key (match-string 1) - node (concat "(" file ")" (match-string 2))) - (and (string-match "\\(.*\\>\\) *$" key) - (setq key (replace-match "\\1" t nil key))) - (add-to-list 'octave-help-lookup-alist - (list key - node - (concat (concat "(" file ")") - Info-current-node) - 0))) - (and (setq node (Info-extract-pointer "next" t)) - (string-match - (concat "\\(Function\\|Operator\\|Variable\\) " - "\\<Index\\>") - node))) - (Info-goto-node node))) - (error nil)) - (setq files (cdr files))))) - (message "Building help lookup alist...done")) - octave-help-lookup-alist) - -(defun octave-help-get-completion-alist () - "Build the index completion alist from all info files with -documentation for Octave." - (if octave-help-completion-alist - () - (message "Building help completion alist...") - (let ((alist (octave-help-get-lookup-alist)) entry) - (while alist - (setq entry (car alist)) - (add-to-list 'octave-help-completion-alist - (cons (car entry) (car entry))) - (setq alist (cdr alist)))) - (message "Building help completion alist...done")) - octave-help-completion-alist) - - -;;; Inferior Octave mode -(require 'comint) - -(defvar inferior-octave-buffer "*Inferior Octave*" - "*Name of buffer for running an inferior Octave process") - -(defvar inferior-octave-process nil) - -(defvar inferior-octave-program "octave") - -(defvar inferior-octave-prompt "\\(^octave\\(:[0-9]+\\)?\\|^\\)>+ " - "*Regexp to match prompts for the inferior Octave process") - -(defvar inferior-octave-mode-map nil) -(if inferior-octave-mode-map - () - (let ((map (copy-keymap comint-mode-map))) - ;; (define-key map "\t" 'inferior-octave-complete) - (define-key map "\t" 'comint-dynamic-complete) - (define-key map "\M-?" 'comint-dynamic-list-filename-completions) - (setq inferior-octave-mode-map map))) - -(defvar inferior-octave-receive-in-progress nil) -(defvar inferior-octave-output-list nil) -(defvar inferior-octave-output-string nil) - -(defvar inferior-octave-startup-file nil - "*Name of a file to send the contents of to the inferior Octave process -on startup.") - -(defvar inferior-octave-startup-args nil - "*A list of command line arguments to be passed to the inferior Octave -process on startup. -For example, for suppressing the startup message and using `traditional' -mode, set this to '(\"-q\" \"--traditional\").") - -(defvar inferior-octave-font-lock-keywords - (list - (cons inferior-octave-prompt 'font-lock-type-face)) - "Additional expressions to highlight in Inferior Octave mode.") - -(defvar inferior-octave-dynamic-complete-functions - '(inferior-octave-complete comint-dynamic-complete-filename) - "List of functions called to perform completion. -This variable is used to initialise `comint-dynamic-complete-functions' -in the Inferior Octave buffer.") - -(defvar inferior-octave-mode-hook nil - "*Hook to be run when Inferior Octave mode is started.") - -(defun inferior-octave-mode () - "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 first runs the hook `comint-mode-hook'. Then, it -sends a few initialization commands to the Octave process. 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\". Executing these commands will NOT produce -any visible output. - -Finally. `inferior-octave-mode-hook' is run." - (interactive) - (comint-mode) - (setq comint-prompt-regexp inferior-octave-prompt - major-mode 'inferior-octave-mode - mode-name "Inferior Octave" - mode-line-process '(":%s")) - (use-local-map inferior-octave-mode-map) - (make-local-variable 'font-lock-defaults) - (make-local-variable 'inferior-octave-output-list) - (make-local-variable 'inferior-octave-receive-in-progress) - (setq comint-input-ring-file-name - (or (getenv "OCTAVE_HISTFILE") "~/.octave_hist") - comint-input-ring-size - (or (getenv "OCTAVE_HISTSIZE") 1024) - comint-dynamic-complete-functions - inferior-octave-dynamic-complete-functions - font-lock-defaults - '(inferior-octave-font-lock-keywords nil nil) - inferior-octave-process - (get-buffer-process inferior-octave-buffer) - inferior-octave-output-list nil - inferior-octave-receive-in-progress t - comint-input-filter-functions '(inferior-octave-directory-tracker)) - (set-process-filter inferior-octave-process - 'inferior-octave-slurp-output) - (while inferior-octave-receive-in-progress - (accept-process-output inferior-octave-process)) - (if (not (bobp)) - (insert-before-markers "\n")) - (if inferior-octave-output-list - (insert-before-markers - (concat (mapconcat 'identity - inferior-octave-output-list "\n") - "\n"))) - ;; Inferior Octave startup commands - (let* ((commands '("page_screen_output = 0;\n")) - (program (file-name-nondirectory inferior-octave-program)) - (startfile (or inferior-octave-startup-file - (concat "~/.emacs_" program)))) - (if (not (string-equal inferior-octave-output-string ">> ")) - (add-to-list 'commands "PS1=\"\\\\s> \";\n")) - (if (file-exists-p startfile) - (add-to-list 'commands - (format "source (\"%s\");\n" startfile))) - (inferior-octave-send-list-slurp-output commands)) - (set-process-filter inferior-octave-process - 'inferior-octave-output-filter) - (run-hooks 'inferior-octave-mode-hook) - (insert-before-markers inferior-octave-output-string) - (comint-read-input-ring t)) - -;;;###autoload -(defun inferior-octave (&optional arg) - "Run an inferior Octave process, with I/O through the buffer specified -by `inferior-octave-buffer'. The 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 Octave process on startup." - (interactive "P") - (if (comint-check-proc inferior-octave-buffer) - () - (save-excursion - (set-buffer - (apply 'make-comint - (substring inferior-octave-buffer 1 -1) - (file-name-nondirectory inferior-octave-program) - nil - inferior-octave-startup-args)) - (inferior-octave-mode))) - (if (not arg) - (pop-to-buffer inferior-octave-buffer))) - -;;;###autoload -(defalias 'run-octave 'inferior-octave) - -(defun inferior-octave-complete () - "Perform completion on the Octave command preceding point. -This is implemented using the Octave command `completion_matches' which -is NOT available with older versions of Octave." - (interactive) - (let* ((end (point)) - (command (save-excursion - (skip-syntax-backward "\\w\\s_") - (and (looking-at comint-prompt-regexp) - (goto-char (match-end 0))) - (buffer-substring-no-properties (point) end))) - (proc (get-buffer-process inferior-octave-buffer)) - (filter (process-filter proc))) - (if (string-equal command "") - (message "Cannot complete an empty string") - (setq inferior-octave-output-list nil - inferior-octave-receive-in-progress t) - (set-process-filter proc 'inferior-octave-slurp-output) - (unwind-protect - (progn - (comint-send-string proc (concat "completion_matches (\"" - command "\");\n")) - (while inferior-octave-receive-in-progress - (accept-process-output proc))) - (set-process-filter proc filter)) - (and inferior-octave-output-list - (string-match "^\a*error:" - (car inferior-octave-output-list)) - (error (concat "This version of Octave does not support the " - "`completion_matches' command"))) - ;; Sort the list - (setq inferior-octave-output-list - (sort inferior-octave-output-list 'string-lessp)) - ;; Remove duplicates - (let* ((x inferior-octave-output-list) - (y (cdr x))) - (while y - (if (string-equal (car x) (car y)) - (setcdr x (setq y (cdr y))) - (setq x y - y (cdr y))))) - ;; And let comint handle the rest - (comint-dynamic-simple-complete command - inferior-octave-output-list)))) - -(defun octave-strip-ctrl-g (string) - "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) - "Ring Emacs bell if process output starts with an ASCII bell, and pass -the rest to comint-output-filter." - (comint-output-filter proc (octave-strip-ctrl-g string))) - -(defun inferior-octave-slurp-output (proc string) - "Save all output from the inferior Octave process between newlines into -inferior-octave-output-list, the rest to inferior-octave-output-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-output-string string - inferior-octave-receive-in-progress nil))) - -(defun inferior-octave-send-list-slurp-output (list) - "Send the elements of LIST (which have to be strings) to the Octave -process, passing all output to the filter inferior-octave-slurp-output." - (let* ((proc (get-buffer-process inferior-octave-buffer)) - (filter (process-filter proc)) - string) - (set-process-filter proc 'inferior-octave-slurp-output) - (setq inferior-octave-output-list nil) - (unwind-protect - (while (setq string (car list)) - (setq 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 Octave. -Use M-x inferior-octave-resync-dirs to resync if Emacs gets confused." - (if (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." - (interactive) - (inferior-octave-send-list-slurp-output '("pwd\n")) - (cd (car inferior-octave-output-list))) - - -;;; Communication with the inferior Octave process -(defvar octave-send-show-buffer t - "*Non-nil means always display inferior-octave-buffer after sending a -command.") -(defvar octave-send-line-auto-forward t - "*Non-nil means always go to the next line of Octave code after -sending a line to the inferior process.") -(defvar octave-send-echo-input t - "*Non-nil means echo input sent to the inferior Octave process.") - -(defun octave-kill-process () - "Kill inferior Octave process and its buffer." - (interactive) - (if inferior-octave-process - (comint-send-string inferior-octave-process "quit;\n")) - (if inferior-octave-buffer - (kill-buffer inferior-octave-buffer))) - -(defun octave-show-process-buffer () - "Make sure that `inferior-octave-buffer' is displayed." - (interactive) - (display-buffer inferior-octave-buffer)) - -(defun octave-hide-process-buffer () - "Delete all windows that display `inferior-octave-buffer'." - (interactive) - (delete-windows-on inferior-octave-buffer)) - -(defun octave-send-region (beg end) - "Send the region to the inferior Octave process." - (interactive "r") - (if (not (comint-check-proc inferior-octave-buffer)) - (inferior-octave t)) - (let ((proc inferior-octave-process) - (string (buffer-substring beg end)) - line) - (save-excursion - (set-buffer inferior-octave-buffer) - (setq inferior-octave-output-list nil) - (while (not (string-equal string "")) - (if (string-match "\n" string) - (setq line (substring string 0 (match-beginning 0)) - string (substring string (match-end 0))) - (setq line string string "")) - (setq inferior-octave-receive-in-progress t) - (inferior-octave-send-list-slurp-output - (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 '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 the current block to the inferior Octave process." - (interactive) - (save-excursion - (octave-mark-block) - (octave-send-region (point) (mark)))) - -(defun octave-send-defun () - "Send the current function to the inferior Octave process." - (interactive) - (save-excursion - (octave-mark-defun) - (octave-send-region (point) (mark)))) - -(defun octave-send-line (&optional arg) - "Send the current 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; print value into current buffer." - (interactive) - (let ((standard-output (current-buffer)) - (print-escape-newlines nil) - (opoint (point))) - (terpri) - (prin1 - (save-excursion - (forward-sexp -1) - (inferior-octave-send-list-slurp-output - (list (concat (buffer-substring-no-properties (point) opoint) - "\n"))) - (mapconcat 'identity inferior-octave-output-list "\n"))) - (terpri))) - - -;;; Bug reporting -(defun octave-submit-bug-report () - "Submit a bug report on Octave mode via mail." - (interactive) - (require 'reporter) - (and - (y-or-n-p "Do you want to submit a bug report? ") - (reporter-submit-bug-report - octave-help-address - (concat "Octave version " octave-version) - (list - 'octave-auto-newline - 'octave-blink-matching-block - 'octave-block-offset - 'octave-comment-char - 'octave-comment-column - 'octave-continuation-offset - 'octave-continuation-string - 'octave-fill-column - 'octave-inhibit-startup-message - 'octave-help-files - 'octave-send-echo-input - 'octave-send-line-auto-forward - 'octave-send-show-buffer)))) - -;;; provide ourself - -(provide 'octave) - -;; Compile this file when saving it: - -;;; Local Variables: -;;; after-save-hook: ((lambda () (byte-compile-file buffer-file-name))) -;;; End: