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:
parent
d592696ca7
commit
5076fe2dda
@ -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
|
||||
|
||||
|
@ -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) => {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user