Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: [PATCH] use clear-to-end to reduce trailing whitespace
- X-seq: zsh-workers 53315
- From: Daniel Colascione <dancol@xxxxxxxxxx>
- To: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>
- Cc: zsh-workers@xxxxxxx
- Subject: Re: [PATCH] use clear-to-end to reduce trailing whitespace
- Date: Sun, 19 Jan 2025 15:52:26 -0800
- Archived-at: <https://zsh.org/workers/53315>
- In-reply-to: <CAH+w=7aWgKLzQ6MZfsyEYabdGic0qX6tfsC4HX4g8vBAW-+Lpw@mail.gmail.com> (Bart Schaefer's message of "Fri, 17 Jan 2025 13:02:41 -0800")
- List-id: <zsh-workers.zsh.org>
- References: <87ed121ui4.fsf@dancol.org> <CAH+w=7bXVUpVVZ-wauCQTchCJK60zaqCSZUV+KKQ93tNoe2VDQ@mail.gmail.com> <CAH+w=7aWgKLzQ6MZfsyEYabdGic0qX6tfsC4HX4g8vBAW-+Lpw@mail.gmail.com>
Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> writes:
> On Fri, Jan 17, 2025 at 12:36 PM Bart Schaefer
> <schaefer@xxxxxxxxxxxxxxxx> wrote:
>>
>> 2) I'd also like to hear more feedback about discarding the "hasam"
>> conditional test. Are there really no longer any automargin terminals
>> suffering from the wrap bug?
>
> For background -- and I may be recalling this incorrectly -- the bug
> in question is:
> * There are N logical spaces after the last non-space character and
> before the lower-right corner of the display, and
> * The number of characters in the clear-to-eol sequence is N or more, then
> * Emitting the clear-to-eol sequence will cause the automargin
> terminal to scroll up one line
The attached new version of the patch should handle right prompts too. I
tested it with both zero and non-zero right prompt margins.
As for automargins:
I also tested a bunch of terminals. I was unable to get any of them to
mistakenly scroll due to issuing a clear-to-end-of-line at the right
edge of the screen. I tested:
* xterm (394)
* urxvt
* VTE (via Sakura)
* Emacs term-mode
* screen
* tmux
* alacritty
* kitty
* putty
* Terminal.app
* iterm2
See the attached program
commit 3123dcdb12818b9619f63f5b24c1a8833acae30d
Author: Daniel Colascione <dancol@xxxxxxxxxx>
Date: Wed Jan 15 12:23:31 2025 -0800
Always use TCCLEAREOL when available to clear trailing spaces
Simplify the logic around using TCCLEAREOL to clear to end of line.
Instead of complex conditions about line wrapping, right prompts,
and cost comparisons, just use TCCLEAREOL whenever it's available.
This fixes an issue where trailing spaces would appear when switching
between lines of different lengths (e.g. when using up/down arrows).
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index f076bdd61..b6efe22ca 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -1792,24 +1792,20 @@ refreshline(int ln)
nllen = ollen;
}
-/* 2: see if we can clear to end-of-line, and if it's faster, work out where
- to do it from - we can normally only do so if there's no right-prompt.
- With automatic margins, we shouldn't do it if there is another line, in
- case it messes up cut and paste. */
-
- if (hasam && ln < nlnct - 1 && rnllen == winw)
- col_cleareol = -2; /* clearing eol would be evil so don't */
- else {
- col_cleareol = -1;
- if (tccan(TCCLEAREOL) && (nllen == winw || put_rpmpt != oput_rpmpt)) {
- for (i = nllen; i && ZR_equal(zr_sp, nl[i - 1]); i--)
- ;
- for (j = ollen; j && ZR_equal(ol[j - 1], zr_sp); j--)
- ;
- if ((j > i + tclen[TCCLEAREOL]) /* new buf has enough spaces */
- || (nllen == winw && ZR_equal(zr_sp, nl[winw - 1])))
- col_cleareol = i;
- }
+/* 2: see if we can clear to end-of-line. Always use TCCLEAREOL when
+ available to avoid leaving trailing spaces when moving between
+ lines of different lengths. Don't do this when we have a right
+ prompt. */
+
+ col_cleareol = -1;
+ if (tccan(TCCLEAREOL) && !put_rpmpt) {
+ /* Find rightmost non-space character in main line */
+ for (i = nllen; i && ZR_equal(zr_sp, nl[i - 1]); i--)
+ ;
+ for (j = nllen; j && ZR_equal(zr_sp, ol[j - 1]); j--)
+ ;
+ if (j > i)
+ col_cleareol = i;
}
/* 2b: first a new trick for automargin niceness - good for cut and paste */
@@ -1892,8 +1888,7 @@ refreshline(int ln)
}
if ((char_ins <= 0) || (ccs >= winw)) /* written everything */
return;
- if (tccan(TCCLEAREOL) && (char_ins >= tclen[TCCLEAREOL])
- && col_cleareol != -2)
+ if (tccan(TCCLEAREOL) && col_cleareol != -2)
/* we've got junk on the right yet to clear */
col_cleareol = 0; /* force a clear to end of line */
}
import curses
import sys
import time
def test_corner_clear():
curses.setupterm()
stdout = sys.stdout.buffer
clear_to_eol = curses.tigetstr('el')
cursor_address = curses.tigetstr('cup')
cursor_left = b'\b'
cols = curses.tigetnum('cols')
rows = curses.tigetnum('lines')
has_am = curses.tigetflag('am')
print(f"Terminal has automatic margins: {has_am}")
print(f"Clear to EOL sequence length: {len(clear_to_eol)} bytes")
print(f"Clear to EOL sequence (raw): {repr(clear_to_eol)}")
print("\nMoving to last line for test...")
def _flush_and_wait():
stdout.flush()
time.sleep(0.5)
stdout.write(curses.tparm(cursor_address, rows, 0))
stdout.write((b'XY'*((cols + 1) // 2))[:cols])
_flush_and_wait()
stdout.write(b'\r')
stdout.write((b'12'*((cols + 1) // 2))[:(cols-1)])
_flush_and_wait()
stdout.write(clear_to_eol)
_flush_and_wait()
stdout.write(b'\n')
_flush_and_wait()
if __name__ == "__main__":
test_corner_clear()
Messages sorted by:
Reverse Date,
Date,
Thread,
Author