gyscos / gyscos/cursive

[BUG] cursive with crossterm or termion backends redraws the screen every time

Open
#667 4 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
4.8k
Forks
270
Avg merge
5d 19h
Merged PRs (30d)
2

Description

**Describe the bug**

With default `ncurses` backend, `cursive` applications feel smooth and does not blink in e.g. Alacritty.
But with other backends (crossterm and termion), it seems like it just redraws the entire screen each time something is updated.

Also in scenario where `ncurses` backend write only 11 KB to the tty, but with the pure-Rust backends I see 174 KB of data. This may become problematic if TUI applications are accessed over SSH with bad network.

**To Reproduce**

1. Build some cursive application with multiple backends.

Example application
```
extern crate cursive_table_view;

use std::cmp::Ordering;

use cursive::{
align::HAlign,
traits::{Nameable, Resizable},
views::{TextView, LinearLayout, TextArea},
Cursive, With,
};
use cursive_table_view::{TableView, TableViewItem};

#[derive(Copy, Clone, PartialEq, Eq, Hash)]
enum MyColumn {
Name,
Count,
Rate,
}

#[derive(Clone, Debug)]
struct Foo {
name: String,
count: usize,
rate: usize,
}

impl TableViewItem for Foo {
fn to_column(&self, column: MyColumn) -> String {
match column {
MyColumn::Name => self.name.to_string(),
MyColumn::Count => format!("{}", self.count),
MyColumn::Rate => format!("{}", self.rate),
}
}

fn cmp(&self, other: &Self, column: MyColumn) -> Ordering
where
Self: Sized,
{
match column {
MyColumn::Name => self.name.cmp(&other.name),
MyColumn::Count => self.count.cmp(&other.count),
MyColumn::Rate => self.rate.cmp(&other.rate),
}
}
}

fn main() {
let mut siv = cursive::default();

// Configure the actual table
let table = TableView::::new()
.column(MyColumn::Name, "Name", |c| c.width(20))
.column(MyColumn::Count, "Count", |c| c.align(HAlign::Center))
.column(MyColumn::Rate, "Rate", |c| {
c.ordering(Ordering::Greater).align(HAlign::Right).width(20)
})
.default_column(MyColumn::Name)
.with(|table| {
table.insert_item(Foo {
count: 3,
name: "QQQ".to_owned(),
rate: 4,
});
table.insert_item(Foo {
count: 2,
name: "WWW".to_owned(),
rate: 40,
});
table.insert_item(Foo {
count: 0,
name: "EEE".to_owned(),
rate: 0,
});
})
.on_submit(|siv: &mut Cursive, _row: usize, index: usize| {
siv.call_on_name("q", |t: &mut TableView| {
if let Some(i) = t.borrow_item_mut(index) {
i.count += 1;
}
});
});

let linear_layout = LinearLayout::vertical()
.child(TextView::new("Top of the page"))
.child(TextArea::new().fixed_height(8).full_width())
.child(table.with_name("q").full_height().full_width());

siv.add_fullscreen_layer(linear_layout.full_screen());

siv.run();
}
```

2. Run those multiple versions on Linux (e.g. in Alacritty + tmux)
3. Compare how the feel

**Expected behavior**

Applications differ only by their filesize and dynamic dependencies, maybe some tricky feature support.

**Environment**
* Linux Debian, Xorg
* Backend used: ncurses, crossterm, termion
* Current locale: C.UTF-8
* Cursive version: 0.18.0

**Other notes**

If this cannot be fixed easily, then it should be documented in ["Backends" wiki article](https://github.com/gyscos/cursive/wiki/Backends).
This blinking and tty bandwidth usage may be overseen by deploying developer, who might think that by switching to crossterm/termion one just gains easy deployment without any apparent loss in functionality.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.