Experiment with TUI so we can render selections.

This commit is contained in:
Blaž Hrastnik 2020-09-07 18:10:08 +09:00
parent 67017e5336
commit 9ad40bc40b
3 changed files with 70 additions and 7 deletions

20
Cargo.lock generated
View File

@ -212,6 +212,12 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
[[package]]
name = "cassowary"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "cc"
version = "1.0.59"
@ -420,6 +426,7 @@ dependencies = [
"helix-core",
"num_cpus",
"smol",
"tui",
]
[[package]]
@ -738,6 +745,19 @@ dependencies = [
"utf-8",
]
[[package]]
name = "tui"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a977b0bb2e2033a6fef950f218f13622c3c34e59754b704ce3492dedab1dfe95"
dependencies = [
"bitflags",
"cassowary",
"crossterm",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "unicode-segmentation"
version = "1.6.0"

View File

@ -22,6 +22,5 @@ crossterm = { version = "0.17.7", features = ["event-stream"] }
smol = "0.4"
futures = { version = "0.3.5", default-features = false, features = ["std", "async-await"] }
num_cpus = "1.13.0"
tui = { version = "0.10.0", default-features = false, features = ["crossterm"] }
# futures-timer = "3.0.2"
# tui = { version = "0.9.5", default-features = false }

View File

@ -14,9 +14,17 @@
use std::path::PathBuf;
use std::time::Duration;
use tui::backend::CrosstermBackend;
use tui::buffer::Buffer as Surface;
use tui::layout::Rect;
use tui::style::Style;
type Terminal = tui::Terminal<CrosstermBackend<std::io::Stdout>>;
static EX: smol::Executor = smol::Executor::new();
pub struct Editor {
terminal: Terminal,
state: Option<State>,
first_line: u16,
size: (u16, u16),
@ -24,7 +32,12 @@ pub struct Editor {
impl Editor {
pub fn new(mut args: Args) -> Result<Self, Error> {
let backend = CrosstermBackend::new(stdout());
let mut terminal = Terminal::new(backend)?;
let mut editor = Editor {
terminal,
state: None,
first_line: 0,
size: terminal::size().unwrap(),
@ -45,6 +58,9 @@ pub fn open(&mut self, path: PathBuf) -> Result<(), Error> {
fn render(&mut self) {
match &self.state {
Some(state) => {
let area = Rect::new(0, 0, self.size.0, self.size.1);
let mut surface = Surface::empty(area);
let lines = state
.doc
.lines_at(self.first_line as usize)
@ -60,12 +76,33 @@ fn render(&mut self) {
cursor::MoveTo(0, n as u16),
Print((n + 1).to_string())
);
execute!(
stdout,
SetForegroundColor(Color::Reset),
cursor::MoveTo(2, n as u16),
Print(line)
surface.set_string(2, n as u16, line, Style::default());
// execute!(
// stdout,
// SetForegroundColor(Color::Reset),
// cursor::MoveTo(2, n as u16),
// Print(line)
// );
}
// iterate over selections and render them
let select = Style::default().bg(tui::style::Color::LightBlue);
let text = state.doc.slice(..);
for range in state.selection.ranges() {
// get terminal coords for x,y for each range pos
// TODO: this won't work with multiline
let (y1, x1) = coords_at_pos(&text, range.from());
let (y2, x2) = coords_at_pos(&text, range.to());
let area = Rect::new(
(x1 + 2) as u16,
y1 as u16,
(x2 - x1 + 1) as u16,
(y2 - y1 + 1) as u16,
);
surface.set_style(area, select);
// TODO: don't highlight next char in append mode
}
let mode = match state.mode {
@ -80,6 +117,13 @@ fn render(&mut self) {
Print(mode)
);
use tui::backend::Backend;
// TODO: double buffer and diff here
let empty = Surface::empty(area);
self.terminal
.backend_mut()
.draw(empty.diff(&surface).into_iter());
// set cursor shape
match state.mode {
Mode::Insert => write!(stdout, "\x1B[6 q"),