aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Kamat2017-12-22 15:34:44 -0800
committerNoam Postavsky2018-01-05 09:29:00 -0500
commit933d8fc0b70452f8a266e761231e58a759a7c80a (patch)
tree255939a4a1f1e651559dedda47964f2f192dc725
parent1cc7bc0f63ab118fda55aa40fa4b571a7c94393e (diff)
downloademacs-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.el60
-rw-r--r--lisp/eshell/em-pred.el3
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^.
644Returns nil if string does not match quick substitution format,
645and 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.
635The syntax used here was taken from the Bash info manual. 664The syntax used here was taken from the Bash info manual.
636Returns the resultant reference, or the same string REFERENCE if none 665Returns the resultant reference, or the same string REFERENCE if none
637matched." 666matched."
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)