From: Jay Kamat <jaygkamat@gmail.com>
To: Noam Postavsky <npostavs@users.sourceforge.net>
Cc: 29821@debbugs.gnu.org
Subject: bug#29821: Ensure quick substitution only occurs at start of line
Date: Mon, 01 Jan 2018 15:44:59 -0800 [thread overview]
Message-ID: <87608l6t50.fsf@gmail.com> (raw)
In-Reply-To: <87shbqto33.fsf@users.sourceforge.net> (Noam Postavsky's message of "Sun, 31 Dec 2017 19:33:20 -0500")
[-- Attachment #1: Type: text/plain, Size: 2111 bytes --]
Noam Postavsky <npostavs@users.sourceforge.net> writes:
> Hmm, using history expansion would mean typing
>
> M-p DEL C-a M-f M-d M-d ! ! : $
>
> to get
>
> mv !!:$ two.txt
>
> vs
>
> M-p C-a M-f M-d M-d C-k C-y C-y DEL
>
> to get
>
> mv two.txtt two.txt
>
> Hardly seems worth the trouble of learning this syntax (and occasionally
> triggering accidentally, which is why I disable it in bash too). Is
> having history expansion enabled by default very important? You can
> still enable it in your config.
I do suppose that is true, but I still find myself preferring history
substitution in some cases, such as typing a new command but preserving
the last argument.
I don't think it's too important that history expansion is enabled by
default, but I do think it's important to have it available as an
option. I think that turning it off would startle some users, especially
because it's featured in some popular 'getting started' articles for
eshell (such as this one:
https://masteringemacs.org/article/complete-guide-mastering-eshell), but
the decision is up to you.
I would much prefer a variable (perhaps defaulting to off) to tweak this
setting on or of rather than adding/removing a function to the hook.
Removing it in the current way makes it feel more 'deprecated' to me,
rather than 'disabled by default'.
Would you mind if I submitted a patch to add a new
`eshell-history-expansion-enabled' variable (or similar)?
> I guess it's an improvement on what we have currently (the feature is
> rather underspecified). Should we consider also handling spaces like
> bash does? In bash I can do this:
>
> ~/tmp$ echo foo bar
> foo bar
> ~/tmp$ ^foo bar^blah^
> echo blah
> blah
>
> In eshell (with and without your patch) I get:
>
> ~/src/emacs $ echo foo bar
> ("foo" "bar")
> ~/src/emacs $ ^foo bar^blah^
> ^foo: command not found
I've attached a new patch which attempts to solve this as well. I'm
unfamiliar with eshell internals though, so I'm not sure if it's done
properly. Let me know if anyone sees any issues with it!
Thanks,
-Jay
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Prevent-expansion-of-quick-substitutions-when-not-at.patch --]
[-- Type: text/x-diff, Size: 3995 bytes --]
From 573b03a76798496b3bcfcada1557f1a9d83cc987 Mon Sep 17 00:00:00 2001
From: Jay Kamat <jaygkamat@gmail.com>
Date: Fri, 22 Dec 2017 15:34:44 -0800
Subject: [PATCH] Prevent expansion of quick substitutions when not at start of
line
See bug #29157 for an initial report
Also, allow spaces inside substitutions, so ^foo bar^baz works.
* 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.
---
lisp/eshell/em-hist.el | 57 ++++++++++++++++++++++++++++++++------------------
1 file changed, 37 insertions(+), 20 deletions(-)
diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el
index df462a7058..d4d4b93b81 100644
--- a/lisp/eshell/em-hist.el
+++ b/lisp/eshell/em-hist.el
@@ -581,21 +581,30 @@ eshell-hist-parse-arguments
(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)
@@ -630,20 +639,28 @@ eshell-complete-history-reference
(setq history (cdr history)))
(cdr fhist)))))))
+(defun eshell-history-substitution (line)
+ "Expand whole-line history substitutions by converting them to
+!!:s/a/b/ syntax.
+Returns nil if no match found."
+ ;; `^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 "^\\^\\([^^]+\\)\\^\\([^^]+\\)\\^?\\s-*$"
+ line))
+ (let* ((reference (format "!!:s/%s/%s/"
+ (match-string 1 line)
+ (match-string 2 line)))
+ (result (eshell-history-reference reference)))
+ (unless (eq result reference)
+ result))))
+
(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 (.
--
2.11.0
prev parent reply other threads:[~2018-01-01 23:44 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-12-22 23:57 bug#29821: Ensure quick substitution only occurs at start of line Jay Kamat
2018-01-01 0:33 ` Noam Postavsky
2018-01-01 9:56 ` Andreas Schwab
2018-01-02 1:29 ` Noam Postavsky
2018-01-02 2:30 ` Jay Kamat
2018-01-02 3:58 ` Noam Postavsky
2018-01-02 17:48 ` Jay Kamat
2018-01-03 1:51 ` Noam Postavsky
2018-01-04 1:17 ` Jay Kamat
2018-01-04 3:10 ` Noam Postavsky
2018-01-04 20:26 ` Jay Kamat
2018-01-05 1:04 ` Noam Postavsky
2018-01-05 1:53 ` Jay Kamat
2018-01-05 14:31 ` Noam Postavsky
2018-01-01 23:44 ` Jay Kamat [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87608l6t50.fsf@gmail.com \
--to=jaygkamat@gmail.com \
--cc=29821@debbugs.gnu.org \
--cc=npostavs@users.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).