aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Porter2022-03-27 22:28:40 -0700
committerLars Ingebrigtsen2022-05-01 20:41:18 +0200
commitade1424a975aabaa208010c6fdd3c8b7c51242ff (patch)
treef4c2e874ed3b1f5684f6e72e7f41401b9b3bd22c
parent788694d026b401715330576633a98542623978ff (diff)
downloademacs-ade1424a975aabaa208010c6fdd3c8b7c51242ff.tar.gz
emacs-ade1424a975aabaa208010c6fdd3c8b7c51242ff.zip
Use a common set of string delimiters for all Eshell predicates/modifiers
* lisp/eshell/em-pred.el (eshell-pred-delimiter-pairs): New variable. (eshell-get-comparison-modifier-argument) (eshell-get-numeric-modifier-argument) (eshell-get-delimited-modifier-argument): New functions... (eshell-pred-user-or-group, eshell-pred-file-time) (eshell-pred-file-links, eshell-pred-file-size) (eshell-pred-substitute, eshell-join-memebers, eshell-split-members): ... and use them here. (eshell-include-members): Pass 'mod-char' and use 'eshell-get-delimited-modifier-argument'. (eshell-pred-file-type, eshell-pred-file-mode): Use 'when-let'. (eshell-modifier-alist): Pass modifier char to 'eshell-include-members'. * test/lisp/eshell/em-pred-tests.el (em-pred-test/predicate-delimiters): New test. (em-pred-test/predicate-uid, em-pred-test/predicate-gid, em-pred-test/modifier-include, em-pred-test/modifier-exclude): Remove cases covered by 'em-pred-test/predicate-delimiters'. (em-pred-test/modifier-substitute): Add test cases for new delimiter styles. * doc/misc/eshell.texi (Argument Predication and Modification): Explain how string parameters are delimited. (Argument Modifiers): Document some special delimiter behavior with the 's/PATTERN/REPLACE/' modifier (bug#55204). * etc/NEWS: Announce this change, and move the 'eshell-eval-using-options' entry to the Eshell section.
-rw-r--r--doc/misc/eshell.texi12
-rw-r--r--etc/NEWS26
-rw-r--r--lisp/eshell/em-pred.el273
-rw-r--r--test/lisp/eshell/em-pred-tests.el33
4 files changed, 180 insertions, 164 deletions
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index e5392061665..a3ed922cf2c 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -1191,6 +1191,13 @@ or modifiers. For example, @samp{*(.)} expands to all regular files
1191in the current directory and @samp{*(^@@:U^u0)} expands to all 1191in the current directory and @samp{*(^@@:U^u0)} expands to all
1192non-symlinks not owned by @code{root}, upper-cased. 1192non-symlinks not owned by @code{root}, upper-cased.
1193 1193
1194Some predicates and modifiers accept string parameters, such as
1195@samp{*(u'@var{user}')}, which matches all files owned by @var{user}.
1196These parameters must be surrounded by delimiters; you can use any of
1197the following pairs of delimiters: @code{" @dots{} "}, @code{' @dots{}
1198'}, @code{/ @dots{} /}, @code{| @dots{} |}, @code{( @dots{} )},
1199@code{[ @dots{} ]}, @code{< @dots{} >}, or @code{@{ @dots{} @}}.
1200
1194You can customize the syntax and behavior of predicates and modifiers 1201You can customize the syntax and behavior of predicates and modifiers
1195in Eshell via the Customize group ``eshell-pred'' (@pxref{Easy 1202in Eshell via the Customize group ``eshell-pred'' (@pxref{Easy
1196Customization, , , emacs, The GNU Emacs Manual}). 1203Customization, , , emacs, The GNU Emacs Manual}).
@@ -1379,6 +1386,11 @@ meaning.
1379Replaces the first instance of the regular expression @var{pattern} 1386Replaces the first instance of the regular expression @var{pattern}
1380with @var{replace}. Signals an error if no match is found. 1387with @var{replace}. Signals an error if no match is found.
1381 1388
1389As with other modifiers taking string parameters, you can use
1390different delimiters to separate @var{pattern} and @var{replace}, such
1391as @samp{s'@dots{}'@dots{}'}, @samp{s[@dots{}][@dots{}]}, or even
1392@samp{s[@dots{}]/@dots{}/}.
1393
1382@item gs/@var{pattern}/@var{replace}/ 1394@item gs/@var{pattern}/@var{replace}/
1383Replaces all instances of the regular expression @var{pattern} with 1395Replaces all instances of the regular expression @var{pattern} with
1384@var{replace}. 1396@var{replace}.
diff --git a/etc/NEWS b/etc/NEWS
index 090d0b6dddc..3380c266daa 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -174,11 +174,22 @@ files that were compiled with an old EIEIO (Emacs<25).
174** 'C-x 8 .' has been moved to 'C-x 8 . .'. 174** 'C-x 8 .' has been moved to 'C-x 8 . .'.
175This is to open up the 'C-x 8 .' map to bind further characters there. 175This is to open up the 'C-x 8 .' map to bind further characters there.
176 176
177** Eshell
178
177--- 179---
178** 'source' and '.' in Eshell no longer accept the '--help' option. 180*** 'source' and '.' no longer accept the '--help' option.
179This is for compatibility with the shell versions of these commands, 181This is for compatibility with the shell versions of these commands,
180which don't handle options like '--help' in any special way. 182which don't handle options like '--help' in any special way.
181 183
184+++
185*** String delimiters in argument predicates/modifiers are more restricted.
186Previously, some argument predicates/modifiers allowed arbitrary
187characters as string delimiters. To provide more unified behavior
188across all predicates/modifiers, the list of allowed delimiters has
189been restricted to "...", '...', /.../, |...|, (...), [...], <...>,
190and {...}. See the "(eshell) Argument Predication and Modification"
191node in the Eshell manual for more details.
192
182--- 193---
183** The 'delete-forward-char' command now deletes by grapheme clusters. 194** The 'delete-forward-char' command now deletes by grapheme clusters.
184This command is by default bound to the <Delete> function key 195This command is by default bound to the <Delete> function key
@@ -1354,6 +1365,14 @@ Lisp function. This frees you from having to keep track of whether
1354commands are Lisp function or external when supplying absolute file 1365commands are Lisp function or external when supplying absolute file
1355name arguments. See "Electric forward slash" in the Eshell manual. 1366name arguments. See "Electric forward slash" in the Eshell manual.
1356 1367
1368---
1369*** Built-in Eshell commands now follow POSIX/GNU argument syntax conventions.
1370Built-in commands in Eshell now accept command-line options with
1371values passed as a single token, such as '-oVALUE' or
1372'--option=VALUE'. New commands can take advantage of this with the
1373'eshell-eval-using-options' macro. See "Defining new built-in
1374commands" in the "(eshell) Built-ins" node of the Eshell manual.
1375
1357** Calc 1376** Calc
1358 1377
1359+++ 1378+++
@@ -1937,11 +1956,6 @@ dimensions.
1937Specifying a cons as the FROM argument allows to start measuring text 1956Specifying a cons as the FROM argument allows to start measuring text
1938from a specified amount of pixels above or below a position. 1957from a specified amount of pixels above or below a position.
1939 1958
1940---
1941** 'eshell-eval-using-options' now follows argument syntax conventions.
1942Built-in commands in Eshell now accept command-line options with
1943values passed as a single token, such as '-oVALUE' or '--option=VALUE'.
1944
1945** XDG support 1959** XDG support
1946 1960
1947--- 1961---
diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el
index eb5109b82dc..594563554d2 100644
--- a/lisp/eshell/em-pred.el
+++ b/lisp/eshell/em-pred.el
@@ -116,8 +116,8 @@ The format of each entry is
116 (?U . (lambda (lst) (mapcar #'upcase lst))) 116 (?U . (lambda (lst) (mapcar #'upcase lst)))
117 (?C . (lambda (lst) (mapcar #'capitalize lst))) 117 (?C . (lambda (lst) (mapcar #'capitalize lst)))
118 (?h . (lambda (lst) (mapcar #'file-name-directory lst))) 118 (?h . (lambda (lst) (mapcar #'file-name-directory lst)))
119 (?i . (eshell-include-members)) 119 (?i . (eshell-include-members ?i))
120 (?x . (eshell-include-members t)) 120 (?x . (eshell-include-members ?x t))
121 (?r . (lambda (lst) (mapcar #'file-name-sans-extension lst))) 121 (?r . (lambda (lst) (mapcar #'file-name-sans-extension lst)))
122 (?e . (lambda (lst) (mapcar #'file-name-extension lst))) 122 (?e . (lambda (lst) (mapcar #'file-name-extension lst)))
123 (?t . (lambda (lst) (mapcar #'file-name-nondirectory lst))) 123 (?t . (lambda (lst) (mapcar #'file-name-nondirectory lst)))
@@ -219,6 +219,20 @@ FOR LISTS OF ARGUMENTS:
219EXAMPLES: 219EXAMPLES:
220 *.c(:o) sorted list of .c files") 220 *.c(:o) sorted list of .c files")
221 221
222(defvar eshell-pred-delimiter-pairs
223 '((?\( . ?\))
224 (?\[ . ?\])
225 (?\< . ?\>)
226 (?\{ . ?\})
227 (?\' . ?\')
228 (?\" . ?\")
229 (?/ . ?/)
230 (?| . ?|))
231 "A list of delimiter pairs that can be used in argument predicates/modifiers.
232Each element is of the form (OPEN . CLOSE), where OPEN and CLOSE
233are characters representing the opening and closing delimiter,
234respectively.")
235
222(defvar-keymap eshell-pred-mode-map 236(defvar-keymap eshell-pred-mode-map
223 "C-c M-q" #'eshell-display-predicate-help 237 "C-c M-q" #'eshell-display-predicate-help
224 "C-c M-m" #'eshell-display-modifier-help) 238 "C-c M-m" #'eshell-display-modifier-help)
@@ -364,38 +378,68 @@ resultant list of strings."
364 (lambda (file) (funcall pred (file-truename file)))))) 378 (lambda (file) (funcall pred (file-truename file))))))
365 (cons pred funcs)) 379 (cons pred funcs))
366 380
381(defun eshell-get-comparison-modifier-argument (&optional functions)
382 "Starting at point, get the comparison modifier argument, if any.
383These are the -/+ characters, corresponding to `<' and `>',
384respectively. If no comparison modifier is at point, return `='.
385
386FUNCTIONS, if non-nil, is a list of comparison functions,
387specified as (LESS-THAN GREATER-THAN EQUAL-TO)."
388 (let ((functions (or functions (list #'< #'> #'=))))
389 (if (memq (char-after) '(?- ?+))
390 (prog1
391 (if (eq (char-after) ?-) (nth 0 functions) (nth 1 functions))
392 (forward-char))
393 (nth 2 functions))))
394
395(defun eshell-get-numeric-modifier-argument ()
396 "Starting at point, get the numeric modifier argument, if any.
397If a number is found, update point to just after the number."
398 (when (looking-at "[0-9]+")
399 (prog1
400 (string-to-number (match-string 0))
401 (goto-char (match-end 0)))))
402
403(defun eshell-get-delimited-modifier-argument (&optional chained-p)
404 "Starting at point, get the delimited modifier argument, if any.
405If the character after point is a predicate/modifier
406delimiter (see `eshell-pred-delimiter-pairs', read the value of
407the argument and update point to be just after the closing
408delimiter.
409
410If CHAINED-P is true, then another delimited modifier argument
411will immediately follow this one. In this case, when the opening
412and closing delimiters are the same, update point to be just
413before the closing delimiter. This allows modifiers like
414`:s/match/repl' to work as expected."
415 (when-let* ((open (char-after))
416 (close (cdr (assoc open eshell-pred-delimiter-pairs)))
417 (end (eshell-find-delimiter open close nil nil t)))
418 (prog1
419 (buffer-substring-no-properties (1+ (point)) end)
420 (goto-char (if (and chained-p (eq open close))
421 end
422 (1+ end))))))
423
367(defun eshell-pred-user-or-group (mod-char mod-type attr-index get-id-func) 424(defun eshell-pred-user-or-group (mod-char mod-type attr-index get-id-func)
368 "Return a predicate to test whether a file match a given user/group id." 425 "Return a predicate to test whether a file match a given user/group id."
369 (let (ugid open close end) 426 (let ((ugid (eshell-get-numeric-modifier-argument)))
370 (if (looking-at "[0-9]+") 427 (unless ugid
371 (progn 428 (let ((ugname (or (eshell-get-delimited-modifier-argument)
372 (setq ugid (string-to-number (match-string 0))) 429 (error "Malformed %s name string for modifier `%c'"
373 (goto-char (match-end 0))) 430 mod-type mod-char))))
374 (setq open (char-after)) 431 (setq ugid (funcall get-id-func ugname))))
375 (if (setq close (memq open '(?\( ?\[ ?\< ?\{)))
376 (setq close (car (last '(?\) ?\] ?\> ?\})
377 (length close))))
378 (setq close open))
379 (forward-char)
380 (setq end (eshell-find-delimiter open close))
381 (unless end
382 (error "Malformed %s name string for modifier `%c'"
383 mod-type mod-char))
384 (setq ugid
385 (funcall get-id-func (buffer-substring (point) end)))
386 (goto-char (1+ end)))
387 (unless ugid 432 (unless ugid
388 (error "Unknown %s name specified for modifier `%c'" 433 (error "Unknown %s name specified for modifier `%c'"
389 mod-type mod-char)) 434 mod-type mod-char))
390 (lambda (file) 435 (lambda (file)
391 (let ((attrs (file-attributes file))) 436 (when-let ((attrs (file-attributes file)))
392 (if attrs 437 (= (nth attr-index attrs) ugid)))))
393 (= (nth attr-index attrs) ugid))))))
394 438
395(defun eshell-pred-file-time (mod-char mod-type attr-index) 439(defun eshell-pred-file-time (mod-char mod-type attr-index)
396 "Return a predicate to test whether a file matches a certain time." 440 "Return a predicate to test whether a file matches a certain time."
397 (let* ((quantum 86400) 441 (let* ((quantum 86400)
398 qual when open close end) 442 qual when)
399 (when (memq (char-after) '(?M ?w ?h ?m ?s)) 443 (when (memq (char-after) '(?M ?w ?h ?m ?s))
400 (setq quantum (char-after)) 444 (setq quantum (char-after))
401 (cond 445 (cond
@@ -410,36 +454,21 @@ resultant list of strings."
410 ((eq quantum ?s) 454 ((eq quantum ?s)
411 (setq quantum 1))) 455 (setq quantum 1)))
412 (forward-char)) 456 (forward-char))
413 (when (memq (char-after) '(?+ ?-)) 457 (setq qual (eshell-get-comparison-modifier-argument
414 (setq qual (char-after)) 458 (list #'time-less-p
415 (forward-char)) 459 (lambda (a b) (time-less-p b a))
416 (if (looking-at "[0-9]+") 460 #'time-equal-p)))
417 (progn 461 (if-let ((number (eshell-get-numeric-modifier-argument)))
418 (setq when (time-since (* (string-to-number (match-string 0)) 462 (setq when (time-since (* number quantum)))
419 quantum))) 463 (let* ((file (or (eshell-get-delimited-modifier-argument)
420 (goto-char (match-end 0))) 464 (error "Malformed %s time modifier `%c'"
421 (setq open (char-after)) 465 mod-type mod-char)))
422 (if (setq close (memq open '(?\( ?\[ ?\< ?\{))) 466 (attrs (or (file-attributes file)
423 (setq close (car (last '(?\) ?\] ?\> ?\}) 467 (error "Cannot stat file `%s'" file))))
424 (length close)))) 468 (setq when (nth attr-index attrs))))
425 (setq close open)) 469 (lambda (file)
426 (forward-char) 470 (when-let ((attrs (file-attributes file)))
427 (setq end (eshell-find-delimiter open close)) 471 (funcall qual when (nth attr-index attrs))))))
428 (unless end
429 (error "Malformed %s time modifier `%c'" mod-type mod-char))
430 (let* ((file (buffer-substring (point) end))
431 (attrs (file-attributes file)))
432 (unless attrs
433 (error "Cannot stat file `%s'" file))
434 (setq when (nth attr-index attrs)))
435 (goto-char (1+ end)))
436 (let ((f (cond ((eq qual ?-) #'time-less-p)
437 ((eq qual ?+) (lambda (a b) (time-less-p b a)))
438 (#'time-equal-p))))
439 (lambda (file)
440 (let ((attrs (file-attributes file)))
441 (if attrs
442 (funcall f when (nth attr-index attrs))))))))
443 472
444(defun eshell-pred-file-type (type) 473(defun eshell-pred-file-type (type)
445 "Return a test which tests that the file is of a certain TYPE. 474 "Return a test which tests that the file is of a certain TYPE.
@@ -454,36 +483,23 @@ that `ls -l' will show in the first column of its display."
454 '(?b ?c) 483 '(?b ?c)
455 (list type)))) 484 (list type))))
456 (lambda (file) 485 (lambda (file)
457 (let ((attrs (eshell-file-attributes (directory-file-name file)))) 486 (when-let ((attrs (eshell-file-attributes (directory-file-name file))))
458 (if attrs 487 (memq (aref (file-attribute-modes attrs) 0) set)))))
459 (memq (aref (file-attribute-modes attrs) 0) set))))))
460 488
461(defsubst eshell-pred-file-mode (mode) 489(defsubst eshell-pred-file-mode (mode)
462 "Return a test which tests that MODE pertains to the file." 490 "Return a test which tests that MODE pertains to the file."
463 (lambda (file) 491 (lambda (file)
464 (let ((modes (file-modes file 'nofollow))) 492 (when-let ((modes (file-modes file 'nofollow)))
465 (if modes 493 (not (zerop (logand mode modes))))))
466 (not (zerop (logand mode modes)))))))
467 494
468(defun eshell-pred-file-links () 495(defun eshell-pred-file-links ()
469 "Return a predicate to test whether a file has a given number of links." 496 "Return a predicate to test whether a file has a given number of links."
470 (let (qual amount) 497 (let ((qual (eshell-get-comparison-modifier-argument))
471 (when (memq (char-after) '(?- ?+)) 498 (amount (or (eshell-get-numeric-modifier-argument)
472 (setq qual (char-after)) 499 (error "Invalid file link count modifier `l'"))))
473 (forward-char)) 500 (lambda (file)
474 (unless (looking-at "[0-9]+") 501 (when-let ((attrs (eshell-file-attributes file)))
475 (error "Invalid file link count modifier `l'")) 502 (funcall qual (file-attribute-link-number attrs) amount)))))
476 (setq amount (string-to-number (match-string 0)))
477 (goto-char (match-end 0))
478 (let ((f (if (eq qual ?-)
479 #'<
480 (if (eq qual ?+)
481 #'>
482 #'=))))
483 (lambda (file)
484 (let ((attrs (eshell-file-attributes file)))
485 (if attrs
486 (funcall f (file-attribute-link-number attrs) amount)))))))
487 503
488(defun eshell-pred-file-size () 504(defun eshell-pred-file-size ()
489 "Return a predicate to test whether a file is of a given size." 505 "Return a predicate to test whether a file is of a given size."
@@ -498,85 +514,52 @@ that `ls -l' will show in the first column of its display."
498 ((eq qual ?p) 514 ((eq qual ?p)
499 (setq quantum 512))) 515 (setq quantum 512)))
500 (forward-char)) 516 (forward-char))
501 (when (memq (char-after) '(?- ?+)) 517 (setq qual (eshell-get-comparison-modifier-argument))
502 (setq qual (char-after)) 518 (setq amount (* (or (eshell-get-numeric-modifier-argument)
503 (forward-char)) 519 (error "Invalid file size modifier `L'"))
504 (unless (looking-at "[0-9]+") 520 quantum))
505 (error "Invalid file size modifier `L'")) 521 (lambda (file)
506 (setq amount (* (string-to-number (match-string 0)) quantum)) 522 (when-let ((attrs (eshell-file-attributes file)))
507 (goto-char (match-end 0)) 523 (funcall qual (file-attribute-size attrs) amount)))))
508 (let ((f (if (eq qual ?-)
509 #'<
510 (if (eq qual ?+)
511 #'>
512 #'=))))
513 (lambda (file)
514 (let ((attrs (eshell-file-attributes file)))
515 (if attrs
516 (funcall f (file-attribute-size attrs) amount)))))))
517 524
518(defun eshell-pred-substitute (&optional repeat) 525(defun eshell-pred-substitute (&optional repeat)
519 "Return a modifier function that will substitute matches." 526 "Return a modifier function that will substitute matches."
520 (let ((delim (char-after)) 527 (let* ((match (or (eshell-get-delimited-modifier-argument t)
521 match replace end) 528 (error "Malformed pattern string for modifier `s'")))
522 (forward-char) 529 (replace (or (eshell-get-delimited-modifier-argument)
523 (setq end (eshell-find-delimiter delim delim nil nil t) 530 (error "Malformed replace string for modifier `s'")))
524 match (buffer-substring-no-properties (point) end)) 531 (function (if repeat
525 (goto-char (1+ end)) 532 (lambda (str)
526 (setq end (eshell-find-delimiter delim delim nil nil t) 533 (replace-regexp-in-string match replace str t))
527 replace (buffer-substring-no-properties (point) end)) 534 (lambda (str)
528 (goto-char (1+ end)) 535 (if (string-match match str)
529 (if repeat 536 (replace-match replace t nil str)
530 (lambda (lst) 537 (error (concat str ": substitution failed")))))))
531 (mapcar 538 (lambda (lst) (mapcar function lst))))
532 (lambda (str) 539
533 (replace-regexp-in-string match replace str t)) 540(defun eshell-include-members (mod-char &optional invert-p)
534 lst)) 541 "Include only Lisp members matching a regexp.
535 (lambda (lst) 542If INVERT-P is non-nil, include only members not matching a regexp."
536 (mapcar 543 (let* ((regexp (or (eshell-get-delimited-modifier-argument)
537 (lambda (str) 544 (error "Malformed pattern string for modifier `%c'"
538 (if (string-match match str) 545 mod-char)))
539 (replace-match replace t nil str) 546 (predicates
540 (error (concat str ": substitution failed")))) 547 (list (if invert-p
541 lst))))) 548 (lambda (elem) (not (string-match regexp elem)))
542 549 (lambda (elem) (string-match regexp elem))))))
543(defun eshell-include-members (&optional invert-p) 550 (lambda (lst)
544 "Include only Lisp members matching a regexp." 551 (eshell-winnow-list lst nil predicates))))
545 (let ((delim (char-after))
546 regexp end)
547 (forward-char)
548 (setq end (eshell-find-delimiter delim delim nil nil t)
549 regexp (buffer-substring-no-properties (point) end))
550 (goto-char (1+ end))
551 (let ((predicates
552 (list (if invert-p
553 (lambda (elem) (not (string-match regexp elem)))
554 (lambda (elem) (string-match regexp elem))))))
555 (lambda (lst)
556 (eshell-winnow-list lst nil predicates)))))
557 552
558(defun eshell-join-members () 553(defun eshell-join-members ()
559 "Return a modifier function that join matches." 554 "Return a modifier function that join matches."
560 (let ((delim (char-after)) 555 (let ((str (or (eshell-get-delimited-modifier-argument)
561 str end) 556 " ")))
562 (if (not (memq delim '(?' ?/)))
563 (setq str " ")
564 (forward-char)
565 (setq end (eshell-find-delimiter delim delim nil nil t)
566 str (buffer-substring-no-properties (point) end))
567 (goto-char (1+ end)))
568 (lambda (lst) 557 (lambda (lst)
569 (mapconcat #'identity lst str)))) 558 (mapconcat #'identity lst str))))
570 559
571(defun eshell-split-members () 560(defun eshell-split-members ()
572 "Return a modifier function that splits members." 561 "Return a modifier function that splits members."
573 (let ((delim (char-after)) 562 (let ((sep (eshell-get-delimited-modifier-argument)))
574 sep end)
575 (when (memq delim '(?' ?/))
576 (forward-char)
577 (setq end (eshell-find-delimiter delim delim nil nil t)
578 sep (buffer-substring-no-properties (point) end))
579 (goto-char (1+ end)))
580 (lambda (lst) 563 (lambda (lst)
581 (mapcar 564 (mapcar
582 (lambda (str) 565 (lambda (str)
diff --git a/test/lisp/eshell/em-pred-tests.el b/test/lisp/eshell/em-pred-tests.el
index 7f88ac44755..4d2af392923 100644
--- a/test/lisp/eshell/em-pred-tests.el
+++ b/test/lisp/eshell/em-pred-tests.el
@@ -26,6 +26,7 @@
26(require 'ert) 26(require 'ert)
27(require 'esh-mode) 27(require 'esh-mode)
28(require 'eshell) 28(require 'eshell)
29(require 'em-pred)
29 30
30(require 'eshell-tests-helpers 31(require 'eshell-tests-helpers
31 (expand-file-name "eshell-tests-helpers" 32 (expand-file-name "eshell-tests-helpers"
@@ -254,8 +255,6 @@ read, write, and execute predicates to query the file's modes."
254 (cl-letf (((symbol-function 'eshell-user-id) 255 (cl-letf (((symbol-function 'eshell-user-id)
255 (lambda (name) (seq-position user-names name)))) 256 (lambda (name) (seq-position user-names name))))
256 (should (equal (eshell-eval-predicate files "u'one'") 257 (should (equal (eshell-eval-predicate files "u'one'")
257 '("/fake/uid=1")))
258 (should (equal (eshell-eval-predicate files "u{one}")
259 '("/fake/uid=1"))))))) 258 '("/fake/uid=1")))))))
260 259
261(ert-deftest em-pred-test/predicate-gid () 260(ert-deftest em-pred-test/predicate-gid ()
@@ -268,8 +267,6 @@ read, write, and execute predicates to query the file's modes."
268 (cl-letf (((symbol-function 'eshell-group-id) 267 (cl-letf (((symbol-function 'eshell-group-id)
269 (lambda (name) (seq-position group-names name)))) 268 (lambda (name) (seq-position group-names name))))
270 (should (equal (eshell-eval-predicate files "g'one'") 269 (should (equal (eshell-eval-predicate files "g'one'")
271 '("/fake/gid=1")))
272 (should (equal (eshell-eval-predicate files "g{one}")
273 '("/fake/gid=1"))))))) 270 '("/fake/gid=1")))))))
274 271
275(defmacro em-pred-test--time-deftest (name file-attribute predicate 272(defmacro em-pred-test--time-deftest (name file-attribute predicate
@@ -430,6 +427,8 @@ PREDICATE is the predicate used to query that attribute."
430 "Test that \":s/PAT/REP/\" replaces PAT with REP once." 427 "Test that \":s/PAT/REP/\" replaces PAT with REP once."
431 (should (equal (eshell-eval-predicate "bar" ":s/a/*/") "b*r")) 428 (should (equal (eshell-eval-predicate "bar" ":s/a/*/") "b*r"))
432 (should (equal (eshell-eval-predicate "bar" ":s|a|*|") "b*r")) 429 (should (equal (eshell-eval-predicate "bar" ":s|a|*|") "b*r"))
430 (should (equal (eshell-eval-predicate "bar" ":s{a}{*}") "b*r"))
431 (should (equal (eshell-eval-predicate "bar" ":s{a}'*'") "b*r"))
433 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":s/[ao]/*/") 432 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":s/[ao]/*/")
434 '("f*o" "b*r" "b*z"))) 433 '("f*o" "b*r" "b*z")))
435 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":s|[ao]|*|") 434 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":s|[ao]|*|")
@@ -450,23 +449,15 @@ PREDICATE is the predicate used to query that attribute."
450(ert-deftest em-pred-test/modifier-include () 449(ert-deftest em-pred-test/modifier-include ()
451 "Test that \":i/PAT/\" filters elements to include only ones matching PAT." 450 "Test that \":i/PAT/\" filters elements to include only ones matching PAT."
452 (should (equal (eshell-eval-predicate "foo" ":i/a/") nil)) 451 (should (equal (eshell-eval-predicate "foo" ":i/a/") nil))
453 (should (equal (eshell-eval-predicate "foo" ":i|a|") nil))
454 (should (equal (eshell-eval-predicate "bar" ":i/a/") "bar")) 452 (should (equal (eshell-eval-predicate "bar" ":i/a/") "bar"))
455 (should (equal (eshell-eval-predicate "bar" ":i|a|") "bar"))
456 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":i/a/") 453 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":i/a/")
457 '("bar" "baz")))
458 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":i|a|")
459 '("bar" "baz")))) 454 '("bar" "baz"))))
460 455
461(ert-deftest em-pred-test/modifier-exclude () 456(ert-deftest em-pred-test/modifier-exclude ()
462 "Test that \":x/PAT/\" filters elements to exclude any matching PAT." 457 "Test that \":x/PAT/\" filters elements to exclude any matching PAT."
463 (should (equal (eshell-eval-predicate "foo" ":x/a/") "foo")) 458 (should (equal (eshell-eval-predicate "foo" ":x/a/") "foo"))
464 (should (equal (eshell-eval-predicate "foo" ":x|a|") "foo"))
465 (should (equal (eshell-eval-predicate "bar" ":x/a/") nil)) 459 (should (equal (eshell-eval-predicate "bar" ":x/a/") nil))
466 (should (equal (eshell-eval-predicate "bar" ":x|a|") nil))
467 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":x/a/") 460 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":x/a/")
468 '("foo")))
469 (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":x|a|")
470 '("foo")))) 461 '("foo"))))
471 462
472(ert-deftest em-pred-test/modifier-split () 463(ert-deftest em-pred-test/modifier-split ()
@@ -516,7 +507,7 @@ PREDICATE is the predicate used to query that attribute."
516 '("baz" "bar" "foo")))) 507 '("baz" "bar" "foo"))))
517 508
518 509
519;; Combinations 510;; Miscellaneous
520 511
521(ert-deftest em-pred-test/combine-predicate-and-modifier () 512(ert-deftest em-pred-test/combine-predicate-and-modifier ()
522 "Test combination of predicates and modifiers." 513 "Test combination of predicates and modifiers."
@@ -526,4 +517,20 @@ PREDICATE is the predicate used to query that attribute."
526 (should (equal (eshell-eval-predicate files ".:e:u") 517 (should (equal (eshell-eval-predicate files ".:e:u")
527 '("el" "txt")))))) 518 '("el" "txt"))))))
528 519
520(ert-deftest em-pred-test/predicate-delimiters ()
521 "Test various delimiter pairs with predicates and modifiers."
522 (dolist (delims eshell-pred-delimiter-pairs)
523 (eshell-with-file-attributes-from-name
524 (let ((files '("/fake/uid=1" "/fake/uid=2"))
525 (user-names '("root" "one" "two")))
526 (cl-letf (((symbol-function 'eshell-user-id)
527 (lambda (name) (seq-position user-names name))))
528 (should (equal (eshell-eval-predicate
529 files (format "u%cone%c" (car delims) (cdr delims)))
530 '("/fake/uid=1"))))))
531 (should (equal (eshell-eval-predicate
532 '("foo" "bar" "baz")
533 (format ":j%c-%c" (car delims) (cdr delims)))
534 "foo-bar-baz"))))
535
529;; em-pred-tests.el ends here 536;; em-pred-tests.el ends here