1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 02:25:28 +03:00

term: fix rewrap issue for lines == terminal width

closes: https://github.com/wez/wezterm/issues/971
This commit is contained in:
Wez Furlong 2021-07-22 07:49:18 -07:00
parent d592696ca7
commit 5076fe2dda
3 changed files with 41 additions and 10 deletions

View File

@ -59,6 +59,7 @@ As features stabilize some brief notes about them will accumulate here.
* New: [window_frame](config/lua/config/window_frame.md) option to configure Wayland window decorations [#761](https://github.com/wez/wezterm/issues/761)
* New: [window:get_appearance()] to determine if the window has a dark mode appearance, and adjust color scheme to match [#806](https://github.com/wez/wezterm/issues/806)
* Improved: [improve the new-tab button formatting](config/lua/config/tab_bar_style.md). Thanks to [@sdrik](https://github.com/sdrik)! [#950](https://github.com/wez/wezterm/pull/950)
* Fixed: if a line of text was exactly the width of the terminal it would get marked as wrappable even when followed by a newline, causing text to reflow incorrectly on resize. [#971](https://github.com/wez/wezterm/issues/971)
### 20210502-154244-3f7122cb

View File

@ -2969,7 +2969,7 @@ impl<'a> DerefMut for Performer<'a> {
impl<'a> Drop for Performer<'a> {
fn drop(&mut self) {
self.flush_print();
self.flush_print(false);
}
}
@ -2991,13 +2991,16 @@ impl<'a> Performer<'a> {
Self { state, print: None }
}
fn flush_print(&mut self) {
fn flush_print(&mut self, cr_follows: bool) {
let p = match self.print.take() {
Some(s) => s,
None => return,
};
for g in unicode_segmentation::UnicodeSegmentation::graphemes(p.as_str(), true) {
let mut graphemes =
unicode_segmentation::UnicodeSegmentation::graphemes(p.as_str(), true).peekable();
while let Some(g) = graphemes.next() {
let g = if (self.shift_out && self.g1_charset == CharSet::DecLineDrawing)
|| (!self.shift_out && self.g0_charset == CharSet::DecLineDrawing)
{
@ -3061,8 +3064,15 @@ impl<'a> Performer<'a> {
// If we didn't do this, then we'd effectively filter them out from
// the model, which seems like a lossy design choice.
let print_width = unicode_column_width(g).max(1);
let is_last = graphemes.peek().is_none();
if x + print_width >= width {
// We're going to mark the cell as being wrapped, but not if this grapheme
// is the last in this run and we know that we're followed by a CR.
// In that case, we know that there is an explicit line break and
// we mustn't record a wrap for that!
let wrappable = (x + print_width >= width) && !(is_last && cr_follows);
if wrappable {
pen.set_wrapped(true);
}
@ -3077,10 +3087,19 @@ impl<'a> Performer<'a> {
}
// Assign the cell
log::trace!("print x={} y={} cell={:?}", x, y, cell);
log::trace!(
"print x={} y={} is_last={} cr_follows={} print_width={} width={} cell={:?}",
x,
y,
is_last,
cr_follows,
print_width,
width,
cell
);
self.screen_mut().set_cell(x, y, &cell);
if x + print_width < width {
if !wrappable {
self.cursor.x += print_width;
self.wrap_next = false;
} else {
@ -3173,7 +3192,8 @@ impl<'a> Performer<'a> {
}
fn control(&mut self, control: ControlCode) {
self.flush_print();
let cr_follows = matches!(control, ControlCode::CarriageReturn);
self.flush_print(cr_follows);
match control {
ControlCode::LineFeed | ControlCode::VerticalTab | ControlCode::FormFeed => {
if self.left_and_right_margins.contains(&self.cursor.x) {
@ -3266,7 +3286,7 @@ impl<'a> Performer<'a> {
}
fn csi_dispatch(&mut self, csi: CSI) {
self.flush_print();
self.flush_print(false);
match csi {
CSI::Sgr(sgr) => self.state.perform_csi_sgr(sgr),
CSI::Cursor(cursor) => self.state.perform_csi_cursor(cursor),
@ -3282,7 +3302,7 @@ impl<'a> Performer<'a> {
}
fn esc_dispatch(&mut self, esc: Esc) {
self.flush_print();
self.flush_print(false);
match esc {
Esc::Code(EscCode::StringTerminator) => {
// String Terminator (ST); explicitly has nothing to do here, as its purpose is
@ -3390,7 +3410,7 @@ impl<'a> Performer<'a> {
}
fn osc_dispatch(&mut self, osc: OperatingSystemCommand) {
self.flush_print();
self.flush_print(false);
match osc {
OperatingSystemCommand::SetIconNameSun(title)
| OperatingSystemCommand::SetIconName(title) => {

View File

@ -768,6 +768,16 @@ fn test_resize_wrap() {
);
}
#[test]
fn test_resize_wrap_issue_971() {
const LINES: usize = 4;
let mut term = TestTerm::new(LINES, 4, 0);
term.print("====\r\nSS\r\n");
assert_visible_contents(&term, file!(), line!(), &["====", "SS", "", ""]);
term.resize(LINES, 6, 0, 0);
assert_visible_contents(&term, file!(), line!(), &["====", "SS", "", ""]);
}
#[test]
fn test_scrollup() {
let mut term = TestTerm::new(2, 1, 4);