diff options
Diffstat (limited to 'lisp/eshell/em-glob.el')
-rw-r--r-- | lisp/eshell/em-glob.el | 77 |
1 files changed, 46 insertions, 31 deletions
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el index 02f2fffe94f..7fc6958a00f 100644 --- a/lisp/eshell/em-glob.el +++ b/lisp/eshell/em-glob.el @@ -49,8 +49,9 @@ ;;; Code: +(require 'esh-arg) +(require 'esh-module) (require 'esh-util) -(eval-when-compile (require 'eshell)) ;;;###autoload (progn @@ -68,6 +69,15 @@ by zsh for filename generation." :type 'hook :group 'eshell-glob) +(defcustom eshell-glob-splice-results nil + "If non-nil, the results of glob patterns will be spliced in-place. +When splicing, the resulting command is as though the user typed +each result individually. Otherwise, the glob results a single +argument as a list." + :version "30.1" + :type 'boolean + :group 'eshell-glob) + (defcustom eshell-glob-include-dot-files nil "If non-nil, glob patterns will match files beginning with a dot." :type 'boolean @@ -78,7 +88,7 @@ by zsh for filename generation." :type 'boolean :group 'eshell-glob) -(defcustom eshell-glob-case-insensitive (eshell-under-windows-p) +(defcustom eshell-glob-case-insensitive (not (not (eshell-under-windows-p))) "If non-nil, glob pattern matching will ignore case." :type 'boolean :group 'eshell-glob) @@ -138,23 +148,16 @@ This mimics the behavior of zsh if non-nil, but bash if nil." (defun eshell-no-command-globbing (terms) "Don't glob the command argument. Reflect this by modifying TERMS." (ignore - (when (and (listp (car terms)) - (eq (caar terms) 'eshell-extended-glob)) - (setcar terms (cadr (car terms)))))) + (pcase (car terms) + ((or `(eshell-extended-glob ,term) + `(eshell-splice-args (eshell-extended-glob ,term))) + (setcar terms term))))) (defun eshell-add-glob-modifier () "Add `eshell-extended-glob' to the argument modifier list." - (when (memq 'expand-file-name eshell-current-modifiers) - (setq eshell-current-modifiers - (delq 'expand-file-name eshell-current-modifiers)) - ;; if this is a glob pattern than needs to be expanded, then it - ;; will need to expand each member of the resulting glob list - (add-to-list 'eshell-current-modifiers - (lambda (list) - (if (listp list) - (mapcar 'expand-file-name list) - (expand-file-name list))))) - (add-to-list 'eshell-current-modifiers 'eshell-extended-glob)) + (when eshell-glob-splice-results + (add-hook 'eshell-current-modifiers #'eshell-splice-args 99)) + (add-hook 'eshell-current-modifiers #'eshell-extended-glob)) (defun eshell-parse-glob-chars () "Parse a globbing delimiter. @@ -170,7 +173,7 @@ interpretation." (end (eshell-find-delimiter delim (if (eq delim ?\[) ?\] ?\))))) (if (not end) - (throw 'eshell-incomplete delim) + (throw 'eshell-incomplete (char-to-string delim)) (if (and (eshell-using-module 'eshell-pred) (eshell-arg-delimiter (1+ end))) (ignore (goto-char here)) @@ -187,6 +190,12 @@ interpretation." '(("**/" . recurse) ("***/" . recurse-symlink))) +(defsubst eshell-glob-chars-regexp () + "Return the lazily-created value for `eshell-glob-chars-regexp'." + (or eshell-glob-chars-regexp + (setq-local eshell-glob-chars-regexp + (format "[%s]+" (apply 'string eshell-glob-chars-list))))) + (defun eshell-glob-regexp (pattern) "Convert glob-pattern PATTERN to a regular expression. The basic syntax is: @@ -207,11 +216,8 @@ set to true, then these characters will match themselves in the resulting regular expression." (let ((matched-in-pattern 0) ; How much of PATTERN handled regexp) - (while (string-match - (or eshell-glob-chars-regexp - (setq-local eshell-glob-chars-regexp - (format "[%s]+" (apply 'string eshell-glob-chars-list)))) - pattern matched-in-pattern) + (while (string-match (eshell-glob-chars-regexp) + pattern matched-in-pattern) (let* ((op-begin (match-beginning 0)) (op-char (aref pattern op-begin))) (setq regexp @@ -236,6 +242,10 @@ resulting regular expression." (regexp-quote (substring pattern matched-in-pattern)) "\\'"))) +(defun eshell-glob-p (pattern) + "Return non-nil if PATTERN has any special glob characters." + (string-match (eshell-glob-chars-regexp) pattern)) + (defun eshell-glob-convert-1 (glob &optional last) "Convert a GLOB matching a single element of a file name to regexps. If LAST is non-nil, this glob is the last element of a file name. @@ -288,14 +298,13 @@ The result is a list of three elements: symlinks. 3. A boolean indicating whether to match directories only." - (let ((globs (eshell-split-path glob)) - (isdir (eq (aref glob (1- (length glob))) ?/)) + (let ((globs (eshell-split-filename glob)) + (isdir (string-suffix-p "/" glob)) start-dir result last-saw-recursion) (if (and (cdr globs) (file-name-absolute-p (car globs))) - (setq start-dir (car globs) - globs (cdr globs)) - (setq start-dir ".")) + (setq start-dir (pop globs)) + (setq start-dir (file-name-as-directory "."))) (while globs (if-let ((recurse (cdr (assoc (car globs) eshell-glob-recursive-alist)))) @@ -303,11 +312,15 @@ The result is a list of three elements: (setcar result recurse) (push recurse result) (setq last-saw-recursion t)) - (push (eshell-glob-convert-1 (car globs) (null (cdr globs))) - result) + (if (or result (eshell-glob-p (car globs))) + (push (eshell-glob-convert-1 (car globs) (null (cdr globs))) + result) + ;; We haven't seen a glob yet, so instead append to the start + ;; directory. + (setq start-dir (file-name-concat start-dir (car globs)))) (setq last-saw-recursion nil)) (setq globs (cdr globs))) - (list (file-name-as-directory start-dir) + (list start-dir (nreverse result) isdir))) @@ -335,7 +348,9 @@ regular expressions, and these cannot support the above constructs." (or (and eshell-glob-matches (sort eshell-glob-matches #'string<)) (if eshell-error-if-no-glob (error "No matches found: %s" glob) - glob)))) + (if eshell-glob-splice-results + (list glob) + glob))))) ;; FIXME does this really need to abuse eshell-glob-matches, message-shown? (defun eshell-glob-entries (path globs only-dirs) |