fix(backend): move the cursor when first diff is on second cell

Both termion and crossterm backends were not moving the cursor if the first diff to draw was on the
second cell. The condition triggering the cursor move has been updated to fix this. In addition, two
tests have been added to avoid future regressions.
pull/349/head
Florian Dehau 4 years ago
parent 641f391137
commit ecb482f297

@ -47,6 +47,8 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
env:
RUST_BACKTRACE: full
- name: "Clippy"
uses: actions-rs/cargo@v1
with:
@ -75,3 +77,5 @@ jobs:
with:
command: test
args: --no-default-features --features=crossterm --tests --examples
env:
RUST_BACKTRACE: full

@ -2,6 +2,10 @@
## To be released
### Fixes
* Fix incorrect output when the first diff to draw is on the second cell of the terminal (#347).
## v0.10.0 - 2020-07-17
### Breaking changes

@ -58,16 +58,13 @@ where
let mut fg = Color::Reset;
let mut bg = Color::Reset;
let mut modifier = Modifier::empty();
let mut last_y = 0;
let mut last_x = 0;
map_error(queue!(string, MoveTo(0, 0)))?;
let mut last_pos: Option<(u16, u16)> = None;
for (x, y, cell) in content {
if y != last_y || x != last_x + 1 {
// Move the cursor if the previous location was not (x - 1, y)
if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) {
map_error(queue!(string, MoveTo(x, y)))?;
}
last_x = x;
last_y = y;
last_pos = Some((x, y));
if cell.modifier != modifier {
let diff = ModifierDiff {
from: modifier,

@ -1,13 +1,13 @@
use std::fmt;
use std::io;
use std::io::Write;
use super::Backend;
use crate::{
buffer::Cell,
layout::Rect,
style::{Color, Modifier},
};
use std::{
fmt,
io::{self, Write},
};
pub struct TermionBackend<W>
where
@ -82,15 +82,13 @@ where
let mut fg = Color::Reset;
let mut bg = Color::Reset;
let mut modifier = Modifier::empty();
let mut last_y = 0;
let mut last_x = 0;
write!(string, "{}", termion::cursor::Goto(1, 1)).unwrap();
let mut last_pos: Option<(u16, u16)> = None;
for (x, y, cell) in content {
if y != last_y || x != last_x + 1 {
// Move the cursor if the previous location was not (x - 1, y)
if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) {
write!(string, "{}", termion::cursor::Goto(x + 1, y + 1)).unwrap();
}
last_x = x;
last_y = y;
last_pos = Some((x, y));
if cell.modifier != modifier {
write!(
string,

@ -0,0 +1,63 @@
#[cfg(feature = "termion")]
#[test]
fn backend_termion_should_only_write_diffs() -> Result<(), Box<dyn std::error::Error>> {
use std::{fmt::Write, io::Cursor};
let mut bytes = Vec::new();
let mut stdout = Cursor::new(&mut bytes);
{
use tui::{
backend::TermionBackend, layout::Rect, widgets::Paragraph, Terminal, TerminalOptions,
Viewport,
};
let backend = TermionBackend::new(&mut stdout);
let area = Rect::new(0, 0, 3, 1);
let mut terminal = Terminal::with_options(
backend,
TerminalOptions {
viewport: Viewport::fixed(area),
},
)?;
terminal.draw(|f| {
f.render_widget(Paragraph::new("a"), area);
})?;
terminal.draw(|f| {
f.render_widget(Paragraph::new("ab"), area);
})?;
terminal.draw(|f| {
f.render_widget(Paragraph::new("abc"), area);
})?;
}
let expected = {
use termion::{color, cursor, style};
let mut s = String::new();
// First draw
write!(s, "{}", cursor::Goto(1, 1))?;
s.push_str("a");
write!(s, "{}", color::Fg(color::Reset))?;
write!(s, "{}", color::Bg(color::Reset))?;
write!(s, "{}", style::Reset)?;
write!(s, "{}", cursor::Hide)?;
// Second draw
write!(s, "{}", cursor::Goto(2, 1))?;
s.push_str("b");
write!(s, "{}", color::Fg(color::Reset))?;
write!(s, "{}", color::Bg(color::Reset))?;
write!(s, "{}", style::Reset)?;
write!(s, "{}", cursor::Hide)?;
// Third draw
write!(s, "{}", cursor::Goto(3, 1))?;
s.push_str("c");
write!(s, "{}", color::Fg(color::Reset))?;
write!(s, "{}", color::Bg(color::Reset))?;
write!(s, "{}", style::Reset)?;
write!(s, "{}", cursor::Hide)?;
// Terminal drop
write!(s, "{}", cursor::Show)?;
s
};
assert_eq!(std::str::from_utf8(&bytes)?, expected);
Ok(())
}
Loading…
Cancel
Save