summaryrefslogtreecommitdiff
path: root/lisp/eshell
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2000-10-29 05:18:48 +0000
committerJohn Wiegley <johnw@newartisans.com>2000-10-29 05:18:48 +0000
commitdace60cfea488a9cc8a775109c56b66907aa6abb (patch)
tree364b9c0114540a5f51a42e1e28a37b98714edaee /lisp/eshell
parent657f9cb8b7f7c3a9687f3998319ce63346ef13a4 (diff)
downloademacs-dace60cfea488a9cc8a775109c56b66907aa6abb.tar.gz
See ChangeLog
Diffstat (limited to 'lisp/eshell')
-rw-r--r--lisp/eshell/em-alias.el7
-rw-r--r--lisp/eshell/em-dirs.el6
-rw-r--r--lisp/eshell/em-glob.el5
-rw-r--r--lisp/eshell/em-ls.el74
-rw-r--r--lisp/eshell/em-script.el3
-rw-r--r--lisp/eshell/em-smart.el35
-rw-r--r--lisp/eshell/em-unix.el129
-rw-r--r--lisp/eshell/esh-cmd.el120
-rw-r--r--lisp/eshell/esh-groups.el1
-rw-r--r--lisp/eshell/esh-maint.el68
-rw-r--r--lisp/eshell/esh-mode.el11
-rw-r--r--lisp/eshell/esh-module.el6
-rw-r--r--lisp/eshell/esh-test.el8
-rw-r--r--lisp/eshell/esh-util.el14
14 files changed, 279 insertions, 208 deletions
diff --git a/lisp/eshell/em-alias.el b/lisp/eshell/em-alias.el
index 85e4e97e692..a407bf5deb8 100644
--- a/lisp/eshell/em-alias.el
+++ b/lisp/eshell/em-alias.el
@@ -151,7 +151,12 @@ command, which will automatically write them to the file named by
(add-hook 'eshell-alternate-command-hook 'eshell-fix-bad-commands t t)
(eshell-read-aliases-list)
(make-local-hook 'eshell-named-command-hook)
- (add-hook 'eshell-named-command-hook 'eshell-maybe-replace-by-alias t t))
+ (add-hook 'eshell-named-command-hook 'eshell-maybe-replace-by-alias t t)
+ (make-local-variable 'eshell-complex-commands)
+ (add-to-list 'eshell-complex-commands 'eshell-command-aliased-p))
+
+(defun eshell-command-aliased-p (name)
+ (member name eshell-command-aliases-list))
(defun eshell/alias (&optional alias &rest definition)
"Define an ALIAS in the user's alias list using DEFINITION."
diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el
index 02d1eb3076b..0c147f14be6 100644
--- a/lisp/eshell/em-dirs.el
+++ b/lisp/eshell/em-dirs.el
@@ -297,7 +297,7 @@ Thus, this does not include the current directory.")
(file-name-as-directory (cdr user))))
eshell-user-names)))))))
-(defun eshell/pwd (&rest args) ; ignored
+(defun eshell/pwd (&rest args)
"Change output from `pwd` to be cleaner."
(let* ((path default-directory)
(len (length path)))
@@ -307,8 +307,8 @@ Thus, this does not include the current directory.")
(string-match "\\`[A-Za-z]:[\\\\/]\\'" path))))
(setq path (substring path 0 (1- (length path)))))
(if eshell-pwd-convert-function
- (setq path (funcall eshell-pwd-convert-function path)))
- path))
+ (funcall eshell-pwd-convert-function path)
+ path)))
(defun eshell-expand-multiple-dots (path)
"Convert '...' to '../..', '....' to '../../..', etc..
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index b281cee4fd7..f4f9ebbe5b6 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -81,8 +81,9 @@ by zsh for filename generation."
:type 'boolean
:group 'eshell-glob)
-(defcustom eshell-glob-show-progress t
- "*If non-nil, display progress messages during a recursive glob."
+(defcustom eshell-glob-show-progress nil
+ "*If non-nil, display progress messages during a recursive glob.
+This option slows down recursive glob processing by quite a bit."
:type 'boolean
:group 'eshell-glob)
diff --git a/lisp/eshell/em-ls.el b/lisp/eshell/em-ls.el
index 2afef625f55..534ea932c3c 100644
--- a/lisp/eshell/em-ls.el
+++ b/lisp/eshell/em-ls.el
@@ -57,6 +57,12 @@ properties to colorize its output based on the setting of
:type 'hook
:group 'eshell-ls)
+(defcustom eshell-ls-initial-args nil
+ "*If non-nil, this list of args is included before any call to `ls'.
+This is useful for enabling human-readable format (-h), for example."
+ :type '(repeat :tag "Arguments" string)
+ :group 'eshell-ls)
+
(defcustom eshell-ls-use-in-dired nil
"*If non-nil, use `eshell-ls' to read directories in dired."
:set (lambda (symbol value)
@@ -77,11 +83,18 @@ properties to colorize its output based on the setting of
:type 'integer
:group 'eshell-ls)
-(defcustom eshell-ls-exclude-regexp "\\`\\."
+(defcustom eshell-ls-exclude-regexp nil
"*Unless -a is specified, files matching this regexp will not be shown."
:type 'regexp
:group 'eshell-ls)
+(defcustom eshell-ls-exclude-hidden t
+ "*Unless -a is specified, files beginning with . will not be shown.
+Using this boolean, instead of `eshell-ls-exclude-regexp', is both
+faster and conserves more memory."
+ :type 'boolean
+ :group 'eshell-ls)
+
(defcustom eshell-ls-use-colors t
"*If non-nil, use colors in file listings."
:type 'boolean
@@ -196,13 +209,13 @@ This is really just for efficiency, to avoid having to stat the file
yet again."
`(if (numberp (nth 2 ,attrs))
(if (= (user-uid) (nth 2 ,attrs))
- (not (eq (aref (nth 8 ,attrs) ,index) ?-))
- (,(eval func) ,file))
+ (not (eq (aref (nth 8 ,attrs) ,index) ?-))
+ (,(eval func) ,file))
(not (eq (aref (nth 8 ,attrs)
- (+ ,index (if (member (nth 2 ,attrs)
- (eshell-current-ange-uids))
- 0 6)))
- ?-))))
+ (+ ,index (if (member (nth 2 ,attrs)
+ (eshell-current-ange-uids))
+ 0 6)))
+ ?-))))
(defcustom eshell-ls-highlight-alist nil
"*This alist correlates test functions to color.
@@ -248,7 +261,8 @@ instead."
(symbol-value 'font-lock-buffers)))))
(let ((insert-func 'insert)
(error-func 'insert)
- (flush-func 'ignore))
+ (flush-func 'ignore)
+ eshell-ls-initial-args)
(eshell-do-ls (append switches (list file))))))))
(defsubst eshell/ls (&rest args)
@@ -281,7 +295,9 @@ instead."
(funcall flush-func -1)
;; process the command arguments, and begin listing files
(eshell-eval-using-options
- "ls" args
+ "ls" (if eshell-ls-initial-args
+ (list eshell-ls-initial-args args)
+ args)
`((?a "all" nil show-all
"show all files in directory")
(?c nil by-ctime sort-method
@@ -343,11 +359,11 @@ Sort entries alphabetically across.")
(error (concat "-I option requires that `eshell-glob'"
" be a member of `eshell-modules-list'")))
(set-text-properties 0 (length ignore-pattern) nil ignore-pattern)
- (if eshell-ls-exclude-regexp
- (setq eshell-ls-exclude-regexp
+ (setq eshell-ls-exclude-regexp
+ (if eshell-ls-exclude-regexp
(concat "\\(" eshell-ls-exclude-regexp "\\|"
- (eshell-glob-regexp ignore-pattern) "\\)"))
- (setq eshell-ls-exclude-regexp (eshell-glob-regexp ignore-pattern))))
+ (eshell-glob-regexp ignore-pattern) "\\)")
+ (eshell-glob-regexp ignore-pattern))))
;; list the files!
(eshell-ls-entries
(mapcar (function
@@ -356,7 +372,8 @@ Sort entries alphabetically across.")
(file-name-absolute-p arg))
(expand-file-name arg)
arg)
- (eshell-file-attributes arg)))) args)
+ (eshell-file-attributes arg))))
+ args)
t (expand-file-name default-directory)))
(funcall flush-func)))
@@ -491,12 +508,13 @@ relative to that directory."
(file-relative-name dir root-dir)
(expand-file-name dir)))
(cdr dirinfo))) ":\n"))
- (let ((entries
- (eshell-directory-files-and-attributes dir nil nil t)))
- (unless show-all
- (while (and entries
- (string-match eshell-ls-exclude-regexp
- (caar entries)))
+ (let ((entries (eshell-directory-files-and-attributes
+ dir nil (and (not show-all)
+ eshell-ls-exclude-hidden
+ "\\`[^.]") t)))
+ (when (and (not show-all) eshell-ls-exclude-regexp)
+ (while (and entries (string-match eshell-ls-exclude-regexp
+ (caar entries)))
(setq entries (cdr entries)))
(let ((e entries))
(while (cdr e)
@@ -552,17 +570,13 @@ In Eshell's implementation of ls, ENTRIES is always reversed."
(let ((result
(cond
((eq sort-method 'by-atime)
- (eshell-ls-compare-entries
- l r 4 'eshell-time-less-p))
+ (eshell-ls-compare-entries l r 4 'eshell-time-less-p))
((eq sort-method 'by-mtime)
- (eshell-ls-compare-entries
- l r 5 'eshell-time-less-p))
+ (eshell-ls-compare-entries l r 5 'eshell-time-less-p))
((eq sort-method 'by-ctime)
- (eshell-ls-compare-entries
- l r 6 'eshell-time-less-p))
+ (eshell-ls-compare-entries l r 6 'eshell-time-less-p))
((eq sort-method 'by-size)
- (eshell-ls-compare-entries
- l r 7 '<))
+ (eshell-ls-compare-entries l r 7 '<))
((eq sort-method 'by-extension)
(let ((lx (file-name-extension
(directory-file-name (car l))))
@@ -699,8 +713,8 @@ need to be printed."
(if (and need-return (not dir-literal))
(funcall insert-func "\n"))
(eshell-ls-dir dir show-names
- (unless (file-name-absolute-p (car dir))
- root-dir) size-width)
+ (unless (file-name-absolute-p (car dir)) root-dir)
+ size-width)
(setq need-return t))))
(defun eshell-ls-find-column-widths (files)
diff --git a/lisp/eshell/em-script.el b/lisp/eshell/em-script.el
index d6a8ea54e2f..8967426cadf 100644
--- a/lisp/eshell/em-script.el
+++ b/lisp/eshell/em-script.el
@@ -63,6 +63,9 @@ This includes when running `eshell-command'."
(string= (file-name-nondirectory file)
"eshell")) . eshell/source)
eshell-interpreter-alist))
+ (make-local-variable 'eshell-complex-commands)
+ (setq eshell-complex-commands
+ (append '("source" ".") eshell-complex-commands))
;; these two variables are changed through usage, but we don't want
;; to ruin it for other modules
(let (eshell-inside-quote-regexp
diff --git a/lisp/eshell/em-smart.el b/lisp/eshell/em-smart.el
index cc02f2fedc3..9bef8b10d20 100644
--- a/lisp/eshell/em-smart.el
+++ b/lisp/eshell/em-smart.el
@@ -77,6 +77,11 @@ it to get a real sense of how it works."
;; scroll, etc.
;;
;; @ Like I said, it's not really comprehensible until you try it! ;)
+;;
+;; One disadvantage of this module is that it increases Eshell's
+;; memory consumption by a factor of two or more. With small commands
+;; (such as pwd), where the screen is mostly full, consumption can
+;; increase by orders of magnitude.
;;; User Variables:
@@ -154,6 +159,7 @@ The options are `begin', `after' or `end'."
(defvar eshell-smart-displayed nil)
(defvar eshell-smart-command-done nil)
+(defvar eshell-currently-handling-window nil)
;;; Functions:
@@ -175,19 +181,17 @@ The options are `begin', `after' or `end'."
(make-local-hook 'pre-command-hook)
(make-local-hook 'after-change-functions)
- (add-hook 'after-change-functions
- 'eshell-disable-after-change nil t)
+ (add-hook 'after-change-functions 'eshell-disable-after-change nil t)
(make-local-hook 'eshell-input-filter-functions)
- (add-hook 'eshell-input-filter-functions
- 'eshell-smart-display-setup nil t)
+ (add-hook 'eshell-input-filter-functions 'eshell-smart-display-setup nil t)
(make-local-variable 'eshell-smart-command-done)
(make-local-hook 'eshell-post-command-hook)
- (add-hook 'eshell-post-command-hook
- (function
- (lambda ()
- (setq eshell-smart-command-done t))) t t)
+ (add-hook 'eshell-post-command-hook
+ (function
+ (lambda ()
+ (setq eshell-smart-command-done t))) t t)
(unless (eq eshell-review-quick-commands t)
(add-hook 'eshell-post-command-hook
@@ -198,10 +202,9 @@ The options are `begin', `after' or `end'."
(unless eshell-currently-handling-window
(let ((inhibit-point-motion-hooks t)
(eshell-currently-handling-window t))
- (save-current-buffer
- (save-selected-window
- (select-window wind)
- (eshell-smart-redisplay))))))
+ (save-selected-window
+ (select-window wind)
+ (eshell-smart-redisplay)))))
(defun eshell-refresh-windows (&optional frame)
"Refresh all visible Eshell buffers."
@@ -210,10 +213,10 @@ The options are `begin', `after' or `end'."
(function
(lambda (wind)
(with-current-buffer (window-buffer wind)
- (when eshell-mode
- (let (window-scroll-functions)
- (eshell-smart-scroll-window wind (window-start))
- (setq affected t))))))
+ (if eshell-mode
+ (let (window-scroll-functions)
+ (eshell-smart-scroll-window wind (window-start))
+ (setq affected t))))))
0 frame)
(if affected
(let (window-scroll-functions)
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index 7f0414ef056..c9b3d418b83 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -124,6 +124,11 @@ Otherwise, `rmdir' is required."
:type 'boolean
:group 'eshell-unix)
+(defcustom eshell-default-target-is-dot nil
+ "*If non-nil, the default destination for cp, mv or ln is `.'."
+ :type 'boolean
+ :group 'eshell-unix)
+
(defcustom eshell-du-prefer-over-ange nil
"*Use Eshell's du in ange-ftp remote directories.
Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
@@ -140,7 +145,12 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
(when (eshell-using-module 'eshell-cmpl)
(make-local-hook 'pcomplete-try-first-hook)
(add-hook 'pcomplete-try-first-hook
- 'eshell-complete-host-reference nil t)))
+ 'eshell-complete-host-reference nil t))
+ (make-local-variable 'eshell-complex-commands)
+ (setq eshell-complex-commands
+ (append '("grep" "egrep" "fgrep" "agrep" "glimpse" "locate"
+ "cat" "time" "cp" "mv" "make" "du" "diff")
+ eshell-complex-commands)))
(defalias 'eshell/date 'current-time-string)
(defalias 'eshell/basename 'file-name-nondirectory)
@@ -157,6 +167,7 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine."
(funcall 'man (apply 'eshell-flatten-and-stringify args)))
(defun eshell-remove-entries (path files &optional top-level)
+ "From PATH, remove all of the given FILES, perhaps interactively."
(while files
(if (string-match "\\`\\.\\.?\\'"
(file-name-nondirectory (car files)))
@@ -302,8 +313,6 @@ Remove the DIRECTORY(ies), if they are empty.")
(defun eshell-shuffle-files (command action files target func deep &rest args)
"Shuffle around some filesystem entries, using FUNC to do the work."
- (if (null target)
- (error "%s: missing destination file" command))
(let ((attr-target (eshell-file-attributes target))
(is-dir (or (file-directory-p target)
(and preview (not eshell-warn-dot-directories))))
@@ -417,30 +426,35 @@ Remove the DIRECTORY(ies), if they are empty.")
(format "tar %s %s" tar-args archive) args))))
;; this is to avoid duplicating code...
-(defmacro eshell-mvcp-template
- (command action func query-var force-var &optional preserve)
- `(if (and (string-match eshell-tar-regexp (car (last args)))
- (or (> (length args) 2)
- (and (file-directory-p (car args))
- (or (not no-dereference)
- (not (file-symlink-p (car args)))))))
- (eshell-shorthand-tar-command ,command args)
- (let (target ange-cache)
- (if (> (length args) 1)
- (progn
- (setq target (car (last args)))
- (setcdr (last args 2) nil))
- (setq args nil))
- (eshell-shuffle-files
- ,command ,action args target ,func nil
- ,@(append
- `((if (and (or interactive
- ,query-var)
- (not force))
- 1 (or force ,force-var)))
- (if preserve
- (list preserve)))))
- nil))
+(defmacro eshell-mvcpln-template (command action func query-var
+ force-var &optional preserve)
+ `(let ((len (length args)))
+ (if (or (= len 0)
+ (and (= len 1) (null eshell-default-target-is-dot)))
+ (error "%s: missing destination file or directory" ,command))
+ (if (= len 1)
+ (nconc args '(".")))
+ (setq args (eshell-stringify-list (eshell-flatten-list args)))
+ (if (and ,(not (equal command "ln"))
+ (string-match eshell-tar-regexp (car (last args)))
+ (or (> (length args) 2)
+ (and (file-directory-p (car args))
+ (or (not no-dereference)
+ (not (file-symlink-p (car args)))))))
+ (eshell-shorthand-tar-command ,command args)
+ (let ((target (car (last args)))
+ ange-cache)
+ (setcdr (last args 2) nil)
+ (eshell-shuffle-files
+ ,command ,action args target ,func nil
+ ,@(append
+ `((if (and (or interactive
+ ,query-var)
+ (not force))
+ 1 (or force ,force-var)))
+ (if preserve
+ (list preserve)))))
+ nil)))
(defun eshell/mv (&rest args)
"Implementation of mv in Lisp."
@@ -455,6 +469,7 @@ Remove the DIRECTORY(ies), if they are empty.")
(?v "verbose" nil verbose
"explain what is being done")
(nil "help" nil nil "show this usage screen")
+ :preserve-args
:external "mv"
:show-usage
:usage "[OPTION]... SOURCE DEST
@@ -462,9 +477,9 @@ Remove the DIRECTORY(ies), if they are empty.")
Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
\[OPTION] DIRECTORY...")
(let ((no-dereference t))
- (eshell-mvcp-template "mv" "moving" 'rename-file
- eshell-mv-interactive-query
- eshell-mv-overwrite-files))))
+ (eshell-mvcpln-template "mv" "moving" 'rename-file
+ eshell-mv-interactive-query
+ eshell-mv-overwrite-files))))
(defun eshell/cp (&rest args)
"Implementation of cp in Lisp."
@@ -487,6 +502,7 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
(?v "verbose" nil verbose
"explain what is being done")
(nil "help" nil nil "show this usage screen")
+ :preserve-args
:external "cp"
:show-usage
:usage "[OPTION]... SOURCE DEST
@@ -494,9 +510,9 @@ Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.
Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
(if archive
(setq preserve t no-dereference t recursive t))
- (eshell-mvcp-template "cp" "copying" 'copy-file
- eshell-cp-interactive-query
- eshell-cp-overwrite-files preserve)))
+ (eshell-mvcpln-template "cp" "copying" 'copy-file
+ eshell-cp-interactive-query
+ eshell-cp-overwrite-files preserve)))
(defun eshell/ln (&rest args)
"Implementation of ln in Lisp."
@@ -505,11 +521,13 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.")
'((?h "help" nil nil "show this usage screen")
(?s "symbolic" nil symbolic
"make symbolic links instead of hard links")
- (?i "interactive" nil interactive "request confirmation if target already exists")
+ (?i "interactive" nil interactive
+ "request confirmation if target already exists")
(?f "force" nil force "remove existing destinations, never prompt")
(?n "preview" nil preview
"don't change anything on disk")
(?v "verbose" nil verbose "explain what is being done")
+ :preserve-args
:external "ln"
:show-usage
:usage "[OPTION]... TARGET [LINK_NAME]
@@ -518,27 +536,19 @@ Create a link to the specified TARGET with optional LINK_NAME. If there is
more than one TARGET, the last argument must be a directory; create links
in DIRECTORY to each TARGET. Create hard links by default, symbolic links
with '--symbolic'. When creating hard links, each TARGET must exist.")
- (let (target no-dereference ange-cache)
- (if (> (length args) 1)
- (progn
- (setq target (car (last args)))
- (setcdr (last args 2) nil))
- (setq args nil))
- (eshell-shuffle-files "ln" "linking" args target
- (if symbolic
- 'make-symbolic-link
- 'add-name-to-file) nil
- (if (and (or interactive
- eshell-ln-interactive-query)
- (not force))
- 1 (or force eshell-ln-overwrite-files))))
- nil))
+ (let ((no-dereference t))
+ (eshell-mvcpln-template "ln" "linking"
+ (if symbolic
+ 'make-symbolic-link
+ 'add-name-to-file)
+ eshell-ln-interactive-query
+ eshell-ln-overwrite-files))))
(defun eshell/cat (&rest args)
"Implementation of cat in Lisp.
If in a pipeline, or the file is not a regular file, directory or
symlink, then revert to the system's definition of cat."
- (setq args (eshell-flatten-list args))
+ (setq args (eshell-stringify-list (eshell-flatten-list args)))
(if (or eshell-in-pipeline-p
(catch 'special
(eshell-for arg args
@@ -593,7 +603,8 @@ Concatenate FILE(s), or standard input, to standard output.")
(list 'quote (eshell-copy-environment))))))
(compile (concat "make " (eshell-flatten-and-stringify args))))
(throw 'eshell-replace-command
- (eshell-parse-command "*make" (eshell-flatten-list args)))))
+ (eshell-parse-command "*make" (eshell-stringify-list
+ (eshell-flatten-list args))))))
(defun eshell-occur-mode-goto-occurrence ()
"Go to the occurrence the current line describes."
@@ -627,7 +638,8 @@ available..."
(default-directory default-dir))
(erase-buffer)
(occur-mode)
- (let ((files (eshell-flatten-list (cdr args)))
+ (let ((files (eshell-stringify-list
+ (eshell-flatten-list (cdr args))))
(inhibit-redisplay t)
string)
(when (car args)
@@ -670,14 +682,16 @@ external command."
(not eshell-in-subcommand-p))))
(throw 'eshell-replace-command
(eshell-parse-command (concat "*" command)
- (eshell-flatten-list args)))
+ (eshell-stringify-list
+ (eshell-flatten-list args))))
(let* ((compilation-process-setup-function
(list 'lambda nil
(list 'setq 'process-environment
(list 'quote (eshell-copy-environment)))))
(args (mapconcat 'identity
(mapcar 'shell-quote-argument
- (eshell-flatten-list args))
+ (eshell-stringify-list
+ (eshell-flatten-list args)))
" "))
(cmd (progn
(set-text-properties 0 (length args)
@@ -797,7 +811,7 @@ external command."
(defun eshell/du (&rest args)
"Implementation of \"du\" in Lisp, passing ARGS."
(setq args (if args
- (eshell-flatten-list args)
+ (eshell-stringify-list (eshell-flatten-list args))
'(".")))
(let ((ext-du (eshell-search-path "du")))
(if (and ext-du
@@ -909,7 +923,7 @@ Show wall-clock time elapsed during execution of COMMAND.")
(defun eshell/diff (&rest args)
"Alias \"diff\" to call Emacs `diff' function."
- (let ((orig-args (eshell-flatten-list args)))
+ (let ((orig-args (eshell-stringify-list (eshell-flatten-list args))))
(if (or eshell-plain-diff-behavior
(not (and (eshell-interactive-output-p)
(not eshell-in-pipeline-p)
@@ -951,7 +965,8 @@ Show wall-clock time elapsed during execution of COMMAND.")
(and (stringp (car args))
(string-match "^-" (car args))))
(throw 'eshell-replace-command
- (eshell-parse-command "*locate" (eshell-flatten-list args)))
+ (eshell-parse-command "*locate" (eshell-stringify-list
+ (eshell-flatten-list args))))
(save-selected-window
(let ((locate-history-list (list (car args))))
(locate-with-filter (car args) (cadr args))))))
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 6d2ede0a72c..7d5a53625f5 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -203,6 +203,21 @@ which may be modified directly. Any return value is ignored."
:type 'hook
:group 'eshell-cmd)
+(defcustom eshell-complex-commands nil
+ "*A list of commands names or functions, that determine complexity.
+That is, if a command is defined by a function named eshell/NAME,
+and NAME is part of this list, it is invoked as a complex command.
+Complex commands are always correct, but run much slower. If a
+command works fine without being part of this list, then it doesn't
+need to be.
+
+If an entry is a function, it will be called with the name, and should
+return non-nil if the command is complex."
+ :type '(repeat :tag "Commands"
+ (choice (string :tag "Name")
+ (function :tag "Predicate")))
+ :group 'eshell-cmd)
+
;;; Code:
(require 'esh-util)
@@ -518,8 +533,8 @@ implemented via rewriting, rather than as a function."
(list 'car
(list 'symbol-value
(list 'quote 'for-items)))))
- (list 'eshell-copy-handles
- (eshell-invokify-arg body t)))
+ (list 'eshell-protect
+ (eshell-invokify-arg body t)))
(list 'setcar 'for-items
(list 'cadr
(list 'symbol-value
@@ -583,7 +598,7 @@ must be implemented via rewriting, rather than as a function."
(eshell-structure-basic-command
'while '("while" "until") (car terms)
(eshell-invokify-arg (cadr terms) nil t)
- (list 'eshell-copy-handles
+ (list 'eshell-protect
(eshell-invokify-arg (car (last terms)) t)))))
(defun eshell-rewrite-if-command (terms)
@@ -596,13 +611,15 @@ must be implemented via rewriting, rather than as a function."
(eshell-structure-basic-command
'if '("if" "unless") (car terms)
(eshell-invokify-arg (cadr terms) nil t)
- (eshell-invokify-arg
- (if (= (length terms) 5)
- (car (last terms 3))
- (car (last terms))) t)
- (eshell-invokify-arg
- (if (= (length terms) 5)
- (car (last terms))) t))))
+ (list 'eshell-protect
+ (eshell-invokify-arg
+ (if (= (length terms) 5)
+ (car (last terms 3))
+ (car (last terms))) t))
+ (if (= (length terms) 5)
+ (list 'eshell-protect
+ (eshell-invokify-arg
+ (car (last terms)))) t))))
(defun eshell-exit-success-p ()
"Return non-nil if the last command was \"successful\".
@@ -651,8 +668,8 @@ For an external command, it means an exit code of 0."
(assert (car sep-terms))
(setq final (eshell-structure-basic-command
'if (string= (car sep-terms) "&&") "if"
- (list 'eshell-commands (car results))
- final
+ (list 'eshell-protect (car results))
+ (list 'eshell-protect final)
nil t)
results (cdr results)
sep-terms (cdr sep-terms)))
@@ -690,8 +707,8 @@ For an external command, it means an exit code of 0."
(list 'eshell-lisp-command (list 'quote obj)))
(ignore (goto-char here))))))
-(defun eshell-separate-commands
- (terms separator &optional reversed last-terms-sym)
+(defun eshell-separate-commands (terms separator &optional
+ reversed last-terms-sym)
"Separate TERMS using SEPARATOR.
If REVERSED is non-nil, the list of separated term groups will be
returned in reverse order. If LAST-TERMS-SYM is a symbol, it's value
@@ -772,21 +789,6 @@ this grossness will be made to disappear by using `call/cc'..."
(eshell-errorn (error-message-string err))
(eshell-close-handles 1)))))
-;; (defun eshell-copy-or-protect-handles ()
-;; (if (eshell-processp (car (aref eshell-current-handles
-;; eshell-output-handle)))
-;; (eshell-protect-handles eshell-current-handles)
-;; (eshell-create-handles
-;; (car (aref eshell-current-handles
-;; eshell-output-handle)) nil
-;; (car (aref eshell-current-handles
-;; eshell-error-handle)) nil)))
-
-;; (defmacro eshell-copy-handles (object)
-;; "Duplicate current I/O handles, so OBJECT works with its own copy."
-;; `(let ((eshell-current-handles (eshell-copy-or-protect-handles)))
-;; ,object))
-
(defmacro eshell-copy-handles (object)
"Duplicate current I/O handles, so OBJECT works with its own copy."
`(let ((eshell-current-handles
@@ -965,6 +967,22 @@ at the moment are:
(if subform
(concat "\n\n" (eshell-stringify subform)) ""))))))
+(defun eshell-invoke-directly (command input)
+ (let ((base (cadr (nth 2 (nth 2 (cadr command))))) name)
+ (if (and (eq (car base) 'eshell-trap-errors)
+ (eq (car (cadr base)) 'eshell-named-command))
+ (setq name (cadr (cadr base))))
+ (and name (stringp name)
+ (not (member name eshell-complex-commands))
+ (catch 'simple
+ (progn
+ (eshell-for pred eshell-complex-commands
+ (if (and (functionp pred)
+ (funcall pred name))
+ (throw 'simple nil)))
+ t))
+ (fboundp (intern-soft (concat "eshell/" name))))))
+
(defun eshell-eval-command (command &optional input)
"Evaluate the given COMMAND iteratively."
(if eshell-current-command
@@ -1163,29 +1181,29 @@ be finished later after the completion of an asynchronous subprocess."
((eq (car form) 'prog1)
(cadr form))
(t
+ ;; If a command desire to replace its execution form with
+ ;; another command form, all it needs to do is throw the new
+ ;; form using the exception tag `eshell-replace-command'.
+ ;; For example, let's say that the form currently being
+ ;; eval'd is:
+ ;;
+ ;; (eshell-named-command "hello")
+ ;;
+ ;; Now, let's assume the 'hello' command is an Eshell alias,
+ ;; the definition of which yields the command:
+ ;;
+ ;; (eshell-named-command "echo" (list "Hello" "world"))
+ ;;
+ ;; What the alias code would like to do is simply substitute
+ ;; the alias form for the original form. To accomplish
+ ;; this, all it needs to do is to throw the substitution
+ ;; form with the `eshell-replace-command' tag, and the form
+ ;; will be replaced within the current command, and
+ ;; execution will then resume (iteratively) as before.
+ ;; Thus, aliases can even contain references to asynchronous
+ ;; sub-commands, and things will still work out as they
+ ;; should.
(let (result new-form)
- ;; If a command desire to replace its execution form with
- ;; another command form, all it needs to do is throw the
- ;; new form using the exception tag
- ;; `eshell-replace-command'. For example, let's say that
- ;; the form currently being eval'd is:
- ;;
- ;; (eshell-named-command \"hello\")
- ;;
- ;; Now, let's assume the 'hello' command is an Eshell
- ;; alias, the definition of which yields the command:
- ;;
- ;; (eshell-named-command \"echo\" (list \"Hello\" \"world\"))
- ;;
- ;; What the alias code would like to do is simply
- ;; substitute the alias form for the original form. To
- ;; accomplish this, all it needs to do is to throw the
- ;; substitution form with the `eshell-replace-command'
- ;; tag, and the form will be replaced within the current
- ;; command, and execution will then resume (iteratively)
- ;; as before. Thus, aliases can even contain references
- ;; to asynchronous sub-commands, and things will still
- ;; work out as they should.
(if (setq new-form
(catch 'eshell-replace-command
(ignore
diff --git a/lisp/eshell/esh-groups.el b/lisp/eshell/esh-groups.el
index 218bd2a2e52..d82cdff4ffd 100644
--- a/lisp/eshell/esh-groups.el
+++ b/lisp/eshell/esh-groups.el
@@ -132,4 +132,3 @@ functions, or as aliases which make some of Emacs' behavior more
naturally accessible within Emacs."
:tag "Extra alias functions"
:group 'eshell-module)
-
diff --git a/lisp/eshell/esh-maint.el b/lisp/eshell/esh-maint.el
index 13b3597b4ce..89e50401c67 100644
--- a/lisp/eshell/esh-maint.el
+++ b/lisp/eshell/esh-maint.el
@@ -48,7 +48,7 @@
;; (interactive)
;; (require 'autoload)
;; (setq generated-autoload-file
-;; (expand-file-name (car command-line-args-left)))
+;; (expand-file-name (car command-line-args-left)))
;; (setq command-line-args-left (cdr command-line-args-left))
;; (batch-update-autoloads))
@@ -65,23 +65,23 @@
;; Core Functionality\n")
;; (eshell-for module
;; (sort (eshell-subgroups 'eshell)
-;; (function
-;; (lambda (a b)
-;; (string-lessp (symbol-name a)
-;; (symbol-name b)))))
+;; (function
+;; (lambda (a b)
+;; (string-lessp (symbol-name a)
+;; (symbol-name b)))))
;; (insert (format "* %-34s"
-;; (concat (get module 'custom-tag) "::"))
-;; (symbol-name module) ".\n"))
+;; (concat (get module 'custom-tag) "::"))
+;; (symbol-name module) ".\n"))
;; (insert "\nOptional Functionality\n")
;; (eshell-for module
;; (sort (eshell-subgroups 'eshell-module)
-;; (function
-;; (lambda (a b)
-;; (string-lessp (symbol-name a)
-;; (symbol-name b)))))
+;; (function
+;; (lambda (a b)
+;; (string-lessp (symbol-name a)
+;; (symbol-name b)))))
;; (insert (format "* %-34s"
-;; (concat (get module 'custom-tag) "::"))
-;; (symbol-name module) ".\n"))
+;; (concat (get module 'custom-tag) "::"))
+;; (symbol-name module) ".\n"))
;; (insert "@end menu\n"))
;; (defun eshell-make-texi ()
@@ -91,27 +91,27 @@
;; (require 'texidoc)
;; (require 'pcomplete)
;; (apply 'texidoc-files 'eshell-generate-main-menu "eshell.doci"
-;; (append
-;; (list "eshell.el")
-;; (sort (mapcar
-;; (function
-;; (lambda (sym)
-;; (let ((name (symbol-name sym)))
-;; (if (string-match "\\`eshell-\\(.*\\)" name)
-;; (setq name (concat "esh-" (match-string 1 name))))
-;; (concat name ".el"))))
-;; (eshell-subgroups 'eshell))
-;; 'string-lessp)
-;; (sort (mapcar
-;; (function
-;; (lambda (sym)
-;; (let ((name (symbol-name sym)))
-;; (if (string-match "\\`eshell-\\(.*\\)" name)
-;; (setq name (concat "em-" (match-string 1 name))))
-;; (concat name ".el"))))
-;; (eshell-subgroups 'eshell-module))
-;; 'string-lessp)
-;; (list "eshell.texi"))))
+;; (append
+;; (list "eshell.el")
+;; (sort (mapcar
+;; (function
+;; (lambda (sym)
+;; (let ((name (symbol-name sym)))
+;; (if (string-match "\\`eshell-\\(.*\\)" name)
+;; (setq name (concat "esh-" (match-string 1 name))))
+;; (concat name ".el"))))
+;; (eshell-subgroups 'eshell))
+;; 'string-lessp)
+;; (sort (mapcar
+;; (function
+;; (lambda (sym)
+;; (let ((name (symbol-name sym)))
+;; (if (string-match "\\`eshell-\\(.*\\)" name)
+;; (setq name (concat "em-" (match-string 1 name))))
+;; (concat name ".el"))))
+;; (eshell-subgroups 'eshell-module))
+;; 'string-lessp)
+;; (list "eshell.texi"))))
;; (defun eshell-make-readme ()
;; "Make the README file from eshell.el."
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index ad513c47a0b..5da511626c5 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -180,9 +180,7 @@ inserted. They return the string as it should be inserted."
:group 'eshell-mode)
(defcustom eshell-password-prompt-regexp
- "\\(\\([Oo]ld \\|[Nn]ew \\|Kerberos \\|CVS \\|'s \\|login \\|^\\)\
-[Pp]assword\\|pass phrase\\|\\(Enter\\|Repeat\\) passphrase\\)\
-\\( for [^@ \t\n]+@[^@ \t\n]+\\)?:\\s *\\'"
+ "[Pp]ass\\(word\\|phrase\\).*:\\s *\\'"
"*Regexp matching prompts for passwords in the inferior process.
This is used by `eshell-watch-for-password-prompt'."
:type 'regexp
@@ -462,7 +460,8 @@ sessions, such as when using `eshell-command'.")
(eshell-deftest var window-height
"LINES equals window height"
- (eshell-command-result-p "= $LINES (window-height)" "t\n"))
+ (let ((eshell-stringify-t t))
+ (eshell-command-result-p "= $LINES (window-height)" "t\n")))
(defun eshell-command-started ()
"Indicate in the modeline that a command has started."
@@ -736,7 +735,9 @@ newline."
(run-hooks 'eshell-input-filter-functions)
(and (catch 'eshell-terminal
(ignore
- (eshell-eval-command cmd input)))
+ (if (eshell-invoke-directly cmd input)
+ (eval cmd)
+ (eshell-eval-command cmd input))))
(eshell-life-is-too-much)))))
(quit
(eshell-reset t)
diff --git a/lisp/eshell/esh-module.el b/lisp/eshell/esh-module.el
index 3eab199201e..f09f1ac7b24 100644
--- a/lisp/eshell/esh-module.el
+++ b/lisp/eshell/esh-module.el
@@ -24,7 +24,9 @@
(provide 'esh-module)
-(eval-when-compile (require 'esh-maint) (require 'cl))
+(eval-when-compile
+ (require 'esh-maint)
+ (require 'cl))
(defgroup eshell-module nil
"The `eshell-module' group is for Eshell extension modules, which
@@ -85,7 +87,7 @@ customizing the variable `eshell-modules-list'."
(equal (file-name-nondirectory byte-compile-current-file)
"esh-modu.el"))))
(let* ((directory (file-name-directory byte-compile-current-file))
- (elc-file (expand-file-name "esh-groups.elc" directory)))
+ (elc-file (expand-file-name "esh-groups.elc" directory)))
(eshell-load-defgroups directory)
(if (file-exists-p elc-file) (delete-file elc-file)))))
diff --git a/lisp/eshell/esh-test.el b/lisp/eshell/esh-test.el
index 6a14541ab39..acfb409da57 100644
--- a/lisp/eshell/esh-test.el
+++ b/lisp/eshell/esh-test.el
@@ -173,12 +173,12 @@
system-configuration
(cond ((featurep 'motif) ", Motif")
((featurep 'x-toolkit) ", X toolkit")
- (t ""))) "\n")
+ (t ""))))
(switch-to-buffer test-buffer)
(delete-other-windows))
- (eshell-for funcname
- (sort (all-completions "eshell-test--" obarray 'functionp)
- 'string-lessp)
+ (eshell-for funcname (sort (all-completions "eshell-test--"
+ obarray 'functionp)
+ 'string-lessp)
(with-current-buffer test-buffer
(insert "\n"))
(funcall (intern-soft funcname)))
diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el
index 01c0ff2c76e..3d8dedc6bae 100644
--- a/lisp/eshell/esh-util.el
+++ b/lisp/eshell/esh-util.el
@@ -36,6 +36,14 @@
;;; User Variables:
+(defcustom eshell-stringify-t t
+ "*If non-nil, the string representation of t is 't'.
+If nil, t will be represented only in the exit code of the function,
+and not printed as a string. This causes Lisp functions to behave
+similarly to external commands, as far as successful result output."
+ :type 'boolean
+ :group 'eshell-util)
+
(defcustom eshell-group-file "/etc/group"
"*If non-nil, the name of the group file on your system."
:type '(choice (const :tag "No group file" nil) file)
@@ -305,7 +313,9 @@ If N or M is nil, it means the end of the list."
((numberp object)
(number-to-string object))
(t
- (pp-to-string object))))
+ (unless (and (eq object t)
+ (not eshell-stringify-t))
+ (pp-to-string object)))))
(defsubst eshell-stringify-list (args)
"Convert each element of ARGS into a string value."
@@ -611,7 +621,7 @@ Unless optional argument INPLACE is non-nil, return a new string."
(autoload 'parse-time-string "parse-time"))
(eval-when-compile
- (require 'ange-ftp))
+ (load "ange-ftp" t))
(defun eshell-parse-ange-ls (dir)
(let (entry)