Merge from emacs--rel--22
[bpt/emacs.git] / lisp / progmodes / octave-inf.el
index 12b2955..cfb70b5 100644 (file)
@@ -1,18 +1,19 @@
-;; octave-inf.el --- running Octave as an inferior Emacs process
+;;; octave-inf.el --- running Octave as an inferior Emacs process
 
-;;; Copyright (C) 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+;; Free Software Foundation, Inc.
 
-;; Author: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at>
+;; Author: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
 ;; Author: John Eaton <jwe@bevo.che.wisc.edu>
-;; Maintainer: Kurt Hornik <Kurt.Hornik@ci.tuwien.ac.at>
+;; Maintainer: Kurt Hornik <Kurt.Hornik@wu-wien.ac.at>
 ;; Keywords: languages
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
 ;; 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.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
 
 ;;; Code:
 
 (require 'octave-mod)
 (require 'comint)
 
-(defvar inferior-octave-program "octave"
-  "*Program invoked by `inferior-octave'.")
+(defgroup octave-inferior nil
+  "Running Octave as an inferior Emacs process."
+  :group 'octave)
+
+(defcustom inferior-octave-program "octave"
+  "Program invoked by `inferior-octave'."
+  :type 'string
+  :group 'octave-inferior)
 
-(defvar inferior-octave-prompt "\\(^octave\\(:[0-9]+\\)?\\|^\\)>+ "
-  "*Regexp to match prompts for the inferior Octave process.")
+(defcustom inferior-octave-prompt
+  "\\(^octave\\(\\|.bin\\|.exe\\)\\(-[.0-9]+\\)?\\(:[0-9]+\\)?\\|^debug\\|^\\)>+ "
+  "Regexp to match prompts for the inferior Octave process."
+  :type 'regexp
+  :group 'octave-inferior)
 
-(defvar inferior-octave-startup-file nil
-  "*Name of the inferior Octave startup file.
+(defcustom inferior-octave-startup-file nil
+  "Name of the inferior Octave startup file.
 The contents of this file are sent to the inferior Octave process on
-startup.")
+startup."
+  :type '(choice (const :tag "None" nil)
+                file)
+  :group 'octave-inferior)
 
-(defvar inferior-octave-startup-args nil
-  "*List of command line arguments for the inferior Octave process.
+(defcustom inferior-octave-startup-args nil
+  "List of command line arguments for the inferior Octave process.
 For example, for suppressing the startup message and using `traditional'
-mode, set this to (\"-q\" \"--traditional\").")
+mode, set this to (\"-q\" \"--traditional\")."
+  :type '(repeat string)
+  :group 'octave-inferior)
 
-(defvar inferior-octave-mode-map nil
-  "Keymap used in Inferior Octave mode.")
-(if inferior-octave-mode-map
-    ()
-  (let ((map (copy-keymap comint-mode-map)))
+(defvar inferior-octave-mode-map
+  (let ((map (make-sparse-keymap)))
+    (set-keymap-parent map comint-mode-map)
     (define-key map "\t" 'comint-dynamic-complete)
     (define-key map "\M-?" 'comint-dynamic-list-filename-completions)
     (define-key map "\C-c\C-l" 'inferior-octave-dynamic-list-input-ring)
     (define-key map [menu-bar inout list-history]
       '("List Input History" . inferior-octave-dynamic-list-input-ring))
     (define-key map "\C-c\C-h" 'octave-help)
-    (setq inferior-octave-mode-map map)))
+    map)
+  "Keymap used in Inferior Octave mode.")
 
-(defvar inferior-octave-mode-syntax-table nil
-  "Syntax table in use in inferior-octave-mode buffers.")
-(if inferior-octave-mode-syntax-table
-    ()
+(defvar 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)))
+    table)
+  "Syntax table in use in inferior-octave-mode buffers.")
 
-(defvar inferior-octave-mode-hook nil
-  "*Hook to be run when Inferior Octave mode is started.")
+(defcustom inferior-octave-mode-hook nil
+  "*Hook to be run when Inferior Octave mode is started."
+  :type 'hook
+  :group 'octave-inferior)
 
 (defvar inferior-octave-font-lock-keywords
   (list
@@ -77,6 +91,17 @@ mode, set this to (\"-q\" \"--traditional\").")
   ;; Could certainly do more font locking in inferior Octave ...
   "Additional expressions to highlight in Inferior Octave mode.")
 
+
+;;; Compatibility functions
+(if (not (fboundp 'comint-line-beginning-position))
+    ;; comint-line-beginning-position is defined in Emacs 21
+    (defun comint-line-beginning-position ()
+      "Returns the buffer position of the beginning of the line, after any prompt.
+The prompt is assumed to be any text at the beginning of the line matching
+the regular expression `comint-prompt-regexp', a buffer local variable."
+      (save-excursion (comint-bol nil) (point))))
+
+
 (defvar inferior-octave-output-list nil)
 (defvar inferior-octave-output-string nil)
 (defvar inferior-octave-receive-in-progress nil)
@@ -86,8 +111,11 @@ mode, set this to (\"-q\" \"--traditional\").")
 (defvar inferior-octave-complete-impossible nil
   "Non-nil means that `inferior-octave-complete' is impossible.")
 
+(defvar inferior-octave-has-built-in-variables nil
+  "Non-nil means that Octave has built-in variables.")
+
 (defvar inferior-octave-dynamic-complete-functions
-  '(inferior-octave-complete comint-dynamic-complete-filename)  
+  '(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.")
@@ -100,7 +128,7 @@ buffer.
 Entry to this mode successively runs the hooks `comint-mode-hook' and
 `inferior-octave-mode-hook'."
   (interactive)
-  (comint-mode)
+  (delay-mode-hooks (comint-mode))
   (setq comint-prompt-regexp inferior-octave-prompt
        major-mode 'inferior-octave-mode
        mode-name "Inferior Octave"
@@ -109,12 +137,12 @@ Entry to this mode successively runs the hooks `comint-mode-hook' and
   (use-local-map inferior-octave-mode-map)
   (set-syntax-table inferior-octave-mode-syntax-table)
 
-  (make-local-variable 'comment-start)  
+  (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)    
+  (setq comment-column 32)
   (make-local-variable 'comment-start-skip)
   (setq comment-start-skip octave-comment-start-skip)
 
@@ -123,13 +151,14 @@ Entry to this mode successively runs the hooks `comint-mode-hook' and
 
   (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-input-ring-size (or (getenv "OCTAVE_HISTSIZE") 1024))
+  (set (make-local-variable 'comint-dynamic-complete-functions)
+       inferior-octave-dynamic-complete-functions)
+  (add-hook 'comint-input-filter-functions
+       'inferior-octave-directory-tracker nil t)
   (comint-read-input-ring t)
 
-  (run-hooks 'inferior-octave-mode-hook))
+  (run-mode-hooks 'inferior-octave-mode-hook))
 
 ;;;###autoload
 (defun inferior-octave (&optional arg)
@@ -166,7 +195,8 @@ startup file, `~/.emacs-octave'."
               (substring inferior-octave-buffer 1 -1)
               inferior-octave-buffer
               inferior-octave-program
-              inferior-octave-startup-args)))
+              (append (list "-i" "--no-line-editing")
+                      inferior-octave-startup-args))))
     (set-process-filter proc 'inferior-octave-output-digest)
     (setq comint-ptyp process-connection-type
          inferior-octave-process proc
@@ -189,16 +219,34 @@ startup file, `~/.emacs-octave'."
          (concat (mapconcat
                   'identity inferior-octave-output-list "\n")
                  "\n"))))
+
+     ;; Find out whether Octave has built-in variables.
+     (inferior-octave-send-list-and-digest
+      (list "exist \"LOADPATH\"\n"))
+     (setq inferior-octave-has-built-in-variables
+         (string-match "101$" (car inferior-octave-output-list)))
+
+    ;; An empty secondary prompt, as e.g. obtained by '--braindead',
+    ;; means trouble.
+    (inferior-octave-send-list-and-digest (list "PS2\n"))
+    (if (string-match "\\(PS2\\|ans\\) = *$" (car inferior-octave-output-list))
+       (inferior-octave-send-list-and-digest
+        (list (if inferior-octave-has-built-in-variables
+                  "PS2 = \"> \"\n"
+                "PS2 (\"> \");\n"))))
+
     ;; O.k., now we are ready for the Inferior Octave startup commands.
     (let* (commands
           (program (file-name-nondirectory inferior-octave-program))
           (file (or inferior-octave-startup-file
                          (concat "~/.emacs-" program))))
       (setq commands
-           (list "page_screen_output = 0;\n"
+           (list "more off;\n"
                  (if (not (string-equal
-                           inferior-octave-output-string ">> ")) 
-                     "PS1=\"\\\\s> \";\n")
+                           inferior-octave-output-string ">> "))
+                     (if inferior-octave-has-built-in-variables
+                         "PS1=\"\\\\s> \";\n"
+                       "PS1 (\"\\\\s> \");\n"))
                  (if (file-exists-p file)
                      (format "source (\"%s\");\n" file))))
       (inferior-octave-send-list-and-digest commands))
@@ -217,7 +265,11 @@ startup file, `~/.emacs-octave'."
 
     ;; And finally, everything is back to normal.
     (set-process-filter proc 'inferior-octave-output-filter)
-    (run-hooks 'inferior-octave-startup-hook)))
+    (run-hooks 'inferior-octave-startup-hook)
+    (run-hooks 'inferior-octave-startup-hook)
+    ;; Just in case, to be sure a cd in the startup file
+    ;; won't have detrimental effects.
+    (inferior-octave-resync-dirs)))
 
 \f
 (defun inferior-octave-complete ()
@@ -226,13 +278,11 @@ 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)))
+        (command
+         (save-excursion
+           (skip-syntax-backward "w_" (comint-line-beginning-position))
+           (buffer-substring-no-properties (point) end)))
+        (proc (get-buffer-process inferior-octave-buffer)))
     (cond (inferior-octave-complete-impossible
           (error (concat
                   "Your Octave does not have `completion_matches'.  "
@@ -258,7 +308,7 @@ is NOT available with versions of Octave prior to 2.0."
            command inferior-octave-output-list)))))
 
 (defun inferior-octave-dynamic-list-input-ring ()
-  "List the buffer's input history in a help buffer"
+  "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)
@@ -335,20 +385,23 @@ output is passed to the filter `inferior-octave-output-digest'."
 (defun inferior-octave-directory-tracker (string)
   "Tracks `cd' commands issued to the inferior Octave process.
 Use \\[inferior-octave-resync-dirs] to resync if Emacs gets confused."
-  (if (string-match "[ \t]*cd[ \t]*\\([^ \t\n;]*\\)[ \t\n;]"
-                   string)
-      (cd (substring string (match-beginning 1) (match-end 1)))))
+  (cond
+   ((string-match "^[ \t]*cd[ \t;]*$" string)
+    (cd "~"))
+   ((string-match "^[ \t]*cd[ \t]+\\([^ \t\n;]*\\)[ \t\n;]*" string)
+    (cd (substring string (match-beginning 1) (match-end 1))))))
 
 (defun inferior-octave-resync-dirs ()
   "Resync the buffer's idea of the current directory.
 This command queries the inferior Octave process about its current
 directory and makes this the current buffer's default directory."
   (interactive)
-  (inferior-octave-send-list-and-digest '("pwd\n"))
+  (inferior-octave-send-list-and-digest '("disp (pwd ())\n"))
   (cd (car inferior-octave-output-list)))
 
 ;;; provide ourself
 
 (provide 'octave-inf)
 
+;; arch-tag: bdce0395-24d1-4bb4-bfba-6fb1eeb1a660
 ;;; octave-inf.el ends here