port to crossterm
This commit is contained in:
parent
f3f1c4de94
commit
f5da786053
5 changed files with 315 additions and 115 deletions
228
Cargo.lock
generated
228
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
66
src/main.rs
66
src/main.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
41
src/util.rs
41
src/util.rs
|
@ -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())
|
||||
|
|
Loading…
Reference in a new issue