mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Fix double display glitch in erase_lots().
If the cursor is on the rightmost column of the terminal and term->wrapnext is set, and the user asks to erase from the current position to the end of (at least) the line, what should happen? PuTTY's previous behaviour was to ignore term->wrapnext, and do the same thing we would have done without it: erase from the current physical cursor position to EOL inclusive, i.e. blank the character cell we just printed. But this is unfortunate if a program writes an interleaving of printing characters and ESC[K, which I recently found out is what gcc does in its colour-highlighted error messages: if the last printed char just before an ESC[K pushes the cursor into the deferred-wrap state, then the ESC[K blanks that character, and then we wrap to the next line. So one character of the error message ends up missing. xfce4-terminal and gnome-terminal take the approach in this situation of regarding the cursor position as _right_ at the end of the line, so no character cells get cleared at all, and the error message displays as intended. I think that's more sensible, so I've switched to doing the same thing. (xterm has different behaviour again: it blanks the character cell and also clears its analogue of the wrapnext flag. So in _their_ handling of this sequence of output, one character of the error message is still missing, but it looks as if it's been _omitted_ rather than replaced by a space.) Secondly, in the course of fixing that, I looked at the check_boundary call in erase_lots, which is supposed to ensure that if a wide CJK character straddles the boundary between what's being erased and what isn't, then both halves of the character are deleted. I had to modify that anyway because I was moving that very boundary, and in doing so, I noticed that even according to the previous behaviour, it had an off-by-one error. In the case where you send ESC[1K (meaning erase up to and including the cursor position), the call to check_boundary was performed on the _left_ edge of the cursor's character cell, when it should have been the right edge. So you could end up with an erase_char in the left half (i.e. a space) and still have the magic value UCSWIDE in the right half, causing the terminal to think you had a double-width U+0020 on the screen, which isn't supposed to be able to happen.
This commit is contained in:
parent
efcf164abe
commit
6f4083e682
41
terminal.c
41
terminal.c
@ -2439,15 +2439,48 @@ static void erase_lots(Terminal *term,
|
||||
end.x = 0;
|
||||
erase_lattr = true;
|
||||
}
|
||||
|
||||
/* This is the endpoint of the clearing operation that is not
|
||||
* either the start or end of the line / screen. */
|
||||
pos boundary = term->curs;
|
||||
|
||||
if (!from_begin) {
|
||||
start = term->curs;
|
||||
/*
|
||||
* If we're erasing from the current char to the end of
|
||||
* line/screen, then we take account of wrapnext, so as to
|
||||
* maintain the invariant that writing a printing character
|
||||
* followed by ESC[K should not overwrite the character you
|
||||
* _just wrote_. That is, when wrapnext says the cursor is
|
||||
* 'logically' at the very rightmost edge of the screen
|
||||
* instead of just before the last printing char, ESC[K should
|
||||
* do nothing at all, and ESC[J should clear the next line but
|
||||
* leave this one unchanged.
|
||||
*
|
||||
* This adjusted position will also be the position we use for
|
||||
* check_boundary (i.e. the thing we ensure isn't in the
|
||||
* middle of a double-width printing char).
|
||||
*/
|
||||
if (term->wrapnext)
|
||||
incpos(boundary);
|
||||
|
||||
start = boundary;
|
||||
}
|
||||
if (!to_end) {
|
||||
end = term->curs;
|
||||
incpos(end);
|
||||
/*
|
||||
* If we're erasing from the start of (at least) the line _to_
|
||||
* the current position, then that is taken to mean 'inclusive
|
||||
* of the cell under the cursor', which means we don't
|
||||
* consider wrapnext at all: whether it's set or not, we still
|
||||
* clear the cell under the cursor.
|
||||
*
|
||||
* Again, that incremented boundary position is where we
|
||||
* should be careful of a straddling wide character.
|
||||
*/
|
||||
incpos(boundary);
|
||||
end = boundary;
|
||||
}
|
||||
if (!from_begin || !to_end)
|
||||
check_boundary(term, term->curs.x, term->curs.y);
|
||||
check_boundary(term, boundary.x, boundary.y);
|
||||
check_selection(term, start, end);
|
||||
|
||||
/* Clear screen also forces a full window redraw, just in case. */
|
||||
|
Loading…
Reference in New Issue
Block a user