diff --git a/Cargo.lock b/Cargo.lock index fcfebb84..dced0abc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,13 +71,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.71" +version = "0.1.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" +checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -538,7 +538,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1098,9 +1098,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] @@ -1219,7 +1219,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1511,22 +1511,22 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.173" +version = "1.0.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91f70896d6720bc714a4a57d22fc91f1db634680e65c8efe13323f1fa38d53f" +checksum = "3b88756493a5bd5e5395d53baa70b194b05764ab85b59e43e4b8f4e1192fa9b1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.173" +version = "1.0.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6250dde8342e0232232be9ca3db7aa40aceb5a3e5dd9bddbc00d99a007cde49" +checksum = "6e5c3a298c7f978e53536f95a63bdc4c4a64550582f31a0359a9afda6aede62e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1653,9 +1653,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.26" +version = "2.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" +checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" dependencies = [ "proc-macro2", "quote", @@ -1693,22 +1693,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1813,7 +1813,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -1967,7 +1967,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", ] [[package]] @@ -2127,7 +2127,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", "wasm-bindgen-shared", ] @@ -2149,7 +2149,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.27", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/src/core/input/input.rs b/src/core/input/input.rs index 435a3cd8..b6016136 100644 --- a/src/core/input/input.rs +++ b/src/core/input/input.rs @@ -1,23 +1,24 @@ use anyhow::{anyhow, Result}; use ratatui::layout::Rect; use tokio::sync::oneshot::Sender; -use unicode_width::UnicodeWidthStr; +use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; +use super::InputSnap; use crate::{core::{external, Position}, misc::CharKind}; #[derive(Default)] pub struct Input { - title: String, - value: String, - position: (u16, u16), + title: String, + pub(crate) value: String, + position: (u16, u16), - op: InputOp, - start: Option, + pub(crate) op: InputOp, + pub(crate) start: Option, - mode: InputMode, - offset: usize, - cursor: usize, - callback: Option>>, + pub(crate) mode: InputMode, + pub(crate) offset: usize, + pub(crate) cursor: usize, + callback: Option>>, pub visible: bool, } @@ -60,7 +61,7 @@ impl Input { }; self.cursor = self.count(); - self.offset = self.value.width().saturating_sub(50); + self.offset = self.cursor.saturating_sub(50 - 2 /* Border width */); self.callback = Some(tx); self.visible = true; } @@ -129,8 +130,8 @@ impl Input { if self.cursor < self.offset { self.offset = self.cursor; - } else if self.cursor > self.offset + 50 { - self.offset = self.cursor.saturating_sub(50); + } else if self.cursor >= self.offset + 50 - 2 { + self.offset = self.cursor.saturating_sub(50 - 2 - self.mode.delta()); } b } @@ -271,24 +272,20 @@ impl Input { } fn handle_op(&mut self, cursor: usize, include: bool) -> bool { - let old = self.cursor; + let snap = self.snap(); let range = if self.op == InputOp::None { None } else { self.range(cursor, include) }; - let b = match self.op { + match self.op { InputOp::None => { self.cursor = cursor; - false } InputOp::Delete(insert) => { let range = range.unwrap(); - let old_mode = self.mode; - let (start, end) = (self.idx(range.0), self.idx(range.1)); + self.value.drain(start.unwrap()..end.unwrap()); self.mode = if insert { InputMode::Insert } else { InputMode::Normal }; self.cursor = range.0; - - start != end || self.mode != old_mode } InputOp::Yank => { let range = range.unwrap(); @@ -298,13 +295,12 @@ impl Input { futures::executor::block_on(async { external::clipboard_set(yanked).await.ok(); }); - start != end } }; self.op = InputOp::None; self.cursor = self.count().saturating_sub(self.mode.delta()).min(self.cursor); - b || self.cursor != old + snap != self.snap() } } @@ -313,28 +309,24 @@ impl Input { pub fn title(&self) -> String { self.title.clone() } #[inline] - pub fn value(&self) -> String { self.value.clone() } + pub fn value(&self) -> &str { + let win = self.window(); + &self.value[self.idx(win.0).unwrap()..self.idx(win.1).unwrap()] + } + + #[inline] + pub fn mode(&self) -> InputMode { self.mode } #[inline] pub fn area(&self) -> Rect { Rect { x: self.position.0, y: self.position.1 + 2, width: 50, height: 3 } } - #[inline] - pub fn mode(&self) -> InputMode { self.mode } - #[inline] pub fn cursor(&self) -> (u16, u16) { - let width = self - .value - .chars() - .enumerate() - .take_while(|(i, _)| *i < self.cursor) - .map(|(_, c)| c) - .collect::() - .width() as u16; - let area = self.area(); + let width = self.value[self.offset..self.idx(self.cursor).unwrap()].width() as u16; + (area.x + width + 1, area.y + 1) } @@ -346,10 +338,14 @@ impl Input { let start = self.start.unwrap(); let (start, end) = if start < self.cursor { (start, self.cursor) } else { (self.cursor + 1, start + 1) }; + + let win = self.window(); + let (start, end) = (start.max(win.0), end.min(win.1)); let (start, end) = (self.idx(start).unwrap(), self.idx(end).unwrap()); + let offset = self.idx(self.offset).unwrap(); Some(Rect { - x: self.position.0 + 1 + self.value[..start].width() as u16, + x: self.position.0 + 1 + self.value[offset..start].width() as u16, y: self.position.1 + 3, width: self.value[start..end].width() as u16, height: 1, @@ -377,4 +373,23 @@ impl Input { .map(|s| if s <= cursor { (s, cursor) } else { (cursor, s) }) .map(|(s, e)| (s, e + include as usize)) } + + #[inline] + fn window(&self) -> (usize, usize) { + let mut len = 0; + let v = self + .value + .chars() + .enumerate() + .skip(self.offset) + .map_while(|(i, c)| { + len += c.width().unwrap_or(0); + if len > 50 - 2/*Border width*/ { None } else { Some(i) } + }) + .collect::>(); + (v.first().copied().unwrap_or(0), v.last().map(|l| l + 1).unwrap_or(0)) + } + + #[inline] + fn snap(&self) -> InputSnap { InputSnap::from(self) } } diff --git a/src/core/input/mod.rs b/src/core/input/mod.rs index 3c90976f..b7251de8 100644 --- a/src/core/input/mod.rs +++ b/src/core/input/mod.rs @@ -1,3 +1,5 @@ mod input; +mod snap; pub use input::*; +pub use snap::*; diff --git a/src/core/input/snap.rs b/src/core/input/snap.rs new file mode 100644 index 00000000..d9ff2418 --- /dev/null +++ b/src/core/input/snap.rs @@ -0,0 +1,28 @@ +use super::{Input, InputMode, InputOp}; + +#[derive(Default, PartialEq, Eq)] +pub struct InputSnap { + value: String, + + op: InputOp, + start: Option, + + mode: InputMode, + offset: usize, + cursor: usize, +} + +impl From<&Input> for InputSnap { + fn from(input: &Input) -> Self { + Self { + value: input.value.clone(), + + op: input.op, + start: input.start, + + mode: input.mode, + offset: input.offset, + cursor: input.cursor, + } + } +}