diff options
Diffstat (limited to 'lisp/eshell')
-rw-r--r-- | lisp/eshell/em-basic.el | 2 | ||||
-rw-r--r-- | lisp/eshell/em-cmpl.el | 7 | ||||
-rw-r--r-- | lisp/eshell/em-dirs.el | 31 | ||||
-rw-r--r-- | lisp/eshell/em-hist.el | 72 | ||||
-rw-r--r-- | lisp/eshell/em-ls.el | 40 | ||||
-rw-r--r-- | lisp/eshell/em-pred.el | 19 | ||||
-rw-r--r-- | lisp/eshell/em-prompt.el | 1 | ||||
-rw-r--r-- | lisp/eshell/em-script.el | 2 | ||||
-rw-r--r-- | lisp/eshell/em-term.el | 2 | ||||
-rw-r--r-- | lisp/eshell/em-tramp.el | 6 | ||||
-rw-r--r-- | lisp/eshell/em-unix.el | 73 | ||||
-rw-r--r-- | lisp/eshell/em-xtra.el | 8 | ||||
-rw-r--r-- | lisp/eshell/esh-cmd.el | 2 | ||||
-rw-r--r-- | lisp/eshell/esh-ext.el | 4 | ||||
-rw-r--r-- | lisp/eshell/esh-mode.el | 6 | ||||
-rw-r--r-- | lisp/eshell/esh-opt.el | 38 | ||||
-rw-r--r-- | lisp/eshell/esh-proc.el | 11 | ||||
-rw-r--r-- | lisp/eshell/esh-util.el | 23 | ||||
-rw-r--r-- | lisp/eshell/esh-var.el | 2 |
19 files changed, 194 insertions, 155 deletions
diff --git a/lisp/eshell/em-basic.el b/lisp/eshell/em-basic.el index 346fb1c17b0..72a4e6bf801 100644 --- a/lisp/eshell/em-basic.el +++ b/lisp/eshell/em-basic.el @@ -118,7 +118,7 @@ or `eshell-printn' for display." (defun eshell/printnl (&rest args) "Print out each of the arguments, separated by newlines." - (let ((elems (eshell-flatten-list args))) + (let ((elems (flatten-tree args))) (while elems (eshell-printn (eshell-echo (list (car elems)))) (setq elems (cdr elems))))) diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el index f834882f7b6..cd5c14afbe6 100644 --- a/lisp/eshell/em-cmpl.el +++ b/lisp/eshell/em-cmpl.el @@ -262,8 +262,9 @@ to writing a completion function." eshell-cmpl-ignore-case) (set (make-local-variable 'pcomplete-autolist) eshell-cmpl-autolist) - (set (make-local-variable 'pcomplete-suffix-list) - eshell-cmpl-suffix-list) + (if (boundp 'pcomplete-suffix-list) + (set (make-local-variable 'pcomplete-suffix-list) + eshell-cmpl-suffix-list)) (set (make-local-variable 'pcomplete-recexact) eshell-cmpl-recexact) (set (make-local-variable 'pcomplete-man-function) @@ -437,7 +438,7 @@ to writing a completion function." (setq comps-in-path (cdr comps-in-path))) (setq paths (cdr paths))) ;; Add aliases which are currently visible, and Lisp functions. - (pcomplete-uniqify-list + (pcomplete-uniquify-list (if glob-name completions (setq completions diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el index 4d8debb954f..8e79189acf5 100644 --- a/lisp/eshell/em-dirs.el +++ b/lisp/eshell/em-dirs.el @@ -207,7 +207,7 @@ Thus, this does not include the current directory.") (when eshell-cd-on-directory (make-local-variable 'eshell-interpreter-alist) (setq eshell-interpreter-alist - (cons (cons #'(lambda (file args) + (cons (cons #'(lambda (file _args) (eshell-lone-directory-p file)) 'eshell-dirs-substitute-cd) eshell-interpreter-alist))) @@ -259,7 +259,7 @@ Thus, this does not include the current directory.") (if (> (length args) 1) (error "%s: command not found" (car args)) (throw 'eshell-replace-command - (eshell-parse-command "cd" (eshell-flatten-list args))))) + (eshell-parse-command "cd" (flatten-tree args))))) (defun eshell-parse-user-reference () "An argument beginning with ~ is a filename to be expanded." @@ -282,7 +282,7 @@ Thus, this does not include the current directory.") (defvar pcomplete-stub) (defvar pcomplete-last-completion-raw) (declare-function pcomplete-actual-arg "pcomplete") -(declare-function pcomplete-uniqify-list "pcomplete") +(declare-function pcomplete-uniquify-list "pcomplete") (defun eshell-complete-user-reference () "If there is a user reference, complete it." @@ -293,14 +293,14 @@ Thus, this does not include the current directory.") (throw 'pcomplete-completions (progn (eshell-read-user-names) - (pcomplete-uniqify-list + (pcomplete-uniquify-list (mapcar (function (lambda (user) (file-name-as-directory (cdr user)))) eshell-user-names))))))) -(defun eshell/pwd (&rest args) +(defun eshell/pwd (&rest _args) "Change output from `pwd' to be cleaner." (let* ((path default-directory) (len (length path))) @@ -314,16 +314,18 @@ Thus, this does not include the current directory.") path))) (defun eshell-expand-multiple-dots (path) + ;; FIXME: This advice recommendation is rather odd: it's somewhat + ;; dangerous and it claims not to work with minibuffer-completion, which + ;; makes it much less interesting. "Convert `...' to `../..', `....' to `../../..', etc.. With the following piece of advice, you can make this functionality available in most of Emacs, with the exception of filename completion in the minibuffer: - (defadvice expand-file-name - (before translate-multiple-dots - (filename &optional directory) activate) - (setq filename (eshell-expand-multiple-dots filename)))" + (advice-add 'expand-file-name :around #'my-expand-multiple-dots) + (defun my-expand-multiple-dots (orig-fun filename &rest args) + (apply orig-fun (eshell-expand-multiple-dots filename) args))" (while (string-match "\\(?:^\\|/\\)\\.\\.\\(\\.+\\)\\(?:$\\|/\\)" path) (let* ((extra-dots (match-string 1 path)) (len (length extra-dots)) @@ -351,7 +353,7 @@ in the minibuffer: (defun eshell/cd (&rest args) ; all but first ignored "Alias to extend the behavior of `cd'." - (setq args (eshell-flatten-list args)) + (setq args (flatten-tree args)) (let ((path (car args)) (subpath (car (cdr args))) (case-fold-search (eshell-under-windows-p)) @@ -550,15 +552,16 @@ in the minibuffer: (defun eshell-write-last-dir-ring () "Write the buffer's `eshell-last-dir-ring' to a history file." - (let ((file eshell-last-dir-ring-file-name)) + (let* ((file eshell-last-dir-ring-file-name) + (resolved-file (if (stringp file) (file-truename file)))) (cond ((or (null file) (equal file "") (null eshell-last-dir-ring) (ring-empty-p eshell-last-dir-ring)) nil) - ((not (file-writable-p file)) - (message "Cannot write last-dir-ring file %s" file)) + ((not (file-writable-p resolved-file)) + (message "Cannot write last-dir-ring file %s" resolved-file)) (t (let* ((ring eshell-last-dir-ring) (index (ring-length ring))) @@ -568,7 +571,7 @@ in the minibuffer: (insert (ring-ref ring index) ?\n)) (insert (eshell/pwd) ?\n) (eshell-with-private-file-modes - (write-region (point-min) (point-max) file nil + (write-region (point-min) (point-max) resolved-file nil 'no-message)))))))) (provide 'em-dirs) diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el index f0aee6909ea..05579eed32a 100644 --- a/lisp/eshell/em-hist.el +++ b/lisp/eshell/em-hist.el @@ -218,9 +218,6 @@ Returns nil if INPUT is prepended by blank space, otherwise non-nil." (defun eshell-hist-initialize () "Initialize the history management code for one Eshell buffer." - (add-hook 'eshell-expand-input-functions - 'eshell-expand-history-references nil t) - (when (eshell-using-module 'eshell-cmpl) (add-hook 'pcomplete-try-first-hook 'eshell-complete-history-reference nil t)) @@ -469,15 +466,16 @@ lost if `eshell-history-ring' is not empty. If Useful within process sentinels. See also `eshell-read-history'." - (let ((file (or filename eshell-history-file-name))) + (let* ((file (or filename eshell-history-file-name)) + (resolved-file (if (stringp file) (file-truename file)))) (cond ((or (null file) (equal file "") (null eshell-history-ring) (ring-empty-p eshell-history-ring)) nil) - ((not (file-writable-p file)) - (message "Cannot write history file %s" file)) + ((not (file-writable-p resolved-file)) + (message "Cannot write history file %s" resolved-file)) (t (let* ((ring eshell-history-ring) (index (ring-length ring))) @@ -492,7 +490,7 @@ See also `eshell-read-history'." (insert (substring-no-properties (ring-ref ring index)) ?\n) (subst-char-in-region start (1- (point)) ?\n ?\177))) (eshell-with-private-file-modes - (write-region (point-min) (point-max) file append + (write-region (point-min) (point-max) resolved-file append 'no-message)))))))) (defun eshell-list-history () @@ -584,21 +582,30 @@ See also `eshell-read-history'." (defun eshell-expand-history-references (beg end) "Parse and expand any history references in current input." - (let ((result (eshell-hist-parse-arguments beg end))) + (let ((result (eshell-hist-parse-arguments beg end)) + (full-line (buffer-substring-no-properties beg end))) (when result (let ((textargs (nreverse (nth 0 result))) (posb (nreverse (nth 1 result))) - (pose (nreverse (nth 2 result)))) + (pose (nreverse (nth 2 result))) + (full-line-subst (eshell-history-substitution full-line))) (save-excursion - (while textargs - (let ((str (eshell-history-reference (car textargs)))) - (unless (eq str (car textargs)) - (goto-char (car posb)) - (insert-and-inherit str) - (delete-char (- (car pose) (car posb))))) - (setq textargs (cdr textargs) - posb (cdr posb) - pose (cdr pose)))))))) + (if full-line-subst + ;; Found a ^foo^bar substitution + (progn + (goto-char beg) + (insert-and-inherit full-line-subst) + (delete-char (- end beg))) + ;; Try to expand other substitutions + (while textargs + (let ((str (eshell-history-reference (car textargs)))) + (unless (eq str (car textargs)) + (goto-char (car posb)) + (insert-and-inherit str) + (delete-char (- (car pose) (car posb))))) + (setq textargs (cdr textargs) + posb (cdr posb) + pose (cdr pose))))))))) (defvar pcomplete-stub) (defvar pcomplete-last-completion-raw) @@ -633,20 +640,31 @@ See also `eshell-read-history'." (setq history (cdr history))) (cdr fhist))))))) +(defun eshell-history-substitution (line) + "Expand quick hist substitutions formatted as ^foo^bar^. +Returns nil if string does not match quick substitution format, +and acts like !!:s/foo/bar/ otherwise." + ;; `^string1^string2^' + ;; Quick Substitution. Repeat the last command, replacing + ;; STRING1 with STRING2. Equivalent to `!!:s/string1/string2/' + (when (and (eshell-using-module 'eshell-pred) + (string-match + "^\\^\\([^^]+\\)\\^\\([^^]+\\)\\(?:\\^\\(.*\\)\\)?$" + line)) + ;; Save trailing match as `eshell-history-reference' runs string-match. + (let ((matched-end (match-string 3 line))) + (concat + (eshell-history-reference + (format "!!:s/%s/%s/" + (match-string 1 line) + (match-string 2 line))) + matched-end)))) + (defun eshell-history-reference (reference) "Expand directory stack REFERENCE. The syntax used here was taken from the Bash info manual. Returns the resultant reference, or the same string REFERENCE if none matched." - ;; `^string1^string2^' - ;; Quick Substitution. Repeat the last command, replacing - ;; STRING1 with STRING2. Equivalent to `!!:s/string1/string2/' - (if (and (eshell-using-module 'eshell-pred) - (string-match "\\^\\([^^]+\\)\\^\\([^^]+\\)\\^?\\s-*$" - reference)) - (setq reference (format "!!:s/%s/%s/" - (match-string 1 reference) - (match-string 2 reference)))) ;; `!' ;; Start a history substitution, except when followed by a ;; space, tab, the end of the line, = or (. diff --git a/lisp/eshell/em-ls.el b/lisp/eshell/em-ls.el index a4118a0da30..5e4bbdc87ef 100644 --- a/lisp/eshell/em-ls.el +++ b/lisp/eshell/em-ls.el @@ -183,9 +183,9 @@ really need to stick around for very long." "The face used for highlighting junk file names.") (defsubst eshell-ls-filetype-p (attrs type) - "Test whether ATTRS specifies a directory." - (if (nth 8 attrs) - (eq (aref (nth 8 attrs) 0) type))) + "Test whether ATTRS specifies a file of type TYPE." + (if (file-attribute-modes attrs) + (eq (aref (file-attribute-modes attrs) 0) type))) (defmacro eshell-ls-applicable (attrs index func file) "Test whether, for ATTRS, the user can do what corresponds to INDEX. @@ -193,8 +193,8 @@ ATTRS is a string of file modes. See `file-attributes'. If we cannot determine the answer using ATTRS (e.g., if we need to know what group the user is in), compute the return value by calling FUNC with FILE as an argument." - `(let ((owner (nth 2 ,attrs)) - (modes (nth 8 ,attrs))) + `(let ((owner (file-attribute-user-id ,attrs)) + (modes (file-attribute-modes ,attrs))) (cond ((cond ((numberp owner) (= owner (user-uid))) ((stringp owner) @@ -346,7 +346,7 @@ instead." "ls" (if eshell-ls-initial-args (list eshell-ls-initial-args args) args) - `((?a "all" nil show-all + '((?a "all" nil show-all "do not ignore entries starting with .") (?A "almost-all" nil show-almost-all "do not list implied . and ..") @@ -437,7 +437,7 @@ Sort entries alphabetically across.") (defsubst eshell-ls-size-string (attrs size-width) "Return the size string for ATTRS length, using SIZE-WIDTH." - (let* ((str (eshell-ls-printable-size (nth 7 attrs) t)) + (let* ((str (eshell-ls-printable-size (file-attribute-size attrs) t)) (len (length str))) (if (< len size-width) (concat (make-string (- size-width len) ? ) str) @@ -503,19 +503,19 @@ whose cdr is the list of file attributes." (if numeric-uid-gid "%s%4d %-8s %-8s " "%s%4d %-14s %-8s ") - (or (nth 8 attrs) "??????????") - (or (nth 1 attrs) 0) - (or (let ((user (nth 2 attrs))) + (or (file-attribute-modes attrs) "??????????") + (or (file-attribute-link-number attrs) 0) + (or (let ((user (file-attribute-user-id attrs))) (and (stringp user) (eshell-substring user 14))) - (nth 2 attrs) + (file-attribute-user-id attrs) "") - (or (let ((group (nth 3 attrs))) + (or (let ((group (file-attribute-group-id attrs))) (and (stringp group) (eshell-substring group 8))) - (nth 3 attrs) + (file-attribute-group-id attrs) "")) - (let* ((str (eshell-ls-printable-size (nth 7 attrs))) + (let* ((str (eshell-ls-printable-size (file-attribute-size attrs))) (len (length str))) ;; Let file sizes shorter than 9 align neatly. (if (< len (or size-width 8)) @@ -585,12 +585,12 @@ relative to that directory." (let ((total 0.0)) (setq size-width 0) (dolist (e entries) - (if (nth 7 (cdr e)) - (setq total (+ total (nth 7 (cdr e))) + (if (file-attribute-size (cdr e)) + (setq total (+ total (file-attribute-size (cdr e))) size-width (max size-width (length (eshell-ls-printable-size - (nth 7 (cdr e)) + (file-attribute-size (cdr e)) (not ;; If we are under -l, count length ;; of sizes in bytes, not in blocks. @@ -700,7 +700,7 @@ Each member of FILES is either a string or a cons cell of the form (if (not show-size) (setq display-files (mapcar 'eshell-ls-annotate files)) (dolist (file files) - (let* ((str (eshell-ls-printable-size (nth 7 (cdr file)) t)) + (let* ((str (eshell-ls-printable-size (file-attribute-size (cdr file)) t)) (len (length str))) (if (< len size-width) (setq str (concat (make-string (- size-width len) ? ) str))) @@ -766,14 +766,14 @@ need to be printed." (if show-size (max size-width (length (eshell-ls-printable-size - (nth 7 (cdr entry)) t)))))) + (file-attribute-size (cdr entry)) t)))))) (setq dirs (cons entry dirs))) (setq files (cons entry files) size-width (if show-size (max size-width (length (eshell-ls-printable-size - (nth 7 (cdr entry)) t))))))) + (file-attribute-size (cdr entry)) t))))))) (when files (eshell-ls-files (eshell-ls-sort-entries files) size-width show-recursive) diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el index bfabda0ec77..1cbd2367f53 100644 --- a/lisp/eshell/em-pred.el +++ b/lisp/eshell/em-pred.el @@ -89,10 +89,12 @@ ordinary strings." (?t . (eshell-pred-file-mode 1000)) ; sticky bit (?U . #'(lambda (file) ; owned by effective uid (if (file-exists-p file) - (= (nth 2 (file-attributes file)) (user-uid))))) + (= (file-attribute-user-id (file-attributes file)) + (user-uid))))) ;; (?G . #'(lambda (file) ; owned by effective gid ;; (if (file-exists-p file) - ;; (= (nth 2 (file-attributes file)) (user-uid))))) + ;; (= (file-attribute-user-id (file-attributes file)) + ;; (user-uid))))) (?* . #'(lambda (file) (and (file-regular-p file) (not (file-symlink-p file)) @@ -131,7 +133,7 @@ The format of each entry is (?e . #'(lambda (lst) (mapcar 'file-name-extension lst))) (?t . #'(lambda (lst) (mapcar 'file-name-nondirectory lst))) (?q . #'(lambda (lst) (mapcar 'eshell-escape-arg lst))) - (?u . #'(lambda (lst) (eshell-uniqify-list lst))) + (?u . #'(lambda (lst) (eshell-uniquify-list lst))) (?o . #'(lambda (lst) (sort lst 'string-lessp))) (?O . #'(lambda (lst) (nreverse (sort lst 'string-lessp)))) (?j . (eshell-join-members)) @@ -460,7 +462,7 @@ that `ls -l' will show in the first column of its display. " `(lambda (file) (let ((attrs (eshell-file-attributes (directory-file-name file)))) (if attrs - (memq (aref (nth 8 attrs) 0) + (memq (aref (file-attribute-modes attrs) 0) ,(if (eq type ?%) '(?b ?c) (list 'quote (list type)))))))) @@ -489,7 +491,8 @@ that `ls -l' will show in the first column of its display. " '< (if (eq qual ?+) '> - '=)) (nth 1 attrs) ,amount)))))) + '=)) + (file-attribute-link-number attrs) ,amount)))))) (defun eshell-pred-file-size () "Return a predicate to test whether a file is of a given size." @@ -518,7 +521,8 @@ that `ls -l' will show in the first column of its display. " '< (if (eq qual ?+) '> - '=)) (nth 7 attrs) ,amount)))))) + '=)) + (file-attribute-size attrs) ,amount)))))) (defun eshell-pred-substitute (&optional repeat) "Return a modifier function that will substitute matches." @@ -545,7 +549,8 @@ that `ls -l' will show in the first column of its display. " (function (lambda (str) (if (string-match ,match str) - (setq str (replace-match ,replace t nil str))) + (setq str (replace-match ,replace t nil str)) + (error (concat str ": substitution failed"))) str)) lst))))) (defun eshell-include-members (&optional invert-p) diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el index 3d15a441610..a3035205adb 100644 --- a/lisp/eshell/em-prompt.el +++ b/lisp/eshell/em-prompt.el @@ -80,7 +80,6 @@ re-entered for it to take effect." For highlighting other kinds of strings -- similar to shell mode's behavior -- simply use an output filer which changes text properties." :group 'eshell-prompt) -(define-obsolete-face-alias 'eshell-prompt-face 'eshell-prompt "22.1") (defcustom eshell-before-prompt-hook nil "A list of functions to call before outputting the prompt." diff --git a/lisp/eshell/em-script.el b/lisp/eshell/em-script.el index b8a5ecd9002..bab26222baf 100644 --- a/lisp/eshell/em-script.el +++ b/lisp/eshell/em-script.el @@ -61,7 +61,7 @@ This includes when running `eshell-command'." "Initialize the script parsing code." (make-local-variable 'eshell-interpreter-alist) (setq eshell-interpreter-alist - (cons (cons #'(lambda (file args) + (cons (cons #'(lambda (file _args) (string= (file-name-nondirectory file) "eshell")) 'eshell/source) diff --git a/lisp/eshell/em-term.el b/lisp/eshell/em-term.el index 1013bd2b89a..8af783eaf80 100644 --- a/lisp/eshell/em-term.el +++ b/lisp/eshell/em-term.el @@ -175,7 +175,7 @@ allowed." (let* (eshell-interpreter-alist (interp (eshell-find-interpreter (car args) (cdr args))) (program (car interp)) - (args (eshell-flatten-list + (args (flatten-tree (eshell-stringify-list (append (cdr interp) (cdr args))))) (term-buf diff --git a/lisp/eshell/em-tramp.el b/lisp/eshell/em-tramp.el index 81324800aef..603b7627d5d 100644 --- a/lisp/eshell/em-tramp.el +++ b/lisp/eshell/em-tramp.el @@ -26,6 +26,7 @@ ;;; Code: (require 'esh-util) +(require 'esh-cmd) (eval-when-compile (require 'esh-mode) @@ -61,7 +62,7 @@ "Alias \"su\" to call TRAMP. Uses the system su through TRAMP's su method." - (setq args (eshell-stringify-list (eshell-flatten-list args))) + (setq args (eshell-stringify-list (flatten-tree args))) (let ((orig-args (copy-tree args))) (eshell-eval-using-options "su" args @@ -99,13 +100,14 @@ Become another USER during a login session.") "Alias \"sudo\" to call Tramp. Uses the system sudo through TRAMP's sudo method." - (setq args (eshell-stringify-list (eshell-flatten-list args))) + (setq args (eshell-stringify-list (flatten-tree args))) (let ((orig-args (copy-tree args))) (eshell-eval-using-options "sudo" args '((?h "help" nil nil "show this usage screen") (?u "user" t user "execute a command as another USER") :show-usage + :parse-leading-options-only :usage "[(-u | --user) USER] COMMAND Execute a COMMAND as the superuser or another USER.") (throw 'eshell-external diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el index b4ad5a6532c..fca50d70ae7 100644 --- a/lisp/eshell/em-unix.el +++ b/lisp/eshell/em-unix.el @@ -231,7 +231,7 @@ Otherwise, Emacs will attempt to use rsh to invoke du on the remote machine." This is implemented to call either `delete-file', `kill-buffer', `kill-process', or `unintern', depending on the nature of the argument." - (setq args (eshell-flatten-list args)) + (setq args (flatten-tree args)) (eshell-eval-using-options "rm" args '((?h "help" nil nil "show this usage screen") @@ -370,12 +370,14 @@ Remove the DIRECTORY(ies), if they are empty.") (or (not (eshell-under-windows-p)) (eq system-type 'ms-dos)) (setq attr (eshell-file-attributes (car files))) - (nth 10 attr-target) (nth 10 attr) - ;; Use equal, not -, since the inode and the device could - ;; cons cells. - (equal (nth 10 attr-target) (nth 10 attr)) - (nth 11 attr-target) (nth 11 attr) - (equal (nth 11 attr-target) (nth 11 attr))) + (file-attribute-inode-number attr-target) + (file-attribute-inode-number attr) + (equal (file-attribute-inode-number attr-target) + (file-attribute-inode-number attr)) + (file-attribute-device-number attr-target) + (file-attribute-device-number attr) + (equal (file-attribute-device-number attr-target) + (file-attribute-device-number attr))) (eshell-error (format-message "%s: `%s' and `%s' are the same file\n" command (car files) target))) (t @@ -397,16 +399,16 @@ Remove the DIRECTORY(ies), if they are empty.") (let (eshell-warn-dot-directories) (if (and (not deep) (eq func 'rename-file) - ;; Use equal, since the device might be a - ;; cons cell. - (equal (nth 11 (eshell-file-attributes - (file-name-directory - (directory-file-name - (expand-file-name source))))) - (nth 11 (eshell-file-attributes - (file-name-directory - (directory-file-name - (expand-file-name target))))))) + (equal (file-attribute-device-number + (eshell-file-attributes + (file-name-directory + (directory-file-name + (expand-file-name source))))) + (file-attribute-device-number + (eshell-file-attributes + (file-name-directory + (directory-file-name + (expand-file-name target))))))) (apply 'eshell-funcalln func source target args) (unless (file-directory-p target) (if em-verbose @@ -479,7 +481,7 @@ Remove the DIRECTORY(ies), if they are empty.") (error "%s: missing destination file or directory" ,command)) (if (= len 1) (nconc args '("."))) - (setq args (eshell-stringify-list (eshell-flatten-list args))) + (setq args (eshell-stringify-list (flatten-tree args))) (if (and ,(not (equal command "ln")) (string-match eshell-tar-regexp (car (last args))) (or (> (length args) 2) @@ -604,7 +606,7 @@ with `--symbolic'. When creating hard links, each TARGET must exist.") "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-stringify-list (eshell-flatten-list args))) + (setq args (eshell-stringify-list (flatten-tree args))) (if (or eshell-in-pipeline-p (catch 'special (dolist (arg args) @@ -612,7 +614,8 @@ symlink, then revert to the system's definition of cat." (> (length arg) 0) (eq (aref arg 0) ?-)) (let ((attrs (eshell-file-attributes arg))) - (and attrs (memq (aref (nth 8 attrs) 0) + (and attrs + (memq (aref (file-attribute-modes attrs) 0) '(?d ?l ?-))))) (throw 'special t))))) (let ((ext-cat (eshell-search-path "cat"))) @@ -667,7 +670,7 @@ Fallback to standard make when called synchronously." (compile (concat "make " (eshell-flatten-and-stringify args)))) (throw 'eshell-replace-command (eshell-parse-command "*make" (eshell-stringify-list - (eshell-flatten-list args)))))) + (flatten-tree args)))))) (put 'eshell/make 'eshell-no-numeric-conversions t) @@ -702,7 +705,7 @@ available..." (erase-buffer) (occur-mode) (let ((files (eshell-stringify-list - (eshell-flatten-list (cdr args)))) + (flatten-tree (cdr args)))) (inhibit-redisplay t) string) (when (car args) @@ -747,11 +750,11 @@ external command." (throw 'eshell-replace-command (eshell-parse-command (concat "*" command) (eshell-stringify-list - (eshell-flatten-list args)))) + (flatten-tree args)))) (let* ((args (mapconcat 'identity (mapcar 'shell-quote-argument (eshell-stringify-list - (eshell-flatten-list args))) + (flatten-tree args))) " ")) (cmd (progn (set-text-properties 0 (length args) @@ -843,19 +846,19 @@ external command." (unless (string-match "\\`\\.\\.?\\'" (caar entries)) (let* ((entry (concat path "/" (caar entries))) - (symlink (and (stringp (cadr (car entries))) - (cadr (car entries))))) + (symlink (and (stringp (file-attribute-type (cdar entries))) + (file-attribute-type (cdar entries))))) (unless (or (and symlink (not dereference-links)) (and only-one-filesystem (/= only-one-filesystem - (nth 12 (car entries))))) + (file-attribute-device-number (cdar entries))))) (if symlink (setq entry symlink)) (setq size (+ size - (if (eq t (cadr (car entries))) + (if (eq t (car (cdar entries))) (eshell-du-sum-directory entry (1+ depth)) - (let ((file-size (nth 8 (car entries)))) + (let ((file-size (file-attribute-size (cdar entries)))) (prog1 file-size (if show-all @@ -873,7 +876,7 @@ external command." (defun eshell/du (&rest args) "Implementation of \"du\" in Lisp, passing ARGS." (setq args (if args - (eshell-stringify-list (eshell-flatten-list args)) + (eshell-stringify-list (flatten-tree args)) '("."))) (let ((ext-du (eshell-search-path "du"))) (if (and ext-du @@ -926,7 +929,7 @@ Summarize disk usage of each FILE, recursively for directories.") (while args (if only-one-filesystem (setq only-one-filesystem - (nth 11 (eshell-file-attributes + (file-attribute-device-number (eshell-file-attributes (file-name-as-directory (car args)))))) (setq size (+ size (eshell-du-sum-directory (directory-file-name (car args)) 0))) @@ -973,9 +976,9 @@ Show wall-clock time elapsed during execution of COMMAND.") (eshell-parse-command (car time-args) ;;; https://lists.gnu.org/r/bug-gnu-emacs/2007-08/msg00205.html (eshell-stringify-list - (eshell-flatten-list (cdr time-args)))))))) + (flatten-tree (cdr time-args)))))))) -(defun eshell/whoami (&rest args) +(defun eshell/whoami (&rest _args) "Make \"whoami\" Tramp aware." (or (file-remote-p default-directory 'user) (user-login-name))) @@ -997,7 +1000,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-stringify-list (eshell-flatten-list args)))) + (let ((orig-args (eshell-stringify-list (flatten-tree args)))) (if (or eshell-plain-diff-behavior (not (and (eshell-interactive-output-p) (not eshell-in-pipeline-p) @@ -1053,7 +1056,7 @@ Show wall-clock time elapsed during execution of COMMAND.") (string-match "^-" (car args)))) (throw 'eshell-replace-command (eshell-parse-command "*locate" (eshell-stringify-list - (eshell-flatten-list args)))) + (flatten-tree args)))) (save-selected-window (let ((locate-history-list (list (car args)))) (locate-with-filter (car args) (cadr args)))))) diff --git a/lisp/eshell/em-xtra.el b/lisp/eshell/em-xtra.el index d4e5f1a092c..602e8417520 100644 --- a/lisp/eshell/em-xtra.el +++ b/lisp/eshell/em-xtra.el @@ -25,8 +25,10 @@ (require 'esh-util) (eval-when-compile - (require 'eshell) - (require 'pcomplete)) + (require 'eshell)) +;; Strictly speaking, should only be needed at compile time. +;; Require at run-time too to silence compiler. +(require 'pcomplete) (require 'compile) ;; There are no items in this custom group, but eshell modules (ab)use @@ -49,7 +51,7 @@ naturally accessible within Emacs." "Implementation of expr, using the calc package." (if (not (fboundp 'calc-eval)) (throw 'eshell-replace-command - (eshell-parse-command "*expr" (eshell-flatten-list args))) + (eshell-parse-command "*expr" (flatten-tree args))) ;; to fool the byte-compiler... (let ((func 'calc-eval)) (funcall func (eshell-flatten-and-stringify args))))) diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 8e1e936b63f..ee4dbd5550f 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -816,7 +816,7 @@ This is used on systems where async subprocesses are not supported." ;; The last process in the pipe should get its handles ;; redirected as we found them before running the pipe. ,(if (null (cdr pipeline)) - `(progn + '(progn (setq eshell-current-handles tail-handles) (setq eshell-in-pipeline-p nil))) (let ((result ,(car pipeline))) diff --git a/lisp/eshell/esh-ext.el b/lisp/eshell/esh-ext.el index fccdb73b31e..35ebd36b291 100644 --- a/lisp/eshell/esh-ext.el +++ b/lisp/eshell/esh-ext.el @@ -37,8 +37,8 @@ (eval-when-compile (require 'cl-lib) - (require 'esh-io) (require 'esh-cmd)) +(require 'esh-io) (require 'esh-arg) (require 'esh-opt) (require 'esh-proc) @@ -222,7 +222,7 @@ causing the user to wonder if anything's really going on..." (defun eshell-external-command (command args) "Insert output from an external COMMAND, using ARGS." - (setq args (eshell-stringify-list (eshell-flatten-list args))) + (setq args (eshell-stringify-list (flatten-tree args))) (let ((interp (eshell-find-interpreter command args diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el index be6123f21ba..30298763a53 100644 --- a/lisp/eshell/esh-mode.el +++ b/lisp/eshell/esh-mode.el @@ -182,10 +182,11 @@ inserted. They return the string as it should be inserted." :group 'eshell-mode) (defcustom eshell-password-prompt-regexp - (format "\\(%s\\).*:\\s *\\'" (regexp-opt password-word-equivalents)) + (format "\\(%s\\)[^::៖]*[::៖]\\s *\\'" (regexp-opt password-word-equivalents)) "Regexp matching prompts for passwords in the inferior process. This is used by `eshell-watch-for-password-prompt'." :type 'regexp + :version "27.1" :group 'eshell-mode) (defcustom eshell-skip-prompt-function nil @@ -884,8 +885,7 @@ If SCROLLBACK is non-nil, clear the scrollback contents." (interactive) (if scrollback (eshell/clear-scrollback) - (let ((eshell-input-filter-functions - (remq 'eshell-add-to-history eshell-input-filter-functions))) + (let ((eshell-input-filter-functions nil)) (insert (make-string (window-size) ?\n)) (eshell-send-input)))) diff --git a/lisp/eshell/esh-opt.el b/lisp/eshell/esh-opt.el index 6f37a29004a..a023a3c5d2e 100644 --- a/lisp/eshell/esh-opt.el +++ b/lisp/eshell/esh-opt.el @@ -77,9 +77,13 @@ arguments, some do not. The recognized :KEYWORDS are: arguments. :preserve-args - If present, do not pass MACRO-ARGS through `eshell-flatten-list' + If present, do not pass MACRO-ARGS through `flatten-tree' and `eshell-stringify-list'. +:parse-leading-options-only + If present, do not parse dash or switch arguments after the first +positional argument. Instead, treat them as positional arguments themselves. + For example, OPTIONS might look like: ((?C nil nil multi-column \"multi-column display\") @@ -95,14 +99,14 @@ BODY-FORMS. If instead an external command is run (because of an unknown option), the tag `eshell-external' will be thrown with the new process for its value. -Lastly, any remaining arguments will be available in a locally -interned variable `args' (created using a `let' form)." +Lastly, any remaining arguments will be available in the locally +let-bound variable `args'." (declare (debug (form form sexp body))) `(let* ((temp-args ,(if (memq ':preserve-args (cadr options)) macro-args (list 'eshell-stringify-list - (list 'eshell-flatten-list macro-args)))) + (list 'flatten-tree macro-args)))) (processed-args (eshell--do-opts ,name ,options temp-args)) ,@(delete-dups (delq nil (mapcar (lambda (opt) @@ -111,6 +115,8 @@ interned variable `args' (created using a `let' form)." ;; `options' is of the form (quote OPTS). (cadr options)))) (args processed-args)) + ;; Silence unused lexical variable warning if body does not use `args'. + (ignore args) ,@body-forms)) ;;; Internal Functions: @@ -194,11 +200,7 @@ will be modified." (if (eq (nth 2 opt) t) (if (> ai (length eshell--args)) (error "%s: missing option argument" name) - (prog1 (nth ai eshell--args) - (if (> ai 0) - (setcdr (nthcdr (1- ai) eshell--args) - (nthcdr (1+ ai) eshell--args)) - (setq eshell--args (cdr eshell--args))))) + (pop (nthcdr ai eshell--args))) (or (nth 2 opt) t))))) (defun eshell--process-option (name switch kind ai options opt-vals) @@ -243,18 +245,22 @@ switch is unrecognized." (list sym))))) options))) (ai 0) arg - (eshell--args args)) - (while (< ai (length eshell--args)) + (eshell--args args) + (pos-argument-found nil)) + (while (and (< ai (length eshell--args)) + ;; Abort if we saw the first pos argument and option is set + (not (and pos-argument-found + (memq :parse-leading-options-only options)))) (setq arg (nth ai eshell--args)) (if (not (and (stringp arg) (string-match "^-\\(-\\)?\\(.*\\)" arg))) - (setq ai (1+ ai)) + ;; Positional argument found, skip + (setq ai (1+ ai) + pos-argument-found t) + ;; dash or switch argument found, parse (let* ((dash (match-string 1 arg)) (switch (match-string 2 arg))) - (if (= ai 0) - (setq eshell--args (cdr eshell--args)) - (setcdr (nthcdr (1- ai) eshell--args) - (nthcdr (1+ ai) eshell--args))) + (pop (nthcdr ai eshell--args)) (if dash (if (> (length switch) 0) (eshell--process-option name switch 1 ai options opt-vals) diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el index 33ec19ae36d..55251f5bfb2 100644 --- a/lisp/eshell/esh-proc.el +++ b/lisp/eshell/esh-proc.el @@ -158,7 +158,7 @@ The signals which will cause this to happen are matched by (defalias 'eshell/wait 'eshell-wait-for-process) -(defun eshell/jobs (&rest args) +(defun eshell/jobs (&rest _args) "List processes, if there are any." (and (fboundp 'process-list) (process-list) @@ -167,7 +167,8 @@ The signals which will cause this to happen are matched by (defun eshell/kill (&rest args) "Kill processes. Usage: kill [-<signal>] <pid>|<process> ... -Accepts PIDs and process objects." +Accepts PIDs and process objects. Optionally accept signals +and signal names." ;; If the first argument starts with a dash, treat it as the signal ;; specifier. (let ((signum 'SIGINT)) @@ -178,12 +179,12 @@ Accepts PIDs and process objects." ((string-match "\\`-[[:digit:]]+\\'" arg) (setq signum (abs (string-to-number arg)))) ((string-match "\\`-\\([[:upper:]]+\\|[[:lower:]]+\\)\\'" arg) - (setq signum (abs (string-to-number arg))))) + (setq signum (intern (substring arg 1))))) (setq args (cdr args)))) (while args (let ((arg (if (eshell-processp (car args)) (process-id (car args)) - (car args)))) + (string-to-number (car args))))) (when arg (cond ((null arg) @@ -198,6 +199,8 @@ Accepts PIDs and process objects." (setq args (cdr args)))) nil) +(put 'eshell/kill 'eshell-no-numeric-conversions t) + (defun eshell-read-process-name (prompt) "Read the name of a process from the minibuffer, using completion. The prompt will be set to PROMPT." diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index f8dd6f08f45..7e6e39e74a3 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -285,17 +285,9 @@ Prepend remote identification of `default-directory', if any." ,@forms) (setq list-iter (cdr list-iter))))) -(defun eshell-flatten-list (args) - "Flatten any lists within ARGS, so that there are no sublists." - (let ((new-list (list t))) - (dolist (a args) - (if (and (listp a) - (listp (cdr a))) - (nconc new-list (eshell-flatten-list a)) - (nconc new-list (list a)))) - (cdr new-list))) - -(defun eshell-uniqify-list (l) +(define-obsolete-function-alias 'eshell-flatten-list #'flatten-tree "27.1") + +(defun eshell-uniquify-list (l) "Remove occurring multiples in L. You probably want to sort first." (let ((m l)) (while m @@ -305,6 +297,9 @@ Prepend remote identification of `default-directory', if any." (setcdr m (cddr m))) (setq m (cdr m)))) l) +(define-obsolete-function-alias + 'eshell-uniqify-list + 'eshell-uniquify-list "27.1") (defun eshell-stringify (object) "Convert OBJECT into a string value." @@ -327,7 +322,7 @@ Prepend remote identification of `default-directory', if any." (defsubst eshell-flatten-and-stringify (&rest args) "Flatten and stringify all of the ARGS into a single string." - (mapconcat 'eshell-stringify (eshell-flatten-list args) " ")) + (mapconcat 'eshell-stringify (flatten-tree args) " ")) (defsubst eshell-directory-files (regexp &optional directory) "Return a list of files in the given DIRECTORY matching REGEXP." @@ -444,7 +439,7 @@ list." (not (symbol-value timestamp-var)) (time-less-p (symbol-value timestamp-var) - (nth 5 (file-attributes file)))) + (file-attribute-modification-time (file-attributes file)))) (progn (set result-var (eshell-read-passwd-file file)) (set timestamp-var (current-time)))) @@ -498,7 +493,7 @@ list." (not (symbol-value timestamp-var)) (time-less-p (symbol-value timestamp-var) - (nth 5 (file-attributes file)))) + (file-attribute-modification-time (file-attributes file)))) (progn (set result-var (eshell-read-hosts-file file)) (set timestamp-var (current-time)))) diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index b3f54cf048d..133a4f9c713 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -343,6 +343,8 @@ This function is explicit for adding to `eshell-parse-argument-hook'." obarray 'boundp)) (pcomplete-here)))) +;; FIXME the real "env" command does more than this, it runs a program +;; in a modified environment. (defun eshell/env (&rest args) "Implementation of `env' in Lisp." (eshell-init-print-buffer) |