diff options
| author | Jay Kamat | 2017-12-22 15:34:44 -0800 |
|---|---|---|
| committer | Noam Postavsky | 2018-01-05 09:29:00 -0500 |
| commit | 933d8fc0b70452f8a266e761231e58a759a7c80a (patch) | |
| tree | 255939a4a1f1e651559dedda47964f2f192dc725 | |
| parent | 1cc7bc0f63ab118fda55aa40fa4b571a7c94393e (diff) | |
| download | emacs-933d8fc0b70452f8a266e761231e58a759a7c80a.tar.gz emacs-933d8fc0b70452f8a266e761231e58a759a7c80a.zip | |
Make eshell history expansion more like bash (Bug#29821)
- Prevent expansion of quick substitutions when the initial "^" is not
at start of line (Bug#29157).
- Allow spaces inside substitutions, so "^foo bar^baz" works.
- Allow trailing characters after substitution, so "^foo^bar^trailing"
works.
- Throw an error when substitution does not match.
* lisp/eshell/em-hist.el (eshell-expand-history-references): Expand
history substitution before other types of expansions, and expand them
with the whole line.
(eshell-history-substitution): New function to expand only
substitutions, taking in the entire typed line rather than individual
arguments.
| -rw-r--r-- | lisp/eshell/em-hist.el | 60 | ||||
| -rw-r--r-- | lisp/eshell/em-pred.el | 3 |
2 files changed, 42 insertions, 21 deletions
diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el index 83595847bdf..62e2f57d0fd 100644 --- a/lisp/eshell/em-hist.el +++ b/lisp/eshell/em-hist.el | |||
| @@ -581,21 +581,30 @@ See also `eshell-read-history'." | |||
| 581 | 581 | ||
| 582 | (defun eshell-expand-history-references (beg end) | 582 | (defun eshell-expand-history-references (beg end) |
| 583 | "Parse and expand any history references in current input." | 583 | "Parse and expand any history references in current input." |
| 584 | (let ((result (eshell-hist-parse-arguments beg end))) | 584 | (let ((result (eshell-hist-parse-arguments beg end)) |
| 585 | (full-line (buffer-substring-no-properties beg end))) | ||
| 585 | (when result | 586 | (when result |
| 586 | (let ((textargs (nreverse (nth 0 result))) | 587 | (let ((textargs (nreverse (nth 0 result))) |
| 587 | (posb (nreverse (nth 1 result))) | 588 | (posb (nreverse (nth 1 result))) |
| 588 | (pose (nreverse (nth 2 result)))) | 589 | (pose (nreverse (nth 2 result))) |
| 590 | (full-line-subst (eshell-history-substitution full-line))) | ||
| 589 | (save-excursion | 591 | (save-excursion |
| 590 | (while textargs | 592 | (if full-line-subst |
| 591 | (let ((str (eshell-history-reference (car textargs)))) | 593 | ;; Found a ^foo^bar substitution |
| 592 | (unless (eq str (car textargs)) | 594 | (progn |
| 593 | (goto-char (car posb)) | 595 | (goto-char beg) |
| 594 | (insert-and-inherit str) | 596 | (insert-and-inherit full-line-subst) |
| 595 | (delete-char (- (car pose) (car posb))))) | 597 | (delete-char (- end beg))) |
| 596 | (setq textargs (cdr textargs) | 598 | ;; Try to expand other substitutions |
| 597 | posb (cdr posb) | 599 | (while textargs |
| 598 | pose (cdr pose)))))))) | 600 | (let ((str (eshell-history-reference (car textargs)))) |
| 601 | (unless (eq str (car textargs)) | ||
| 602 | (goto-char (car posb)) | ||
| 603 | (insert-and-inherit str) | ||
| 604 | (delete-char (- (car pose) (car posb))))) | ||
| 605 | (setq textargs (cdr textargs) | ||
| 606 | posb (cdr posb) | ||
| 607 | pose (cdr pose))))))))) | ||
| 599 | 608 | ||
| 600 | (defvar pcomplete-stub) | 609 | (defvar pcomplete-stub) |
| 601 | (defvar pcomplete-last-completion-raw) | 610 | (defvar pcomplete-last-completion-raw) |
| @@ -630,20 +639,31 @@ See also `eshell-read-history'." | |||
| 630 | (setq history (cdr history))) | 639 | (setq history (cdr history))) |
| 631 | (cdr fhist))))))) | 640 | (cdr fhist))))))) |
| 632 | 641 | ||
| 642 | (defun eshell-history-substitution (line) | ||
| 643 | "Expand quick hist substitutions formatted as ^foo^bar^. | ||
| 644 | Returns nil if string does not match quick substitution format, | ||
| 645 | and acts like !!:s/foo/bar/ otherwise." | ||
| 646 | ;; `^string1^string2^' | ||
| 647 | ;; Quick Substitution. Repeat the last command, replacing | ||
| 648 | ;; STRING1 with STRING2. Equivalent to `!!:s/string1/string2/' | ||
| 649 | (when (and (eshell-using-module 'eshell-pred) | ||
| 650 | (string-match | ||
| 651 | "^\\^\\([^^]+\\)\\^\\([^^]+\\)\\(?:\\^\\(.*\\)\\)?$" | ||
| 652 | line)) | ||
| 653 | ;; Save trailing match as `eshell-history-reference' runs string-match. | ||
| 654 | (let ((matched-end (match-string 3 line))) | ||
| 655 | (concat | ||
| 656 | (eshell-history-reference | ||
| 657 | (format "!!:s/%s/%s/" | ||
| 658 | (match-string 1 line) | ||
| 659 | (match-string 2 line))) | ||
| 660 | matched-end)))) | ||
| 661 | |||
| 633 | (defun eshell-history-reference (reference) | 662 | (defun eshell-history-reference (reference) |
| 634 | "Expand directory stack REFERENCE. | 663 | "Expand directory stack REFERENCE. |
| 635 | The syntax used here was taken from the Bash info manual. | 664 | The syntax used here was taken from the Bash info manual. |
| 636 | Returns the resultant reference, or the same string REFERENCE if none | 665 | Returns the resultant reference, or the same string REFERENCE if none |
| 637 | matched." | 666 | matched." |
| 638 | ;; `^string1^string2^' | ||
| 639 | ;; Quick Substitution. Repeat the last command, replacing | ||
| 640 | ;; STRING1 with STRING2. Equivalent to `!!:s/string1/string2/' | ||
| 641 | (if (and (eshell-using-module 'eshell-pred) | ||
| 642 | (string-match "\\^\\([^^]+\\)\\^\\([^^]+\\)\\^?\\s-*$" | ||
| 643 | reference)) | ||
| 644 | (setq reference (format "!!:s/%s/%s/" | ||
| 645 | (match-string 1 reference) | ||
| 646 | (match-string 2 reference)))) | ||
| 647 | ;; `!' | 667 | ;; `!' |
| 648 | ;; Start a history substitution, except when followed by a | 668 | ;; Start a history substitution, except when followed by a |
| 649 | ;; space, tab, the end of the line, = or (. | 669 | ;; space, tab, the end of the line, = or (. |
diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el index 2c12cacfff8..61af4048d54 100644 --- a/lisp/eshell/em-pred.el +++ b/lisp/eshell/em-pred.el | |||
| @@ -545,7 +545,8 @@ that `ls -l' will show in the first column of its display. " | |||
| 545 | (function | 545 | (function |
| 546 | (lambda (str) | 546 | (lambda (str) |
| 547 | (if (string-match ,match str) | 547 | (if (string-match ,match str) |
| 548 | (setq str (replace-match ,replace t nil str))) | 548 | (setq str (replace-match ,replace t nil str)) |
| 549 | (error (concat str ": substitution failed"))) | ||
| 549 | str)) lst))))) | 550 | str)) lst))))) |
| 550 | 551 | ||
| 551 | (defun eshell-include-members (&optional invert-p) | 552 | (defun eshell-include-members (&optional invert-p) |