Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: bracketed paste - chopping trailing newlines



Daniel Shahaf wrote on Sun, Sep 06, 2015 at 09:52:24 +0000:
> Carsten Hey wrote on Fri, Sep 04, 2015 at 01:59:36 +0200:
> > An other main paste feature, not running a pasted command without user
> > interaction, would be disabled by this (which makes it, for my private
> > setup, a good candidate for being activated if needed by some currently
> > unused function key).
> > 
> > Btw., I also think that highlighting is sufficient to alert the user
> > that no command is running - that it vanishes if a command runs makes
> > this pretty clear for the second time, and the first time the previously
> > unseen highlighing should catch the attention of the users and make them
> > check what happend.  zle -M ... seems to be a bit too verbose for
> > a default behaviour.
> 
> I'm attaching a patch and a zshrc that together demonstrate the proposed
> behaviour.  To test them, apply the patch, run the resulting 'zsh -f',
> and source the script.
> 
> I propose to make the _resulting behaviour_ the default in 5.1.1.  However,
> before I spend time on rewriting the attached patch entirely in C, I'd
> like to ensure we have consensus for making this change.
> 
> The behaviour is: (a) pastes are never executed until <Enter> is pressed;
> (b) zle_highlight is set; (c) newlines are removed only at <accept-line>.

I've gone ahead and prepared a patch series that implementes that behaviour
entirely in C.  It's attached.

From 5fff3ba4c26ec7105a54f0189a53145d4a287541 Mon Sep 17 00:00:00 2001
From: Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx>
Date: Wed, 2 Sep 2015 12:16:39 +0000
Subject: [PATCH 1/3] Revert "35834: strip a final newline from pasted text:
 inserting is hard to tell apart from accepting it"

This reverts commit f17eb26a34af69a2238a3d8b46079445e09c096e.

Conflicts:
	ChangeLog
	Src/Zle/zle_misc.c
---
 ChangeLog          | 1 +
 Src/Zle/zle_misc.c | 6 ------
 2 files changed, 1 insertion(+), 6 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index cdaed18..bfb71f4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -371,6 +371,7 @@
 
 	* 36125: Src/Zle/zle_hist.c: don't set history context in get-line
 
+	[reverted in NNNNN]
 	* 35834 (tweaked): Src/Zle/zle_misc.c: strip a final newline from
 	pasted text: inserting is hard to tell apart from accepting it
 
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 2d18628..c1005dc 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -787,12 +787,6 @@ bracketedpaste(char **args)
 	    zmult = 1;
 	    if (region_active)
 		killregion(zlenoargs);
-	    /* Chop a final newline if its insertion would be hard to
-	     * distinguish by the user from the line being accepted. */
-	    else if (n > 1 && zlecontext != ZLCON_VARED &&
-		    (zlecs + (insmode ? 0 : n - 1)) >= zlell &&
-		    wpaste[n-1] == ZWC('\n'))
-		n--;
 	    yankcs = yankb = zlecs;
 	    doinsert(wpaste, n);
 	    yanke = zlecs;
-- 
2.1.4

From 2266d4e4e56dcad8c35ec7f57973f69b0b278ff9 Mon Sep 17 00:00:00 2001
From: Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx>
Date: Mon, 7 Sep 2015 15:50:26 +0000
Subject: [PATCH 2/3] Set zle_highlight=(paste:standout) by default.

---
 Doc/Zsh/zle.yo        | 2 +-
 Src/Zle/zle_refresh.c | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 4e93695..05bae3c 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -2656,7 +2656,7 @@ If tt(zle_highlight) is not set or no value applies to a particular
 context, the defaults applied are equivalent to
 
 example(zle_highlight=LPAR()region:standout special:standout
-suffix:bold isearch:underline+RPAR())
+suffix:bold isearch:underline paste:standout+RPAR())
 
 i.e. both the region and special characters are shown in standout mode.
 
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 0c28c0a..6facff4 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -372,7 +372,8 @@ zle_set_highlight(void)
 	region_highlights[1].atr = TXTUNDERLINE;
     if (!suffix_atr_on_set)
 	region_highlights[2].atr = TXTBOLDFACE;
-        /* paste defaults to 0 */
+    if (!paste_atr_on_set)
+	region_highlights[3].atr = TXTSTANDOUT;
 
     allocate_colour_buffer();
 }
-- 
2.1.4

From a0e7bfb791703f140fdbe3aee5c24f490945228c Mon Sep 17 00:00:00 2001
From: Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx>
Date: Mon, 7 Sep 2015 17:10:03 +0000
Subject: [PATCH 3/3] accept-line, accept-and-hold,
 accept-and-infer-next-history: Strip trailing newline after paste.

---
 Src/Zle/zle_hist.c |  4 ++++
 Src/Zle/zle_misc.c | 25 +++++++++++++++++++++++++
 Src/utils.c        | 32 ++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index c61b4ef..c3d7c1a 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -1728,12 +1728,16 @@ infernexthist(Histent he, UNUSED(char **args))
     return NULL;
 }
 
+/* Defined in zle_misc.c */
+void zle_strip_trailing_newline_if_after_paste(void);
+
 /**/
 int
 acceptandinfernexthistory(char **args)
 {
     Histent he;
 
+    zle_strip_trailing_newline_if_after_paste();
     if (!(he = infernexthist(hist_ring, args)))
 	return 1;
     zpushnode(bufstack, ztrdup(he->node.nam));
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index c1005dc..dac31bf 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -395,10 +395,34 @@ poundinsert(UNUSED(char **args))
     return 0;
 }
 
+/* Declare non-static so zle_hist.c can use it */
+void zle_strip_trailing_newline_if_after_paste(void);
+
+/* If the last widget is a paste, and the last byte is a newline, strip it.
+ *
+ * If it was syntactically whitespace, that's cleaner; and if it was
+ * significant, it will be re-added latre.
+ */
+void zle_strip_trailing_newline_if_after_paste(void)
+{
+    if (lbindk == Th(z_bracketedpaste)) {
+	if (zlemetaline ? zlemetall : zlell) {
+	    char last = zlemetaline ? ztr_last(zlemetaline) : zleline[zlell-1];
+	    if (last == ZWC('\n')) {
+		/* backwarddeletechar() doesn't use ARGS, but be conservative
+		 * and pass them empty. */
+		static char *empty_args[] = { NULL };
+		backwarddeletechar(empty_args);
+	    }
+	}
+    }
+}
+
 /**/
 int
 acceptline(UNUSED(char **args))
 {
+    zle_strip_trailing_newline_if_after_paste();
     done = 1;
     return 0;
 }
@@ -407,6 +431,7 @@ acceptline(UNUSED(char **args))
 int
 acceptandhold(UNUSED(char **args))
 {
+    zle_strip_trailing_newline_if_after_paste();
     zpushnode(bufstack, zlelineasstring(zleline, zlell, 0, NULL, NULL, 0));
     stackcs = zlecs;
     done = 1;
diff --git a/Src/utils.c b/Src/utils.c
index ca68eae..325997a 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -4483,6 +4483,38 @@ unmeta(const char *file_name)
     return fn;
 }
 
+/* Return the last character of a metafied non-empty string */
+
+/**/
+mod_export char
+ztr_last(char const *s)
+{
+    char last;
+
+    if (!*s) {
+	DPUTS(1, "BUG: ztr_last() called on empty string\n");
+
+	/* We must return some value.  Hopefully NUL is good enough. */
+	return '\0';
+    }
+
+    while (*s) {
+	if (*s == Meta) {
+	    ++s;
+	    if (! *s) {
+		DPUTS(1, "BUG: unexpected end of string in ztr_last()\n");
+
+		/* We must return some value.  Hopefully NUL is good enough. */
+		return '\0';
+	    }
+	    last = *s++ ^ 32;
+	}
+	else
+	    last = *s++;
+    }
+    return last;
+}
+
 /*
  * Unmetafy and compare two strings, comparing unsigned character values.
  * "a\0" sorts after "a".
-- 
2.1.4



Messages sorted by: Reverse Date, Date, Thread, Author