Changed backend to crossterm
This commit is contained in:
parent
1822cf4237
commit
85880255af
|
@ -1,5 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
|
@ -8,9 +10,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -31,6 +33,31 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c85525306c4291d1b73ce93c8acf9c339f9b213aef6c1d85c3830cbf1c16325c"
|
||||
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 = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
|
@ -40,12 +67,30 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
||||
dependencies = [
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
|
@ -82,7 +127,7 @@ name = "nikki"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"termion",
|
||||
"crossterm",
|
||||
"tokio",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
|
@ -126,18 +171,37 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numtoa"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.7"
|
||||
|
@ -172,12 +236,30 @@ 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.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
||||
dependencies = [
|
||||
"redox_syscall",
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -189,6 +271,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.74"
|
||||
|
@ -200,18 +288,6 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"numtoa",
|
||||
"redox_syscall",
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
|
|
|
@ -8,8 +8,8 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
termion = "1"
|
||||
unicode-segmentation = "1"
|
||||
crossterm = "0.22"
|
||||
unicode-width = "0.1.7"
|
||||
tokio = { version = "1", features = ["time", "signal", "rt", "rt-multi-thread", "sync", "macros"] }
|
||||
chrono = "0.4"
|
||||
chrono = "0.4"
|
||||
|
|
|
@ -1,23 +1,45 @@
|
|||
use termion::color;
|
||||
|
||||
use color::Rgb;
|
||||
use crossterm::style;
|
||||
use crossterm::style::Color;
|
||||
use crossterm::style::Color::Rgb;
|
||||
|
||||
pub struct Colorscheme {
|
||||
pub title: Rgb,
|
||||
pub subtitle: Rgb,
|
||||
pub text: Rgb,
|
||||
pub background: Rgb,
|
||||
pub status_text: Rgb,
|
||||
pub status_background: Rgb,
|
||||
pub currentline: Rgb,
|
||||
pub highlighted_background: Rgb,
|
||||
pub highlighted_text: Rgb,
|
||||
pub title: Color,
|
||||
pub subtitle: Color,
|
||||
pub text: Color,
|
||||
pub background: Color,
|
||||
pub status_text: Color,
|
||||
pub status_background: Color,
|
||||
pub currentline: Color,
|
||||
pub highlighted_background: Color,
|
||||
pub highlighted_text: Color,
|
||||
}
|
||||
|
||||
pub const WHITE: Rgb = Rgb(230, 230, 230);
|
||||
pub const GRAY: Rgb = Rgb(163, 163, 163);
|
||||
pub const GRAY2: Rgb = Rgb(189, 189, 189);
|
||||
pub const BLACK: Rgb = Rgb(40, 40, 40);
|
||||
pub const WHITE: Color = Rgb {
|
||||
r: 230,
|
||||
g: 230,
|
||||
b: 230,
|
||||
};
|
||||
pub const GRAY: Color = Rgb {
|
||||
r: 163,
|
||||
g: 163,
|
||||
b: 163,
|
||||
};
|
||||
pub const GRAY2: Color = Rgb {
|
||||
r: 189,
|
||||
g: 189,
|
||||
b: 189,
|
||||
};
|
||||
pub const BLACK: Color = Rgb {
|
||||
r: 40,
|
||||
g: 40,
|
||||
b: 40,
|
||||
};
|
||||
|
||||
// pub const BLACK2: Color = Rgb {
|
||||
// r: 20,
|
||||
// g: 20,
|
||||
// b: 20,
|
||||
// };
|
||||
|
||||
impl Colorscheme {
|
||||
pub fn default() -> Self {
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::Position;
|
|||
use crate::Row;
|
||||
use std::fs;
|
||||
use std::io::{Error, Write};
|
||||
use std::usize;
|
||||
|
||||
pub struct Document {
|
||||
rows: Vec<Row>,
|
||||
|
@ -81,6 +82,57 @@ impl Document {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn insert_text(&mut self, at: &Position, text: String) {
|
||||
let mut lines: Vec<Row> = text.split('\n').map(Row::from).collect();
|
||||
|
||||
let prev_line = self.rows.get_mut(at.y).unwrap();
|
||||
let end_line = prev_line.split(at.x);
|
||||
|
||||
let l = lines.len();
|
||||
|
||||
if l == 1 {
|
||||
let new_row = Row::from(&text[..]);
|
||||
|
||||
prev_line.append(&new_row);
|
||||
prev_line.append(&end_line);
|
||||
} else {
|
||||
prev_line.append(&lines[0]);
|
||||
|
||||
lines[l - 1].append(&end_line);
|
||||
(1..lines.len()).for_each(|k| {
|
||||
let tmp = lines[k].clone();
|
||||
self.rows.insert(at.y + k, tmp);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// assumes from < to
|
||||
pub fn remove_text(&mut self, from: &Position, to: &Position) {
|
||||
let fromx = from.x;
|
||||
let fromy = from.y;
|
||||
|
||||
let tox = to.x;
|
||||
let toy = to.y;
|
||||
|
||||
let curline = self.rows.get_mut(fromy).unwrap();
|
||||
|
||||
if fromy == toy {
|
||||
let mut rest = curline.split(fromx);
|
||||
|
||||
curline.append(&rest.split(tox - fromx + 1));
|
||||
} else {
|
||||
curline.split(fromx);
|
||||
|
||||
let lastline = self.rows.get_mut(toy).unwrap().split(tox + 1);
|
||||
self.rows[toy] = lastline;
|
||||
for k in fromy + 1..toy {
|
||||
self.rows.remove(fromy + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// self.rows.remove(index);
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, at: &Position, c: char) {
|
||||
// self.dirty = true;
|
||||
|
||||
|
|
164
src/editor.rs
164
src/editor.rs
|
@ -4,12 +4,12 @@ use crate::Row;
|
|||
use crate::SharedInfo;
|
||||
use crate::Statusbar;
|
||||
|
||||
|
||||
use std::env;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use termion::event::Key;
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
//use termion::event::Key;
|
||||
use tokio::select;
|
||||
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||
use tokio::sync::RwLock;
|
||||
|
@ -27,18 +27,19 @@ pub struct Editor {
|
|||
// pub cursor_position: Arc<RwLock<Position>>,
|
||||
pub shared: Arc<RwLock<SharedInfo>>,
|
||||
|
||||
inputreceiver: UnboundedReceiver<Key>,
|
||||
inputreceiver: UnboundedReceiver<KeyEvent>,
|
||||
eventsender: UnboundedSender<Events>,
|
||||
|
||||
// offset: Position,
|
||||
rememberx: usize,
|
||||
quitting: bool,
|
||||
// colorscheme: Colorscheme,
|
||||
// config: Config,
|
||||
selectionstart: Option<Position>,
|
||||
selectionend: Option<Position>, // colorscheme: Colorscheme,
|
||||
// config: Config
|
||||
}
|
||||
|
||||
impl Editor {
|
||||
pub fn default(irt: UnboundedReceiver<Key>, st: UnboundedSender<Events>) -> Self {
|
||||
pub fn default(irt: UnboundedReceiver<KeyEvent>, st: UnboundedSender<Events>) -> Self {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let document = if args.len() > 1 {
|
||||
let filename = &args[1];
|
||||
|
@ -65,6 +66,9 @@ impl Editor {
|
|||
// offset: Position::default(),
|
||||
rememberx: 0,
|
||||
quitting: false,
|
||||
|
||||
selectionstart: None,
|
||||
selectionend: None
|
||||
// colorscheme: Colorscheme::default(),
|
||||
// config: Config::default(),
|
||||
}
|
||||
|
@ -110,7 +114,7 @@ impl Editor {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn process_keypress(&mut self, k: Key) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
async fn process_keypress(&mut self, k: KeyEvent) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let sharedarc = self.shared.clone();
|
||||
let mut sharedlock = sharedarc.write().await;
|
||||
let shared = &mut *sharedlock;
|
||||
|
@ -120,7 +124,10 @@ impl Editor {
|
|||
let stbar = &mut shared.stbar;
|
||||
|
||||
match k {
|
||||
Key::Ctrl('q') => {
|
||||
KeyEvent {
|
||||
code: KeyCode::Char('q'),
|
||||
modifiers: KeyModifiers::CONTROL,
|
||||
} => {
|
||||
if doc.dirty && !self.quitting {
|
||||
stbar.change_status(
|
||||
&"Unsaved changes. Are you sure you want to quit? Press ctrl+q again.",
|
||||
|
@ -134,20 +141,22 @@ impl Editor {
|
|||
// At the end of this fucntion.
|
||||
}
|
||||
|
||||
Key::Ctrl('s') => {
|
||||
KeyEvent {
|
||||
code: KeyCode::Char('s'),
|
||||
modifiers: KeyModifiers::CONTROL,
|
||||
} => {
|
||||
if doc.dirty {
|
||||
match doc.save() {
|
||||
Ok(true) => {
|
||||
stbar.change_status("Document saved successfully.")?;
|
||||
}
|
||||
Ok(false) => {
|
||||
|
||||
drop(sharedlock); // DROP THE LOCK BEFORE PROMPTING
|
||||
|
||||
let filename = self
|
||||
.prompt(&String::from("Input filename"), &String::from(""))
|
||||
.await?;
|
||||
|
||||
|
||||
let sharedarc = self.shared.clone();
|
||||
let shared = &mut *(*sharedarc).write().await;
|
||||
let mut doc = &mut shared.doc;
|
||||
|
@ -169,8 +178,10 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
|
||||
Key::Ctrl('o') => {
|
||||
|
||||
KeyEvent {
|
||||
code: KeyCode::Char('o'),
|
||||
modifiers: KeyModifiers::CONTROL,
|
||||
} => {
|
||||
drop(sharedlock); // DROP THE LOCK BEFORE PROMPTING
|
||||
|
||||
let filename = self
|
||||
|
@ -196,26 +207,102 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
|
||||
Key::Char(c) => {
|
||||
// Key::Ctrl('t') => {
|
||||
// doc.insert_text(cpos, String::from("WHEN THE \nMOON HITS YOU"));
|
||||
// }
|
||||
// KeyEvent {
|
||||
// code: KeyCode::Char('t'),
|
||||
// modifiers: KeyModifiers::CONTROL,
|
||||
// } => {
|
||||
// doc.remove_text(cpos, &Position { x: 2, y: 2 });
|
||||
// }
|
||||
//Key:: => {}
|
||||
KeyEvent {
|
||||
code: KeyCode::Char(c),
|
||||
..
|
||||
} => {
|
||||
doc.dirty = true;
|
||||
doc.insert(&cpos, c);
|
||||
self.move_cursor(Key::Right, doc, cpos).await?;
|
||||
doc.insert(cpos, c);
|
||||
self.move_cursor(
|
||||
KeyEvent {
|
||||
code: KeyCode::Right,
|
||||
modifiers: KeyModifiers::NONE,
|
||||
},
|
||||
doc,
|
||||
cpos,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Key::Delete => {
|
||||
KeyEvent {
|
||||
code: KeyCode::Enter,
|
||||
..
|
||||
} => {
|
||||
doc.dirty = true;
|
||||
doc.delete(&cpos)
|
||||
doc.insert(cpos, '\n');
|
||||
self.move_cursor(
|
||||
KeyEvent {
|
||||
code: KeyCode::Right,
|
||||
modifiers: KeyModifiers::NONE,
|
||||
},
|
||||
doc,
|
||||
cpos,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Key::Backspace => {
|
||||
KeyEvent {
|
||||
code: KeyCode::Delete,
|
||||
..
|
||||
} => {
|
||||
doc.dirty = true;
|
||||
doc.delete(cpos)
|
||||
}
|
||||
KeyEvent {
|
||||
code: KeyCode::Backspace,
|
||||
..
|
||||
} => {
|
||||
if cpos.x > 0 || cpos.y > 0 {
|
||||
doc.dirty = true;
|
||||
self.move_cursor(Key::Left, doc, cpos).await?;
|
||||
doc.delete(&cpos);
|
||||
self.move_cursor(
|
||||
KeyEvent {
|
||||
code: KeyCode::Left,
|
||||
modifiers: KeyModifiers::NONE,
|
||||
},
|
||||
doc,
|
||||
cpos,
|
||||
)
|
||||
.await?;
|
||||
doc.delete(cpos);
|
||||
}
|
||||
}
|
||||
Key::Up | Key::Down | Key::Left | Key::Right => {
|
||||
KeyEvent {
|
||||
code: KeyCode::Up, ..
|
||||
}
|
||||
| KeyEvent {
|
||||
code: KeyCode::Down,
|
||||
..
|
||||
}
|
||||
| KeyEvent {
|
||||
code: KeyCode::Left,
|
||||
..
|
||||
}
|
||||
| KeyEvent {
|
||||
code: KeyCode::Right,
|
||||
..
|
||||
} => {
|
||||
self.move_cursor(k, doc, cpos).await?;
|
||||
}
|
||||
_ => (),
|
||||
// Key::Home => todo!(),
|
||||
// Key::End => todo!(),
|
||||
// Key::PageUp => todo!(),
|
||||
// Key::PageDown => todo!(),
|
||||
// Key::BackTab => todo!(),
|
||||
// Key::Insert => todo!(),
|
||||
// Key::F(_) => todo!(),
|
||||
// Key::Alt(_) => todo!(),
|
||||
// Key::Null => todo!(),
|
||||
// Key::Esc => todo!(),
|
||||
// Key::__IsNotComplete => todo!(),
|
||||
_ => {}
|
||||
}
|
||||
self.quitting = false;
|
||||
Ok(())
|
||||
|
@ -225,7 +312,12 @@ impl Editor {
|
|||
// doc.filecheck();
|
||||
// }
|
||||
|
||||
async fn move_cursor(&mut self, key: Key, doc: &Document, cpos: &mut Position) -> Result<(), Box<dyn Error + Sync + Send>> {
|
||||
async fn move_cursor(
|
||||
&mut self,
|
||||
key: KeyEvent,
|
||||
doc: &Document,
|
||||
cpos: &mut Position,
|
||||
) -> Result<(), Box<dyn Error + Sync + Send>> {
|
||||
// let doc = (*docarc).read().await;
|
||||
// let mut cpos = (*curarc).write().await;
|
||||
|
||||
|
@ -234,14 +326,16 @@ impl Editor {
|
|||
let w = doc.row(y).map_or(0, Row::len);
|
||||
let h = doc.len();
|
||||
|
||||
match key {
|
||||
Key::Up => y = y.saturating_sub(1),
|
||||
Key::Down => {
|
||||
let k = key.code;
|
||||
|
||||
match k {
|
||||
KeyCode::Up => y = y.saturating_sub(1),
|
||||
KeyCode::Down => {
|
||||
if y < h {
|
||||
y = y.saturating_add(1)
|
||||
}
|
||||
}
|
||||
Key::Left => {
|
||||
KeyCode::Left => {
|
||||
if x > 0 {
|
||||
x -= 1;
|
||||
} else if y > 0 {
|
||||
|
@ -250,7 +344,7 @@ impl Editor {
|
|||
}
|
||||
self.rememberx = x;
|
||||
}
|
||||
Key::Right => {
|
||||
KeyCode::Right => {
|
||||
if x < w {
|
||||
x += 1
|
||||
} else if y < h {
|
||||
|
@ -307,20 +401,20 @@ impl Editor {
|
|||
|
||||
match k.unwrap() {
|
||||
|
||||
Key::Left => {
|
||||
KeyEvent{ code: KeyCode::Left, modifiers : KeyModifiers::NONE} => {
|
||||
if pos > 0 {
|
||||
pos = pos - 1
|
||||
}
|
||||
}
|
||||
|
||||
Key::Right => {
|
||||
KeyEvent{ code: KeyCode::Right, modifiers : KeyModifiers::NONE} => {
|
||||
if pos < r.len() {
|
||||
pos = pos + 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Key::Char('\n')=> {
|
||||
KeyEvent{ code: KeyCode::Enter, modifiers : KeyModifiers::NONE} => {
|
||||
stbar.prompting = false;
|
||||
if r.is_empty() {
|
||||
return Ok(None)
|
||||
|
@ -332,19 +426,19 @@ impl Editor {
|
|||
}
|
||||
|
||||
|
||||
Key::Esc => {
|
||||
KeyEvent{ code: KeyCode::Esc, modifiers : KeyModifiers::NONE} => {
|
||||
stbar.prompting = false;
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
Key::Backspace => {
|
||||
KeyEvent{ code: KeyCode::Backspace, modifiers : KeyModifiers::NONE} => {
|
||||
if pos > 0 {
|
||||
r.delete(pos-1);
|
||||
pos = pos - 1
|
||||
}
|
||||
}
|
||||
|
||||
Key::Char(c) => {
|
||||
KeyEvent{ code: KeyCode::Char(c), modifiers : KeyModifiers::NONE} => {
|
||||
r.insert(pos, c);
|
||||
pos = pos + 1
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::cmp;
|
|||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use termion::event::Key;
|
||||
use crossterm::event::KeyEvent;
|
||||
|
||||
use tokio::select;
|
||||
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
|
||||
|
@ -31,7 +31,7 @@ pub struct Renderer {
|
|||
impl Renderer {
|
||||
pub fn default(
|
||||
st: UnboundedSender<Events>,
|
||||
ist: UnboundedSender<Key>,
|
||||
ist: UnboundedSender<KeyEvent>,
|
||||
rt: UnboundedReceiver<Events>,
|
||||
shared: Arc<RwLock<SharedInfo>>,
|
||||
) -> Self {
|
||||
|
@ -57,13 +57,14 @@ impl Renderer {
|
|||
}
|
||||
|
||||
pub async fn run(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
self.terminal.enable_alt_screen();
|
||||
|
||||
self.refresh_screen().await?;
|
||||
|
||||
loop {
|
||||
select! {
|
||||
event = self.receiver.recv() => {match event.unwrap() {
|
||||
Events::Quit => {
|
||||
self.terminal.reset_screen();
|
||||
break;
|
||||
},
|
||||
Events::Refresh => {self.refresh_screen().await?;}
|
||||
|
@ -73,6 +74,8 @@ impl Renderer {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
self.terminal.disable_alt_screen();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -148,16 +151,16 @@ impl Renderer {
|
|||
println!("{}{}\r", space, r)
|
||||
}
|
||||
|
||||
async fn draw_rows(&self) {
|
||||
async fn draw_rows(&mut self) {
|
||||
let sharedarc = self.shared.clone();
|
||||
|
||||
let shared = (*sharedarc).read().await;
|
||||
|
||||
let doc = &shared.doc;
|
||||
|
||||
Terminal::cursor_reset();
|
||||
Terminal::set_text_color(self.colorscheme.text);
|
||||
Terminal::set_bg_color(self.colorscheme.background);
|
||||
self.terminal.cursor_reset();
|
||||
self.terminal.set_text_color(self.colorscheme.text);
|
||||
self.terminal.set_bg_color(self.colorscheme.background);
|
||||
|
||||
let h = self.terminal.size().height as usize;
|
||||
// let w = self.terminal.size().width as usize;
|
||||
|
@ -167,12 +170,12 @@ impl Renderer {
|
|||
let trueh = h.saturating_sub(vertical_pad);
|
||||
|
||||
for _ in 0..vertical_pad {
|
||||
Terminal::clear_current_line();
|
||||
self.terminal.clear_current_line();
|
||||
println!("\r")
|
||||
}
|
||||
|
||||
for terminal_row in 0..trueh - 2 {
|
||||
Terminal::clear_current_line();
|
||||
self.terminal.clear_current_line();
|
||||
if let Some(row) = doc.row(
|
||||
terminal_row as usize + self.offset.y.saturating_sub(self.config.vertical_padding),
|
||||
) {
|
||||
|
@ -181,11 +184,10 @@ impl Renderer {
|
|||
println!("\r");
|
||||
}
|
||||
}
|
||||
Terminal::reset_text_color();
|
||||
Terminal::reset_bg_color();
|
||||
// Terminal::reset_color();
|
||||
}
|
||||
|
||||
async fn draw_info(&self) {
|
||||
async fn draw_info(&mut self) {
|
||||
let sharedarc = self.shared.clone();
|
||||
|
||||
let shared = (*sharedarc).read().await;
|
||||
|
@ -194,8 +196,9 @@ impl Renderer {
|
|||
let cpos = &shared.cpos;
|
||||
let stbar = &shared.stbar;
|
||||
|
||||
Terminal::set_bg_color(self.colorscheme.status_background);
|
||||
Terminal::set_text_color(self.colorscheme.status_text);
|
||||
self.terminal
|
||||
.set_bg_color(self.colorscheme.status_background);
|
||||
self.terminal.set_text_color(self.colorscheme.status_text);
|
||||
|
||||
let width = self.terminal.size().width as usize;
|
||||
|
||||
|
@ -203,13 +206,12 @@ impl Renderer {
|
|||
|
||||
let status2 = stbar.status2(&doc, &cpos, width);
|
||||
|
||||
Terminal::clear_current_line();
|
||||
self.terminal.clear_current_line();
|
||||
println!("{}\r", status);
|
||||
Terminal::clear_current_line();
|
||||
self.terminal.clear_current_line();
|
||||
print!("{}\r", status2);
|
||||
|
||||
Terminal::reset_text_color();
|
||||
Terminal::reset_bg_color();
|
||||
Terminal::reset_color();
|
||||
}
|
||||
|
||||
async fn scroll(&mut self) {
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::cmp;
|
|||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Row {
|
||||
string: String,
|
||||
len: usize,
|
||||
|
|
198
src/terminal.rs
198
src/terminal.rs
|
@ -6,15 +6,31 @@ use std::error::Error;
|
|||
use std::io::{stdin, stdout, Stdout, Write};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use termion::color;
|
||||
use termion::event::Key;
|
||||
use termion::input::TermRead;
|
||||
use termion::raw::{IntoRawMode, RawTerminal};
|
||||
use termion::screen::{AlternateScreen, ToMainScreen};
|
||||
use crossterm::cursor::MoveTo;
|
||||
use crossterm::cursor::{Hide, Show};
|
||||
use crossterm::{
|
||||
cursor, event,
|
||||
event::KeyEvent,
|
||||
execute, queue,
|
||||
style::{Color, Print, ResetColor, SetBackgroundColor, SetForegroundColor},
|
||||
terminal::{
|
||||
enable_raw_mode, size, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen,
|
||||
},
|
||||
ExecutableCommand, QueueableCommand,
|
||||
};
|
||||
|
||||
use crossterm::event::{poll, read, Event};
|
||||
|
||||
//use termion::color;
|
||||
//use termion::event::Key;
|
||||
//use termion::input::TermRead;
|
||||
//use termion::raw::{IntoRawMode, RawTerminal};
|
||||
//use termion::screen::{AlternateScreen, ToMainScreen};
|
||||
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
use tokio::sync::mpsc::{UnboundedSender};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Size {
|
||||
|
@ -25,23 +41,27 @@ pub struct Size {
|
|||
|
||||
pub struct Terminal {
|
||||
size: Arc<RwLock<Size>>,
|
||||
screen: AlternateScreen<RawTerminal<Stdout>>,
|
||||
|
||||
//screen: AlternateScreen<RawTerminal<Stdout>>,
|
||||
pub sender: UnboundedSender<Events>,
|
||||
stdout: Stdout,
|
||||
// pub receiver: UnboundedReceiver<Events>,
|
||||
|
||||
inputsender: UnboundedSender<Key>,
|
||||
inputsender: UnboundedSender<KeyEvent>,
|
||||
// pub inputreceiver: UnboundedReceiver<Key>,
|
||||
|
||||
sigthread: Option<tokio::task::JoinHandle<()>>,
|
||||
// sigthread: Option<tokio::task::JoinHandle<()>>,
|
||||
keythread: Option<std::thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Terminal {
|
||||
pub fn default(st: UnboundedSender<Events>, ist: UnboundedSender<Key>) -> Result<Self, Box<dyn Error + Send + Sync>> {
|
||||
let size = termion::terminal_size()?;
|
||||
let out = stdout().into_raw_mode()?;
|
||||
let screen = AlternateScreen::from(out);
|
||||
pub fn default(
|
||||
st: UnboundedSender<Events>,
|
||||
ist: UnboundedSender<KeyEvent>,
|
||||
) -> Result<Self, Box<dyn Error + Send + Sync>> {
|
||||
let size = size()?;
|
||||
// let out = stdout().into_raw_mode()?;
|
||||
// let screen = AlternateScreen::from(out);
|
||||
enable_raw_mode()?;
|
||||
|
||||
let mut stdout = stdout();
|
||||
|
||||
// let (st, rt) = unbounded_channel();
|
||||
// let (ist, irt) = unbounded_channel();
|
||||
|
@ -51,64 +71,92 @@ impl Terminal {
|
|||
width: size.0,
|
||||
height: size.1,
|
||||
})),
|
||||
screen,
|
||||
stdout,
|
||||
// screen,
|
||||
sender: st,
|
||||
// receiver: rt,
|
||||
inputsender: ist,
|
||||
// inputreceiver: irt,
|
||||
sigthread: None,
|
||||
// sigthread: None,
|
||||
keythread: None,
|
||||
};
|
||||
|
||||
res.start_update_thread()?;
|
||||
res.start_reading_keys()?;
|
||||
// res.start_update_thread()?;
|
||||
res.start_reading()?;
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn reset_screen(&self) {
|
||||
println!("{}", ToMainScreen);
|
||||
}
|
||||
//pub fn reset_screen(&self) {
|
||||
// println!("{}", ToMainScreen);
|
||||
//}
|
||||
|
||||
fn start_update_thread(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let mut signals = signal(SignalKind::window_change())?; // TODO: Support for other signals
|
||||
// fn start_update_thread(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
// let mut signals = signal(SignalKind::window_change())?; // TODO: Support for other signals
|
||||
|
||||
let arcsize = self.size.clone();
|
||||
// let arcsize = self.size.clone();
|
||||
|
||||
let sender = self.sender.clone();
|
||||
// let sender = self.sender.clone();
|
||||
|
||||
let resizethread = tokio::spawn(async move {
|
||||
loop {
|
||||
// let resizethread = tokio::spawn(async move {
|
||||
// loop {
|
||||
// match signals.recv().await {
|
||||
// Some(_) => {
|
||||
// let size = size().unwrap();
|
||||
// let mut sharedsize = arcsize.write().unwrap();
|
||||
// *sharedsize = Size {
|
||||
// width: size.0,
|
||||
// height: size.1,
|
||||
// };
|
||||
|
||||
match signals.recv().await {
|
||||
Some(_) => {
|
||||
let size = termion::terminal_size().unwrap_or_default();
|
||||
let mut sharedsize = arcsize.write().unwrap();
|
||||
*sharedsize = Size {
|
||||
width: size.0,
|
||||
height: size.1,
|
||||
};
|
||||
// sender.send(Events::Refresh);
|
||||
// }
|
||||
// None => {}
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// self.sigthread = Some(resizethread);
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
sender.send(Events::Refresh);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
});
|
||||
self.sigthread = Some(resizethread);
|
||||
pub fn enable_alt_screen(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
execute!(self.stdout, EnterAlternateScreen);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_reading_keys(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
let mut reader = stdin().keys();
|
||||
pub fn disable_alt_screen(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
execute!(self.stdout, LeaveAlternateScreen);
|
||||
Ok(())
|
||||
}
|
||||
fn start_reading(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
//let mut reader = stdin().keys();
|
||||
|
||||
let sender = self.inputsender.clone();
|
||||
let isender = self.inputsender.clone();
|
||||
let sender = self.sender.clone();
|
||||
|
||||
let keythread = thread::spawn(move || loop {
|
||||
if let Some(key) = reader.next() {
|
||||
sender.send(key.unwrap());
|
||||
loop {
|
||||
if poll(Duration::from_millis(500)).unwrap() {
|
||||
// It's guaranteed that the `read()` won't block when the `poll()`
|
||||
// function returns `true`
|
||||
match read().unwrap() {
|
||||
Event::Key(event) => {
|
||||
isender.send(event);
|
||||
}
|
||||
Event::Mouse(event) => {} //println!("{:?}", event),
|
||||
Event::Resize(width, height) => {
|
||||
sender.send(Events::Refresh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
// Ok(());
|
||||
|
||||
// if let Some(key) = reader.next() {
|
||||
// sender.send(key.unwrap());
|
||||
// }
|
||||
|
||||
self.keythread = Some(keythread);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -118,54 +166,58 @@ impl Terminal {
|
|||
*w
|
||||
}
|
||||
|
||||
pub fn clear_screen() {
|
||||
print!("{}", termion::clear::All)
|
||||
pub fn clear_screen(&mut self) {
|
||||
execute!(self.stdout, Clear(ClearType::All));
|
||||
}
|
||||
|
||||
pub fn cursor_reset() {
|
||||
print!("{}", termion::cursor::Goto(1, 1))
|
||||
pub fn clear_current_line(&mut self) {
|
||||
execute!(self.stdout, Clear(ClearType::CurrentLine));
|
||||
}
|
||||
|
||||
pub fn cursor_position(&self, p: &Position) {
|
||||
pub fn cursor_reset(&mut self) {
|
||||
execute!(self.stdout, MoveTo(1, 1));
|
||||
}
|
||||
|
||||
pub fn cursor_position(&mut self, p: &Position) {
|
||||
let Position { x, y } = p;
|
||||
let s = self.size();
|
||||
let x = cmp::min(x.saturating_add(1) as u16, s.width);
|
||||
let y = cmp::min(y.saturating_add(1) as u16, s.height);
|
||||
print!("{}", termion::cursor::Goto(x, y))
|
||||
let x = cmp::min(*x as u16, s.width);
|
||||
let y = cmp::min(*y as u16, s.height);
|
||||
execute!((self.stdout), MoveTo(x, y));
|
||||
}
|
||||
|
||||
pub fn flush(&mut self) -> Result<(), Box<dyn Error + Send + Sync>> {
|
||||
self.screen.flush()?;
|
||||
self.stdout.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cursor_hide() {
|
||||
print!("{}", termion::cursor::Hide);
|
||||
execute!(stdout(), Hide);
|
||||
}
|
||||
|
||||
pub fn cursor_show() {
|
||||
print!("{}", termion::cursor::Show);
|
||||
execute!(stdout(), Show);
|
||||
}
|
||||
|
||||
pub fn clear_current_line() {
|
||||
print!("{}", termion::clear::CurrentLine);
|
||||
pub fn set_bg_color(&mut self, color: Color) {
|
||||
execute!(self.stdout, SetBackgroundColor(color));
|
||||
}
|
||||
|
||||
pub fn set_bg_color(color: color::Rgb) {
|
||||
print!("{}", color::Bg(color))
|
||||
// pub fn reset_bg_color() {
|
||||
// print!("{}", color::Bg(color::Reset))
|
||||
// }
|
||||
|
||||
pub fn set_text_color(&mut self, color: Color) {
|
||||
execute!(self.stdout, SetForegroundColor(color));
|
||||
}
|
||||
|
||||
pub fn reset_bg_color() {
|
||||
print!("{}", color::Bg(color::Reset))
|
||||
pub fn reset_color() {
|
||||
execute!(stdout(), ResetColor);
|
||||
}
|
||||
|
||||
pub fn set_text_color(color: color::Rgb) {
|
||||
print!("{}", color::Fg(color))
|
||||
}
|
||||
|
||||
pub fn reset_text_color() {
|
||||
print!("{}", color::Fg(color::Reset))
|
||||
}
|
||||
// pub fn reset_text_color() {
|
||||
// print!("{}", color::Fg(color::Reset))
|
||||
// }
|
||||
|
||||
pub fn quit(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.sender.send(Events::Quit)?;
|
||||
|
|
Loading…
Reference in New Issue