From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Jay Kamat Newsgroups: gmane.emacs.bugs Subject: bug#29821: Ensure quick substitution only occurs at start of line Date: Thu, 04 Jan 2018 17:53:14 -0800 Message-ID: <87373lhy0l.fsf@gmail.com> References: <87fu8272h6.fsf@gmail.com> <87shbqto33.fsf@users.sourceforge.net> <87wp11rqtr.fsf@users.sourceforge.net> <871sj96lgu.fsf@gmail.com> <87tvw4syi9.fsf@users.sourceforge.net> <87wp105ezz.fsf@gmail.com> <87o9mbso9j.fsf@users.sourceforge.net> <87po6q5sns.fsf@gmail.com> <87a7xus4hr.fsf@users.sourceforge.net> <877esxid5o.fsf@gmail.com> <877esxru9i.fsf@users.sourceforge.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: blaine.gmane.org 1515117144 21747 195.159.176.226 (5 Jan 2018 01:52:24 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Fri, 5 Jan 2018 01:52:24 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.90 (gnu/linux) Cc: 29821@debbugs.gnu.org, Andreas Schwab To: Noam Postavsky Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Fri Jan 05 02:52:19 2018 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eXHB4-0004uQ-Ih for geb-bug-gnu-emacs@m.gmane.org; Fri, 05 Jan 2018 02:52:10 +0100 Original-Received: from localhost ([::1]:33567 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eXHD3-0003NF-Tn for geb-bug-gnu-emacs@m.gmane.org; Thu, 04 Jan 2018 20:54:13 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:35671) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eXHCx-0003M0-8c for bug-gnu-emacs@gnu.org; Thu, 04 Jan 2018 20:54:08 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eXHCs-0000fE-9D for bug-gnu-emacs@gnu.org; Thu, 04 Jan 2018 20:54:07 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:55732) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eXHCr-0000f2-SN for bug-gnu-emacs@gnu.org; Thu, 04 Jan 2018 20:54:01 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1eXHCr-0002vJ-LU for bug-gnu-emacs@gnu.org; Thu, 04 Jan 2018 20:54:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Jay Kamat Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Jan 2018 01:54:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 29821 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 29821-submit@debbugs.gnu.org id=B29821.151511720411189 (code B ref 29821); Fri, 05 Jan 2018 01:54:01 +0000 Original-Received: (at 29821) by debbugs.gnu.org; 5 Jan 2018 01:53:24 +0000 Original-Received: from localhost ([127.0.0.1]:36180 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eXHCG-0002uP-92 for submit@debbugs.gnu.org; Thu, 04 Jan 2018 20:53:24 -0500 Original-Received: from mail-pg0-f45.google.com ([74.125.83.45]:34286) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eXHCF-0002uB-2Y for 29821@debbugs.gnu.org; Thu, 04 Jan 2018 20:53:23 -0500 Original-Received: by mail-pg0-f45.google.com with SMTP id j4so1446479pgp.1 for <29821@debbugs.gnu.org>; Thu, 04 Jan 2018 17:53:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=sl9Fc7yYos9GAxrp0gazOnBLDqkbJSEbmuqlsfF7TWA=; b=BJ2SlHeDNXCiGMNCM6m2Wxoolh5cQFxLoThe6QiPaDTN05qLdTxCCnRmFLj7Bs6xKA CvnsykaJ59eJod8TeGtZPIelRM69F2Ck46FgSqHufEaDVIO5I9HW15V9qdVdgLnMYn0D KanI8V+Uj9dojapfxO1Q0LbGYL16yuwzYUKqiyRlPPtVBgNBYWqZC8dsFly0mK1pbKif oMrzXg4qVfQN8EVglQbqSHv/TTfJtJ2Gv6LOKPdmgqU0CN1fHw6JCZYrrexEOGjjnEfz eEHpXeAkgaubZ6sWKgv8xhfWnfYpoCg5AfiYMd0l94OD7FRPZYJF947+bPUwHwbaUbUX RNEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=sl9Fc7yYos9GAxrp0gazOnBLDqkbJSEbmuqlsfF7TWA=; b=en1hzDg2G/IG1jouOO/Gs5fzLSI96YaoxcDAIOmp2VmAJJLd3E6BDzbLzqFfwHGIG7 xzahVN+6/lAI3h36JPpvH4xYscHmb364Slv+L8QXQVZDoeViNUqXUSSNj6Ho/7RI3pve hsvfUyZQ+7qiYJLsW7rNnfY0hH1wfZ1TBTaEH3wX7KtrZB015abUOU//KltSX6fnWSsY YRqg9/vDC1bJBjvw7k6Qw5jFosXQK8sCmsehpMP3nTjqJKR53bf3fx+HQfx0cLMgQoOg ATaV5X4/TT9xEs5uLqXLGIJeU2aY7rRjUp8efqMEluBWaX2e4M+j2QpwwF06zCpgYZ96 Y+gA== X-Gm-Message-State: AKGB3mIwpFsPof8/BADQ3NA90cOhsoy0U41yOpA6voFZJT067thAcTqk oX53c42ICU2DCVxJIIDIekI= X-Google-Smtp-Source: ACJfBovHadWk3hWo151UeXmrIwPUl98sC6PLOF2lLsb/64DL3ntDp/JUT4iafEkaruq+IoG9FkUgPA== X-Received: by 10.99.96.69 with SMTP id u66mr1192399pgb.355.1515117197148; Thu, 04 Jan 2018 17:53:17 -0800 (PST) Original-Received: from laythe (c-67-161-9-47.hsd1.ca.comcast.net. [67.161.9.47]) by smtp.gmail.com with ESMTPSA id g1sm8384925pgc.32.2018.01.04.17.53.14 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 04 Jan 2018 17:53:15 -0800 (PST) In-Reply-To: <877esxru9i.fsf@users.sourceforge.net> (Noam Postavsky's message of "Thu, 04 Jan 2018 20:04:09 -0500") X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:141787 Archived-At: --=-=-= Content-Type: text/plain Noam Postavsky writes: > There doesn't need to be trailing whitespace between the last "^" and > subsequent text, bash: > So I think this should do it? > > ... > (string-match > "^\\^\\([^^]+\\)\\^\\([^^]+\\)\\(?:\\^\\(.*\\)\\)?$" > line)) > ;; Save trailing match as `eshell-history-reference' runs string-match. > (let ((matched-end (match-string 3 line))) > ... Yup, that regex works perfectly for everything I tried, and preserves the white-space at the end of the target (as bash does). I think it's a good idea to follow bash as closely as possible. For convenience, I've attached a new patch with those changes. Thanks, -Jay --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=0001-Prevent-expansion-of-quick-substitutions-when-not-at.patch >From b901ce56d646d7145989825f7c4b8d408bc500ac Mon Sep 17 00:00:00 2001 From: Jay Kamat 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 In Addition: - 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. --- lisp/eshell/em-hist.el | 60 +++++++++++++++++++++++++++++++++----------------- 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 df462a7058..f923ca679b 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,31 @@ eshell-complete-history-reference (setq history (cdr history))) (cdr fhist))))))) +(defun eshell-history-substitution (line) + "Expand quick hist substitutions formatted as ^foo^bar^. +Returns nil if string does not match quick substitution format, +and acts like !!:s/foo/bar/ otherwise." + ;; `^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 + "^\\^\\([^^]+\\)\\^\\([^^]+\\)\\(?:\\^\\(.*\\)\\)?$" + line)) + ;; Save trailing match as `eshell-history-reference' runs string-match. + (let ((matched-end (match-string 3 line))) + (concat + (eshell-history-reference + (format "!!:s/%s/%s/" + (match-string 1 line) + (match-string 2 line))) + matched-end)))) + (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 (. diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el index 72a7bc4afc..86a9d4262a 100644 --- a/lisp/eshell/em-pred.el +++ b/lisp/eshell/em-pred.el @@ -545,7 +545,8 @@ eshell-pred-substitute (function (lambda (str) (if (string-match ,match str) - (setq str (replace-match ,replace t nil str))) + (setq str (replace-match ,replace t nil str)) + (error (concat str ": substitution failed"))) str)) lst))))) (defun eshell-include-members (&optional invert-p) -- 2.11.0 --=-=-=--