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 uses: actions-rs/cargo@v1
with: with:
command: test command: test
env:
RUST_BACKTRACE: full
- name: "Clippy" - name: "Clippy"
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@ -75,3 +77,5 @@ jobs:
with: with:
command: test command: test
args: --no-default-features --features=crossterm --tests --examples args: --no-default-features --features=crossterm --tests --examples
env:
RUST_BACKTRACE: full

@ -2,6 +2,10 @@
## To be released ## 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 ## v0.10.0 - 2020-07-17
### Breaking changes ### Breaking changes

@ -58,16 +58,13 @@ where
let mut fg = Color::Reset; let mut fg = Color::Reset;
let mut bg = Color::Reset; let mut bg = Color::Reset;
let mut modifier = Modifier::empty(); let mut modifier = Modifier::empty();
let mut last_y = 0; let mut last_pos: Option<(u16, u16)> = None;
let mut last_x = 0;
map_error(queue!(string, MoveTo(0, 0)))?;
for (x, y, cell) in content { 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)))?; map_error(queue!(string, MoveTo(x, y)))?;
} }
last_x = x; last_pos = Some((x, y));
last_y = y;
if cell.modifier != modifier { if cell.modifier != modifier {
let diff = ModifierDiff { let diff = ModifierDiff {
from: modifier, from: modifier,

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