Disable whitespace-newline-mode properly.
[bpt/emacs.git] / lisp / shell.el
index cba5003..c75594d 100644 (file)
@@ -98,6 +98,7 @@
 
 (eval-when-compile (require 'cl))
 (require 'comint)
+(require 'pcomplete)
 
 ;;; Customization and Buffer Variables
 
@@ -186,7 +187,9 @@ This is a fine thing to set in your `.emacs' file.")
     shell-environment-variable-completion
     shell-command-completion
     shell-c-a-p-replace-by-expanded-directory
+    pcomplete-completions-at-point
     shell-filename-completion
+    ;; Not sure when this one would still be useful.  --Stef
     comint-filename-completion)
   "List of functions called to perform completion.
 This variable is used to initialize `comint-dynamic-complete-functions' in the
@@ -378,9 +381,42 @@ This is used by `shell-dir-cookie-watcher' to try and use this info
 to track your current directory.  It can be used instead of or in addition
 to `dirtrack-mode'."
   :group 'shell
-  :type '(choice (const nil) regexp))
-
-(defvar pcomplete-parse-arguments-function)
+  :type '(choice (const nil) regexp)
+  :version "24.1")
+
+(defun shell-parse-pcomplete-arguments ()
+  "Parse whitespace separated arguments in the current region."
+  (let ((begin (save-excursion (shell-backward-command 1) (point)))
+       (end (point))
+       begins args)
+    (save-excursion
+      (goto-char begin)
+      (while (< (point) end)
+       (skip-chars-forward " \t\n")
+       (push (point) begins)
+        (let ((arg ()))
+          (while (looking-at
+                  (eval-when-compile
+                    (concat
+                     "\\(?:[^\s\t\n\\\"']+"
+                     "\\|'\\([^']*\\)'?"
+                     "\\|\"\\(\\(?:[^\"\\]\\|\\\\.\\)*\\)\"?"
+                     "\\|\\\\\\(\\(?:.\\|\n\\)?\\)\\)")))
+            (goto-char (match-end 0))
+            (cond
+             ((match-beginning 3)       ;Backslash escape.
+              (push (if (= (match-beginning 3) (match-end 3))
+                        "\\" (match-string 3))
+                    arg))
+             ((match-beginning 2)       ;Double quote.
+              (push (replace-regexp-in-string
+                     "\\\\\\(.\\)" "\\1" (match-string 2))
+                    arg))
+             ((match-beginning 1)       ;Single quote.
+              (push (match-string 1) arg))
+             (t (push (match-string 0) arg))))
+          (push (mapconcat #'identity (nreverse arg) "") args)))
+      (cons (nreverse args) (nreverse begins)))))
 
 (defun shell-completion-vars ()
   "Setup completion vars for `shell-mode' and `read-shell-command'."
@@ -394,8 +430,18 @@ to `dirtrack-mode'."
   (set (make-local-variable 'comint-dynamic-complete-functions)
        shell-dynamic-complete-functions)
   (set (make-local-variable 'pcomplete-parse-arguments-function)
-       ;; FIXME: This function should be moved to shell.el.
-       #'pcomplete-parse-comint-arguments)
+       #'shell-parse-pcomplete-arguments)
+  (set (make-local-variable 'pcomplete-arg-quote-list)
+       (append "\\ \t\n\r\"'`$|&;(){}[]<>#" nil))
+  (set (make-local-variable 'pcomplete-termination-string)
+       (cond ((not comint-completion-addsuffix) "")
+             ((stringp comint-completion-addsuffix)
+              comint-completion-addsuffix)
+             ((not (consp comint-completion-addsuffix)) " ")
+             (t (cdr comint-completion-addsuffix))))
+  ;; Don't use pcomplete's defaulting mechanism, rely on
+  ;; shell-dynamic-complete-functions instead.
+  (set (make-local-variable 'pcomplete-default-completion-function) #'ignore)
   (setq comint-input-autoexpand shell-input-autoexpand)
   ;; Not needed in shell-mode because it's inherited from comint-mode, but
   ;; placed here for read-shell-command.
@@ -605,9 +651,9 @@ Otherwise, one argument `-i' is passed to the shell.
                t shell-file-name))
              'localname))))
 
-  ;; Pop to buffer, so that the buffer's window will be correctly set
-  ;; when we call comint (so that comint sets the COLUMNS env var properly).
-  (pop-to-buffer buffer)
+  ;; The buffer's window must be correctly set when we call comint (so
+  ;; that comint sets the COLUMNS env var properly).
+  (pop-to-buffer-same-window buffer)
   (unless (comint-check-proc buffer)
     (let* ((prog (or explicit-shell-file-name
                     (getenv "ESHELL") shell-file-name))
@@ -624,9 +670,6 @@ Otherwise, one argument `-i' is passed to the shell.
       (shell-mode)))
   buffer)
 
-;; Don't do this when shell.el is loaded, only while dumping.
-;;;###autoload (add-hook 'same-window-buffer-names (purecopy "*shell*"))
-
 ;;; Directory tracking
 ;;
 ;; This code provides the shell mode input sentinel
@@ -704,6 +747,7 @@ Environment variables are expanded, see function `substitute-in-file-name'."
                               (concat "^" shell-command-separator-regexp)
                               str) ; skip whitespace
                              (match-end 0)))
+               (case-fold-search)
                end cmd arg1)
            (while (string-match shell-command-regexp str start)
              (setq end (match-end 0)
@@ -846,9 +890,13 @@ Environment variables are expanded, see function `substitute-in-file-name'."
 
 (defvaralias 'shell-dirtrack-mode 'shell-dirtrackp)
 (define-minor-mode shell-dirtrack-mode
-  "Turn directory tracking on and off in a shell buffer.
-The `dirtrack' package provides an alternative implementation of this
-feature - see the function `dirtrack-mode'."
+  "Toggle directory tracking in this shell buffer (Shell Dirtrack mode).
+With a prefix argument ARG, enable Shell Dirtrack mode if ARG is
+positive, and disable it otherwise.  If called from Lisp, enable
+the mode if ARG is omitted or nil.
+
+The `dirtrack' package provides an alternative implementation of
+this feature; see the function `dirtrack-mode'."
   nil nil nil
   (setq list-buffers-directory (if shell-dirtrack-mode default-directory))
   (if shell-dirtrack-mode
@@ -1074,12 +1122,15 @@ Returns t if successful."
     (list
      start end
      (lambda (string pred action)
-       (completion-table-with-terminator
-        " " (lambda (string pred action)
-              (if (string-match "/" string)
-                  (completion-file-name-table string pred action)
-                (complete-with-action action completions string pred)))
-        string pred action)))))
+       (if (string-match "/" string)
+           (completion-file-name-table string pred action)
+         (complete-with-action action completions string pred)))
+     :exit-function
+     (lambda (_string finished)
+       (when (memq finished '(sole finished))
+         (if (looking-at " ")
+             (goto-char (match-end 0))
+           (insert " ")))))))
 
 ;; (defun shell-dynamic-complete-as-command ()
 ;;    "Dynamically complete at point as a command.
@@ -1150,18 +1201,17 @@ Returns non-nil if successful."
                                   (substring x 0 (string-match "=" x)))
                                 process-environment))
              (suffix (case (char-before start) (?\{ "}") (?\( ")") (t ""))))
-        (list
-         start end
-         (apply-partially
-          #'completion-table-with-terminator
-          (cons (lambda (comp)
-                  (concat comp
-                          suffix
-                          (if (file-directory-p
-                               (comint-directory (getenv comp)))
-                              "/")))
-                "\\`a\\`")
-          variables))))))
+        (list start end variables
+              :exit-function
+              (lambda (s finished)
+                (when (memq finished '(sole finished))
+                  (let ((suf (concat suffix
+                                     (if (file-directory-p
+                                          (comint-directory (getenv s)))
+                                         "/"))))
+                    (if (looking-at (regexp-quote suf))
+                        (goto-char (match-end 0))
+                      (insert suf))))))))))
 
 
 (defun shell-c-a-p-replace-by-expanded-directory ()