Bug fix for vc-dispatcher split.
[bpt/emacs.git] / lisp / progmodes / octave-inf.el
index cbe4ffc..791f423 100644 (file)
@@ -1,17 +1,18 @@
 ;;; 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>
 ;; 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
 ;; it under the terms of the GNU General Public License as published by
 ;; 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)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 
 ;; 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
 
 ;; 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.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
+
+;;; Commentary:
 
 ;;; Code:
 
 (require 'octave-mod)
 (require 'comint)
 
 
 ;;; 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
 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'
 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)
     (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)
   (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
 
 (defvar inferior-octave-font-lock-keywords
   (list
@@ -77,6 +93,17 @@ mode, set this to (\"-q\" \"--traditional\").")
   ;; Could certainly do more font locking in inferior Octave ...
   "Additional expressions to highlight in Inferior Octave mode.")
 
   ;; Could certainly do more font locking in inferior Octave ...
   "Additional expressions to highlight in Inferior Octave mode.")
 
+
+;;; Compatibility functions
+(if (not (fboundp 'comint-line-beginning-position))
+    ;; comint-line-beginning-position is defined in Emacs 21
+    (defun comint-line-beginning-position ()
+      "Returns the buffer position of the beginning of the line, after any prompt.
+The prompt is assumed to be any text at the beginning of the line matching
+the regular expression `comint-prompt-regexp', a buffer local variable."
+      (save-excursion (comint-bol nil) (point))))
+
+
 (defvar inferior-octave-output-list nil)
 (defvar inferior-octave-output-string nil)
 (defvar inferior-octave-receive-in-progress nil)
 (defvar inferior-octave-output-list nil)
 (defvar inferior-octave-output-string nil)
 (defvar inferior-octave-receive-in-progress nil)
@@ -86,8 +113,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-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
 (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.")
   "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 +130,7 @@ buffer.
 Entry to this mode successively runs the hooks `comint-mode-hook' and
 `inferior-octave-mode-hook'."
   (interactive)
 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"
   (setq comint-prompt-regexp inferior-octave-prompt
        major-mode 'inferior-octave-mode
        mode-name "Inferior Octave"
@@ -109,12 +139,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)
 
   (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-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)
 
   (make-local-variable 'comment-start-skip)
   (setq comment-start-skip octave-comment-start-skip)
 
@@ -123,13 +153,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")
 
   (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)
 
   (comint-read-input-ring t)
 
-  (run-hooks 'inferior-octave-mode-hook))
+  (run-mode-hooks 'inferior-octave-mode-hook))
 
 ;;;###autoload
 (defun inferior-octave (&optional arg)
 
 ;;;###autoload
 (defun inferior-octave (&optional arg)
@@ -166,7 +197,8 @@ startup file, `~/.emacs-octave'."
               (substring inferior-octave-buffer 1 -1)
               inferior-octave-buffer
               inferior-octave-program
               (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
     (set-process-filter proc 'inferior-octave-output-digest)
     (setq comint-ptyp process-connection-type
          inferior-octave-process proc
@@ -189,16 +221,34 @@ startup file, `~/.emacs-octave'."
          (concat (mapconcat
                   'identity inferior-octave-output-list "\n")
                  "\n"))))
          (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
     ;; 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
                  (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))
                  (if (file-exists-p file)
                      (format "source (\"%s\");\n" file))))
       (inferior-octave-send-list-and-digest commands))
@@ -217,7 +267,11 @@ startup file, `~/.emacs-octave'."
 
     ;; And finally, everything is back to normal.
     (set-process-filter proc 'inferior-octave-output-filter)
 
     ;; 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 ()
 
 \f
 (defun inferior-octave-complete ()
@@ -226,13 +280,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))
 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'.  "
     (cond (inferior-octave-complete-impossible
           (error (concat
                   "Your Octave does not have `completion_matches'.  "
@@ -258,7 +310,7 @@ is NOT available with versions of Octave prior to 2.0."
            command inferior-octave-output-list)))))
 
 (defun inferior-octave-dynamic-list-input-ring ()
            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)
   ;; We cannot use `comint-dynamic-list-input-ring', because it replaces
   ;; "completion" by "history reference" ...
   (interactive)
@@ -335,20 +387,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."
 (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)
 
 (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)
 
   (cd (car inferior-octave-output-list)))
 
 ;;; provide ourself
 
 (provide 'octave-inf)
 
+;; arch-tag: bdce0395-24d1-4bb4-bfba-6fb1eeb1a660
 ;;; octave-inf.el ends here
 ;;; octave-inf.el ends here