summaryrefslogtreecommitdiff
path: root/lisp/shell.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/shell.el')
-rw-r--r--lisp/shell.el82
1 files changed, 58 insertions, 24 deletions
diff --git a/lisp/shell.el b/lisp/shell.el
index 100bbc40376..57cc11f9d4f 100644
--- a/lisp/shell.el
+++ b/lisp/shell.el
@@ -70,7 +70,7 @@
;; c-c c-c comint-interrupt-subjob ^c
;; c-c c-z comint-stop-subjob ^z
;; c-c c-\ comint-quit-subjob ^\
-;; c-c c-o comint-kill-output Delete last batch of process output
+;; c-c c-o comint-delete-output Delete last batch of process output
;; c-c c-r comint-show-output Show last batch of process output
;; c-c c-l comint-dynamic-list-input-ring List input history
;; send-invisible Read line w/o echo & send to proc
@@ -334,25 +334,25 @@ Thus, this does not include the shell's current directory.")
(defvar shell-dirstack-query nil
"Command used by `shell-resync-dirs' to query the shell.")
-(defvar shell-mode-map nil)
-(cond ((not shell-mode-map)
- (setq shell-mode-map (nconc (make-sparse-keymap) comint-mode-map))
- (define-key shell-mode-map "\C-c\C-f" 'shell-forward-command)
- (define-key shell-mode-map "\C-c\C-b" 'shell-backward-command)
- (define-key shell-mode-map "\t" 'comint-dynamic-complete)
- (define-key shell-mode-map "\M-?"
- 'comint-dynamic-list-filename-completions)
- (define-key shell-mode-map [menu-bar completion]
- (cons "Complete"
- (copy-keymap (lookup-key comint-mode-map [menu-bar completion]))))
- (define-key-after (lookup-key shell-mode-map [menu-bar completion])
- [complete-env-variable] '("Complete Env. Variable Name" .
- shell-dynamic-complete-environment-variable)
- 'complete-file)
- (define-key-after (lookup-key shell-mode-map [menu-bar completion])
- [expand-directory] '("Expand Directory Reference" .
- shell-replace-by-expanded-directory)
- 'complete-expand)))
+(defvar shell-mode-map
+ (let ((map (nconc (make-sparse-keymap) comint-mode-map)))
+ (define-key map "\C-c\C-f" 'shell-forward-command)
+ (define-key map "\C-c\C-b" 'shell-backward-command)
+ (define-key map "\t" 'comint-dynamic-complete)
+ (define-key map (kbd "M-RET") 'shell-resync-dirs)
+ (define-key map "\M-?" 'comint-dynamic-list-filename-completions)
+ (define-key map [menu-bar completion]
+ (cons "Complete"
+ (copy-keymap (lookup-key comint-mode-map [menu-bar completion]))))
+ (define-key-after (lookup-key map [menu-bar completion])
+ [complete-env-variable] '("Complete Env. Variable Name" .
+ shell-dynamic-complete-environment-variable)
+ 'complete-file)
+ (define-key-after (lookup-key map [menu-bar completion])
+ [expand-directory] '("Expand Directory Reference" .
+ shell-replace-by-expanded-directory)
+ 'complete-expand)
+ map))
(defcustom shell-mode-hook '()
"Hook for customizing Shell mode."
@@ -367,6 +367,17 @@ Thus, this does not include the shell's current directory.")
;;; Basic Procedures
+(defcustom shell-dir-cookie-re nil
+ "Regexp matching your prompt, including some part of the current directory.
+If your prompt includes the current directory or the last few elements of it,
+set this to a pattern that matches your prompt and whose subgroup 1 matches
+the directory part of it.
+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))
+
(put 'shell-mode 'mode-class 'special)
(define-derived-mode shell-mode comint-mode "Shell"
@@ -471,6 +482,10 @@ buffer."
(when (string-equal shell "bash")
(add-hook 'comint-output-filter-functions
'shell-filter-ctrl-a-ctrl-b nil t)))
+ (when shell-dir-cookie-re
+ ;; Watch for magic cookies in the output to track the current dir.
+ (add-hook 'comint-output-filter-functions
+ 'shell-dir-cookie-watcher nil t))
(comint-read-input-ring t)))
(defun shell-filter-ctrl-a-ctrl-b (string)
@@ -549,13 +564,19 @@ Otherwise, one argument `-i' is passed to the shell.
(generate-new-buffer-name "*shell*"))
(if (file-remote-p default-directory)
;; It must be possible to declare a local default-directory.
+ ;; FIXME: This can't be right: it changes the default-directory
+ ;; of the current-buffer rather than of the *shell* buffer.
(setq default-directory
(expand-file-name
(read-file-name
"Default directory: " default-directory default-directory
t nil 'file-directory-p))))))))
(require 'ansi-color)
- (setq buffer (get-buffer-create (or buffer "*shell*")))
+ (setq buffer (if (or buffer (not (derived-mode-p 'shell-mode))
+ (comint-check-proc (current-buffer)))
+ (get-buffer-create (or buffer "*shell*"))
+ ;; If the current buffer is a dead shell buffer, use it.
+ (current-buffer)))
;; 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)
@@ -618,6 +639,20 @@ Otherwise, one argument `-i' is passed to the shell.
;; replace it with a process filter that watches for and strips out
;; these messages.
+(defun shell-dir-cookie-watcher (text)
+ ;; This is fragile: the TEXT could be split into several chunks and we'd
+ ;; miss it. Oh well. It's a best effort anyway. I'd expect that it's
+ ;; rather unusual to have the prompt split into several packets, but
+ ;; I'm sure Murphy will prove me wrong.
+ (when (and shell-dir-cookie-re (string-match shell-dir-cookie-re text))
+ (let ((dir (match-string 1 text)))
+ (cond
+ ((file-name-absolute-p dir) (shell-cd dir))
+ ;; Let's try and see if it seems to be up or down from where we were.
+ ((string-match "\\`\\(.*\\)\\(?:/.*\\)?\n\\(.*/\\)\\1\\(?:/.*\\)?\\'"
+ (setq text (concat dir "\n" default-directory)))
+ (shell-cd (concat (match-string 2 text) dir)))))))
+
(defun shell-directory-tracker (str)
"Tracks cd, pushd and popd commands issued to the shell.
This function is called on each input passed to the shell.
@@ -700,7 +735,7 @@ Environment variables are expanded, see function `substitute-in-file-name'."
(defun shell-process-popd (arg)
(let ((num (or (shell-extract-num arg) 0)))
(cond ((and num (= num 0) shell-dirstack)
- (shell-cd (car shell-dirstack))
+ (shell-cd (shell-prefixed-directory-name (car shell-dirstack)))
(setq shell-dirstack (cdr shell-dirstack))
(shell-dirstack-message))
((and num (> num 0) (<= num (length shell-dirstack)))
@@ -928,7 +963,7 @@ Copy Shell environment variable to Emacs: ")))
"Move forward across ARG shell command(s). Does not cross lines.
See `shell-command-regexp'."
(interactive "p")
- (let ((limit (save-excursion (end-of-line nil) (point))))
+ (let ((limit (line-end-position)))
(if (re-search-forward (concat shell-command-regexp "\\([;&|][\t ]*\\)+")
limit 'move arg)
(skip-syntax-backward " "))))
@@ -1111,5 +1146,4 @@ Returns t if successful."
(provide 'shell)
-;; arch-tag: bcb5f12a-c1f4-4aea-a809-2504bd5bd797
;;; shell.el ends here