port to crossterm

This commit is contained in:
Crispy 2023-03-04 11:26:57 +01:00
parent f3f1c4de94
commit f5da786053
5 changed files with 315 additions and 115 deletions

228
Cargo.lock generated
View file

@ -2,12 +2,49 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossterm"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
dependencies = [
"bitflags",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
dependencies = [
"winapi",
]
[[package]]
name = "libc"
version = "0.2.139"
@ -18,14 +55,62 @@ checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
name = "lili"
version = "0.1.0"
dependencies = [
"termion",
"crossterm",
]
[[package]]
name = "numtoa"
version = "0.1.0"
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "mio"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]]
name = "redox_syscall"
@ -37,22 +122,137 @@ dependencies = [
]
[[package]]
name = "redox_termios"
version = "0.1.2"
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "signal-hook"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
dependencies = [
"redox_syscall",
"libc",
"signal-hook-registry",
]
[[package]]
name = "termion"
version = "2.0.1"
name = "signal-hook-mio"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "659c1f379f3408c7e5e84c7d0da6d93404e3800b6b9d063ba24436419302ec90"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
dependencies = [
"libc",
"numtoa",
"redox_syscall",
"redox_termios",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"

View file

@ -6,4 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
termion = "2.0.1"
crossterm = "0.26.1"

View file

@ -1,15 +1,16 @@
use crossterm::{
cursor::{self, MoveTo},
event::{self, Event, KeyCode, KeyModifiers},
queue,
style::{Color, Colors, ResetColor, SetColors},
terminal::{self, Clear, ClearType},
};
use std::{
fs::{self, File},
io::{stdin, stdout, Write},
io::{stdout, Write},
ops::Range,
vec,
};
use termion::{
clear, color, cursor,
event::{Event, Key},
input::TermRead,
terminal_size,
};
use crate::util::read_line;
use crate::{clipboard::Clipboard, util::RangeConverter};
@ -87,34 +88,39 @@ impl Editor {
}
fn input(&mut self) {
for event in stdin().events().take(1).flatten() {
if let Event::Key(key) = event {
match key {
Key::Esc => self.active = false,
Key::Char(char) => self.insert_char(char),
Key::Backspace => self.backspace(),
Key::Delete => self.delete(),
Key::Left => self.move_left(),
Key::Right => self.move_right(),
Key::Up => self.move_up(),
Key::Down => self.move_down(),
Key::Home => self.move_home(),
Key::End => self.move_end(),
Key::Ctrl('s') => self.save(),
Key::Ctrl('p') => self.toggle_marker(),
Key::Ctrl('c') => self.copy(),
Key::Ctrl('x') => self.cut(),
Key::Ctrl('v') => self.paste(),
match event::read() {
Ok(Event::Key(event)) => match event.modifiers {
KeyModifiers::NONE => match event.code {
KeyCode::Esc => self.active = false,
KeyCode::Char(ch) => self.insert_char(ch),
KeyCode::Backspace => self.backspace(),
KeyCode::Delete => self.delete(),
KeyCode::Left => self.move_left(),
KeyCode::Right => self.move_right(),
KeyCode::Up => self.move_up(),
KeyCode::Down => self.move_down(),
KeyCode::Home => self.move_home(),
KeyCode::End => self.move_end(),
_ => (),
}
}
},
KeyModifiers::CONTROL => match event.code {
KeyCode::Char('s') => self.save(),
KeyCode::Char('p') => self.toggle_marker(),
KeyCode::Char('c') => self.copy(),
KeyCode::Char('x') => self.cut(),
KeyCode::Char('v') => self.paste(),
_ => (),
},
_ => (),
},
_ => (),
}
}
fn draw(&self) {
print!("{}", clear::All);
queue!(stdout(), Clear(ClearType::All)).unwrap();
let max_rows = terminal_size().unwrap().1 as usize - 1;
let max_rows = terminal::size().unwrap().1 as usize - 1;
let end = (self.scroll + max_rows).min(self.lines.len());
let visible_rows = self.scroll..end;
@ -125,7 +131,7 @@ impl Editor {
for (line_index, line) in self.lines[visible_rows].iter().enumerate() {
let text = &self.text[line.clone()];
print!("{}", cursor::Goto(1, line_index as u16 + 1));
queue!(stdout(), MoveTo(0, line_index as u16)).unwrap();
if self.marker.is_none() {
print!("{}", text.replace('\t', &" ".repeat(TAB_SIZE)));
@ -150,21 +156,22 @@ impl Editor {
}
}
self.status_line();
print!(
"{}{}",
cursor::Goto(
self.physical_column() as u16 + 1,
(self.cursor.line - self.scroll) as u16 + 1
queue!(
stdout(),
MoveTo(
self.physical_column() as u16,
(self.cursor.line - self.scroll) as u16
),
cursor::Show
);
)
.unwrap();
stdout().flush().unwrap();
}
fn status_line(&self) {
queue!(stdout(), MoveTo(0, terminal::size().unwrap().1)).unwrap();
print!(
"{}({}, {}) {}",
cursor::Goto(1, terminal_size().unwrap().1),
"({},{}) {}",
self.cursor.line,
self.physical_column(),
self.name(),
@ -213,7 +220,7 @@ impl Editor {
self.cursor.line += 1;
self.cursor.column = physical_column.min(self.current_line().len());
self.ensure_char_boundary();
if self.cursor.line > (self.scroll + terminal_size().unwrap().1 as usize - 2) {
if self.cursor.line > (self.scroll + terminal::size().unwrap().1 as usize - 2) {
self.scroll += 1;
}
}
@ -379,13 +386,9 @@ impl Editor {
}
fn color_selection() {
print!(
"{}{}",
color::Fg(color::Black),
color::Bg(color::LightBlack)
);
queue!(stdout(), SetColors(Colors::new(Color::Black, Color::White))).unwrap();
}
fn color_reset() {
print!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset));
queue!(stdout(), ResetColor).unwrap();
}

View file

@ -1,15 +1,18 @@
use crossterm::{
cursor::{self, MoveTo},
event::{self, Event, KeyCode, KeyModifiers},
execute, queue,
style::{Color, Colors, ResetColor, SetColors},
terminal::{
disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen,
LeaveAlternateScreen,
},
};
use std::{
env,
io::{stdin, stdout, Stdout, Write},
io::{stdout, Write},
process::exit,
};
use termion::{
clear, color,
cursor::{self, Goto},
event::{Event, Key},
input::TermRead,
raw::{IntoRawMode, RawTerminal},
};
mod clipboard;
mod editor;
@ -25,12 +28,10 @@ struct Navigator {
editors: Vec<Editor>,
selected: Option<usize>,
clipboard: Clipboard,
_term: RawTerminal<Stdout>,
}
impl Navigator {
fn new() -> Self {
let term = stdout().into_raw_mode().unwrap();
let clipboard = Clipboard::new();
let mut editors: Vec<Editor> = env::args()
.skip(1)
@ -43,13 +44,12 @@ impl Navigator {
editors,
selected: Some(0),
clipboard,
_term: term,
}
}
fn run(mut self) {
print!("{}", clear::All);
stdout().flush().unwrap();
execute!(stdout(), EnterAlternateScreen, Clear(ClearType::All)).unwrap();
enable_raw_mode().unwrap();
loop {
self.draw();
@ -58,41 +58,38 @@ impl Navigator {
}
fn draw(&self) {
print!(
"{}{}{}Open editors: {}",
clear::All,
cursor::Hide,
Goto(1, 1),
self.editors.len()
);
queue!(stdout(), Clear(ClearType::All), cursor::Hide, MoveTo(0, 0)).unwrap();
print!("Open editors: {}", self.editors.len());
for (index, editor) in self.editors.iter().enumerate() {
if Some(index) == self.selected {
print!("{}{}", color::Fg(color::Black), color::Bg(color::White));
queue!(stdout(), SetColors(Colors::new(Color::Black, Color::White))).unwrap();
}
queue!(stdout(), MoveTo(1, index as u16 + 1)).unwrap();
print!(
"{}{}{}",
Goto(2, index as u16 + 2),
"{}{}",
editor.has_unsaved_changes().then_some("*").unwrap_or(" "),
editor.name()
);
print!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset));
queue!(stdout(), ResetColor).unwrap();
}
stdout().flush().unwrap();
}
fn input(&mut self) {
for event in stdin().events().take(1).flatten() {
if let Event::Key(key) = event {
match key {
Key::Char('q') => self.quit(),
Key::Char('\n') => self.open_selected(),
Key::Ctrl('n') => self.new_editor(),
Key::Up => self.nav_up(),
Key::Down => self.nav_down(),
_ => (),
if let Ok(Event::Key(event)) = event::read() {
match event.code {
KeyCode::Char('q') => self.quit(),
KeyCode::Up => self.nav_up(),
KeyCode::Down => self.nav_down(),
KeyCode::Enter => self.open_selected(),
KeyCode::Char('n') => {
if event.modifiers == KeyModifiers::CONTROL {
self.new_editor();
}
}
_ => (),
}
}
}
@ -124,7 +121,8 @@ impl Navigator {
}
fn quit(&self) {
print!("{}{}", clear::All, cursor::Show);
disable_raw_mode().unwrap();
execute!(stdout(), LeaveAlternateScreen, cursor::Show).unwrap();
exit(0);
}
}

View file

@ -1,37 +1,36 @@
use std::{
io::{stdin, stdout, Write},
ops::Range,
};
use termion::{
use crossterm::{
cursor,
event::{Event, Key},
input::TermRead,
terminal_size,
event::{self, Event, KeyCode},
queue, terminal,
};
use std::{
io::{stdout, Write},
ops::Range,
};
pub fn read_line(prompt: &str) -> Option<String> {
let mut response = String::new();
let size = terminal_size().unwrap();
let start_pos = cursor::Goto(1, size.1);
let width = size.0 as usize;
let size = terminal::size().unwrap();
let start_pos = cursor::MoveTo(0, size.1);
print!("{start_pos}{prompt}{response}",);
queue!(stdout(), start_pos).unwrap();
print!("{prompt}");
stdout().flush().unwrap();
for event in stdin().events() {
if let Ok(Event::Key(key)) = event {
match key {
Key::Char('\n') => break,
Key::Char(ch) => response.push(ch),
Key::Backspace => {
loop {
if let Ok(Event::Key(event)) = event::read() {
match event.code {
KeyCode::Enter => break,
KeyCode::Char(ch) => response.push(ch),
KeyCode::Backspace => {
response.pop();
print!("{start_pos}{:width$}", " ");
}
Key::Esc => return None,
KeyCode::Esc => return None,
_ => (),
}
}
print!("{start_pos}{prompt}{response}",);
queue!(stdout(), start_pos).unwrap();
print!("{prompt}{response} ");
stdout().flush().unwrap();
}
Some(response.trim().into())