diff --git a/Cargo.lock b/Cargo.lock index d4642a2..10b3bad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" [[package]] name = "assert_cmd" @@ -56,9 +56,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bstr" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "lazy_static", "memchr", @@ -68,9 +68,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" [[package]] name = "cassowary" @@ -342,9 +342,9 @@ dependencies = [ [[package]] name = "half" -version = "1.7.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "hashbrown" @@ -380,9 +380,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", ] @@ -404,9 +404,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "js-sys" -version = "0.3.53" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4bf49d50e2961077d9c99f4b7997d770a1114f087c3c2e0069b36c13fc2979d" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ "wasm-bindgen", ] @@ -419,9 +419,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.105" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" [[package]] name = "linked-hash-map" @@ -449,18 +449,18 @@ dependencies = [ [[package]] name = "lua-src" -version = "543.0.0" +version = "543.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029180f994b9b36f47d905f92569b516acf7d073778e2e781c15ee375b1ca27d" +checksum = "b72914332bf1ef0e1185b229135d639f11a4a8ccfd32852db8e52419c04c0247" dependencies = [ "cc", ] [[package]] name = "luajit-src" -version = "210.3.0+restyeced77f" +version = "210.3.1+restycd2285f" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084807a533537567019ffc9415c901d5d0a2f1e5f3956f2f4de0534a4bb74118" +checksum = "0107579f29cba96b4450335469432ee6f0f0bc68690626a951bd680212477efc" dependencies = [ "cc", ] @@ -498,9 +498,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" dependencies = [ "libc", "log", @@ -618,9 +618,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" [[package]] name = "plotters" @@ -652,9 +652,9 @@ dependencies = [ [[package]] name = "predicates" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308" +checksum = "5c6ce811d0b2e103743eec01db1c50612221f173084ce2f7941053e94b6bb474" dependencies = [ "difflib", "itertools", @@ -669,28 +669,28 @@ checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451" [[package]] name = "predicates-tree" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7dd0fd014130206c9352efbdc92be592751b2b9274dff685348341082c6ea3d" +checksum = "338c7be2905b732ae3984a2f40032b5e94fd8f52505b186c7d4d68d193445df7" dependencies = [ "predicates-core", - "treeline", + "termtree", ] [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] @@ -828,9 +828,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" dependencies = [ "itoa", "ryu", @@ -881,21 +881,27 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "syn" -version = "1.0.75" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] +[[package]] +name = "termtree" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13a4ec180a2de59b57434704ccfad967f789b12737738798fa08798cd5824c16" + [[package]] name = "textwrap" version = "0.11.0" @@ -926,12 +932,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "treeline" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41" - [[package]] name = "tui" version = "0.16.0" @@ -946,6 +946,16 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "tui-input" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "425271346f51f4a17222eb51b80a3184d7927fcdc1dee0d3e8b7933cbd756ca9" +dependencies = [ + "crossterm 0.22.1", + "serde", +] + [[package]] name = "unicase" version = "2.6.0" @@ -963,9 +973,9 @@ checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -1007,9 +1017,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.76" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce9b1b516211d33767048e5d47fa2a381ed8b76fc48d2ce4aa39877f9f183e0" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1017,9 +1027,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.76" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe8dc78e2326ba5f845f4b5bf548401604fa20b1dd1d365fb73b6c1d6364041" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", @@ -1032,9 +1042,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.76" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44468aa53335841d9d6b6c023eaab07c0cd4bddbcfdee3e2bb1e8d2cb8069fef" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1042,9 +1052,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.76" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0195807922713af1e67dc66132c7328206ed9766af3858164fb583eedc25fbad" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ "proc-macro2", "quote", @@ -1055,15 +1065,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.76" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdb075a845574a1fa5f09fd77e43f7747599301ea3417a9fbffdeedfc1f4a29" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" [[package]] name = "web-sys" -version = "0.3.53" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224b2f6b67919060055ef1a67807367c2066ed520c3862cc013d26cf893a783c" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" dependencies = [ "js-sys", "wasm-bindgen", @@ -1121,6 +1131,7 @@ dependencies = [ "serde", "serde_yaml", "tui", + "tui-input", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bed625b..906dd62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ dirs = "4.0.0" serde = { version = "1.0.130", features = ["derive"] } serde_yaml = "0.8.21" mime_guess = "2.0.3" -anyhow = "1.0.44" +anyhow = "1.0.45" chrono = { version = "0.4.19", features = ["serde"] } lazy_static = "1.4.0" indexmap = { version = "1.7.0", features = ["serde"] } @@ -33,7 +33,8 @@ natord = "1.0.9" humansize = "1.1.1" mlua = { version = "0.6.6", features = ["luajit", "vendored", "serialize", "send"] } ansi-to-tui = "0.4.1" -libc = "0.2.105" +libc = "0.2.106" +tui-input = { version = "0.1.2", features = [ "serde" ] } [dev-dependencies] criterion = "0.3.5" diff --git a/docs/en/src/general-config.md b/docs/en/src/general-config.md index 429c624..581095d 100644 --- a/docs/en/src/general-config.md +++ b/docs/en/src/general-config.md @@ -29,19 +29,6 @@ Type: boolean Set it to `true` if you want to enable a safety feature that will save you from yourself when you type recklessly. -## cursor.format - -Type: nullable string - -This is the shape of the cursor visible when the input buffer contains some -string. - -## cursor.style - -Type: [Style][1] - -Style of the cursor. - ## initial_layout Type: string diff --git a/docs/en/src/style.md b/docs/en/src/style.md index 23ce1f8..fd3b240 100644 --- a/docs/en/src/style.md +++ b/docs/en/src/style.md @@ -72,10 +72,10 @@ Modifier can be one of the following: ## Example ```lua -xplr.config.general.cursor.style.fg = "Red" -xplr.config.general.cursor.style.bg = { Rgb = { 100, 150, 200 } } -xplr.config.general.cursor.style.add_modifiers = { "Bold", "Italic" } -xplr.config.general.cursor.style.sub_modifiers = { "Hidden" } +xplr.config.general.prompt.style.fg = "Red" +xplr.config.general.prompt.style.bg = { Rgb = { 100, 150, 200 } } +xplr.config.general.prompt.style.add_modifiers = { "Bold", "Italic" } +xplr.config.general.prompt.style.sub_modifiers = { "Hidden" } ``` [1]: #fg diff --git a/src/app.rs b/src/app.rs index 292e1ca..5cabc5e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -16,6 +16,7 @@ use std::collections::VecDeque; use std::env; use std::fs; use std::path::{Path, PathBuf}; +use tui_input::{Input, InputRequest}; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const TEMPLATE_TABLE_ROW: &str = "TEMPLATE_TABLE_ROW"; @@ -776,6 +777,9 @@ pub enum ExternalMsg { /// Follow the symlink under focus to its actual location. FollowSymlink, + /// Update the input buffer from given key + UpdateInputBufferFromKey, + /// Append/buffer the given string into the input buffer. /// /// **Example:** `BufferInput: foo` @@ -1247,7 +1251,7 @@ pub struct App { pub msg_out: VecDeque, pub mode: Mode, pub layout: Layout, - pub input_buffer: Option, + pub input: Option, pub pid: u32, pub session_path: String, pub pipe: Pipe, @@ -1372,7 +1376,7 @@ impl App { msg_out: Default::default(), mode, layout, - input_buffer: Default::default(), + input: Default::default(), pid, session_path: session_path.clone(), pipe: Pipe::from_session_path(&session_path)?, @@ -1477,6 +1481,9 @@ impl App { ExternalMsg::LastVisitedPath => self.last_visited_path(), ExternalMsg::NextVisitedPath => self.next_visited_path(), ExternalMsg::FollowSymlink => self.follow_symlink(), + ExternalMsg::UpdateInputBufferFromKey => { + self.update_input_buffer_from_key(key) + } ExternalMsg::BufferInput(input) => self.buffer_input(&input), ExternalMsg::BufferInputFromKey => { self.buffer_input_from_key(key) @@ -1731,9 +1738,9 @@ impl App { fn focus_previous_by_relative_index_from_input(self) -> Result { if let Some(index) = self - .input_buffer + .input .as_ref() - .and_then(|i| i.parse::().ok()) + .and_then(|i| i.value().parse::().ok()) { self.focus_previous_by_relative_index(index) } else { @@ -1769,9 +1776,9 @@ impl App { fn focus_next_by_relative_index_from_input(self) -> Result { if let Some(index) = self - .input_buffer + .input .as_ref() - .and_then(|i| i.parse::().ok()) + .and_then(|i| i.value().parse::().ok()) { self.focus_next_by_relative_index(index) } else { @@ -1865,11 +1872,26 @@ impl App { } } + fn update_input_buffer_from_key( + mut self, + key: Option, + ) -> Result { + if let Some(req) = key.and_then(|k| k.to_input_request()) { + if let Some(buf) = self.input.as_mut() { + buf.handle(req); + } + } + Ok(self) + } + fn buffer_input(mut self, input: &str) -> Result { - if let Some(buf) = self.input_buffer.as_mut() { - buf.push_str(input) + if let Some(buf) = self.input.as_mut() { + buf.handle(InputRequest::GoToEnd); + for c in input.chars() { + buf.handle(InputRequest::InsertChar(c)); + } } else { - self.input_buffer = Some(input.to_owned()); + self.input = Some(Input::default().with_value(input.into())); }; self.logs_hidden = true; Ok(self) @@ -1884,41 +1906,31 @@ impl App { } fn set_input_buffer(mut self, string: String) -> Result { - self.input_buffer = Some(string); + self.input = Some(Input::default().with_value(string)); self.logs_hidden = true; Ok(self) } fn remove_input_buffer_last_character(mut self) -> Result { - if let Some(mut buf) = self.input_buffer { - buf.pop(); - self.input_buffer = Some(buf); + if let Some(buf) = self.input.as_mut() { + buf.handle(InputRequest::GoToEnd); + buf.handle(InputRequest::DeletePrevChar); self.logs_hidden = true; }; Ok(self) } fn remove_input_buffer_last_word(mut self) -> Result { - if let Some(buf) = self.input_buffer { - let buf = buf - .chars() - .into_iter() - .rev() - .skip_while(|c| !c.is_ascii_alphanumeric()) - .skip_while(|c| c.is_ascii_alphanumeric()) - .collect::>() - .into_iter() - .rev() - .collect::(); - - self.input_buffer = Some(buf); + if let Some(buf) = self.input.as_mut() { + buf.handle(InputRequest::GoToEnd); + buf.handle(InputRequest::DeletePrevWord); self.logs_hidden = true; }; Ok(self) } fn reset_input_buffer(mut self) -> Result { - self.input_buffer = None; + self.input = None; Ok(self) } @@ -1935,9 +1947,9 @@ impl App { fn focus_by_index_from_input(self) -> Result { if let Some(index) = self - .input_buffer + .input .as_ref() - .and_then(|i| i.parse::().ok()) + .and_then(|i| i.value().parse::().ok()) { self.focus_by_index(index) } else { @@ -2004,8 +2016,8 @@ impl App { } fn focus_path_from_input(self) -> Result { - if let Some(p) = self.input_buffer.clone() { - self.focus_path(&p, true) + if let Some(p) = self.input.clone() { + self.focus_path(p.value(), true) } else { Ok(self) } @@ -2026,7 +2038,7 @@ impl App { fn pop_mode(self) -> Result { self.pop_mode_keeping_input_buffer().map(|mut a| { - a.input_buffer = None; + a.input = None; a }) } @@ -2040,7 +2052,7 @@ impl App { fn switch_mode(self, mode: &str) -> Result { self.switch_mode_keeping_input_buffer(mode).map(|mut a| { - a.input_buffer = None; + a.input = None; a }) } @@ -2058,7 +2070,7 @@ impl App { fn switch_mode_builtin(self, mode: &str) -> Result { self.switch_mode_builtin_keeping_input_buffer(mode) .map(|mut a| { - a.input_buffer = None; + a.input = None; a }) } @@ -2079,7 +2091,7 @@ impl App { fn switch_mode_custom(self, mode: &str) -> Result { self.switch_mode_custom_keeping_input_buffer(mode) .map(|mut a| { - a.input_buffer = None; + a.input = None; a }) } @@ -2290,10 +2302,13 @@ impl App { mut self, filter: NodeFilter, ) -> Result { - if let Some(input) = self.input_buffer.clone() { + if let Some(input) = self.input.as_ref() { self.explorer_config .filters - .insert(NodeFilterApplicable::new(filter, input)); + .insert(NodeFilterApplicable::new( + filter, + input.value().into(), + )); }; Ok(self) } @@ -2310,8 +2325,8 @@ impl App { mut self, filter: NodeFilter, ) -> Result { - if let Some(input) = self.input_buffer.clone() { - let nfa = NodeFilterApplicable::new(filter, input); + if let Some(input) = self.input.as_ref() { + let nfa = NodeFilterApplicable::new(filter, input.value().into()); self.explorer_config.filters.retain(|f| f != &nfa); }; Ok(self) @@ -2668,7 +2683,7 @@ impl App { selection: self.selection.clone(), mode: self.mode.clone(), layout: self.layout.clone(), - input_buffer: self.input_buffer.clone(), + input_buffer: self.input.as_ref().map(|i| i.value().into()), pid: self.pid, session_path: self.session_path.clone(), explorer_config: self.explorer_config.clone(), diff --git a/src/config.rs b/src/config.rs index 12d5100..3631515 100644 --- a/src/config.rs +++ b/src/config.rs @@ -227,9 +227,6 @@ pub struct GeneralConfig { #[serde(default)] pub enable_recover_mode: bool, - #[serde(default)] - pub cursor: UiElement, - #[serde(default)] pub prompt: UiElement, diff --git a/src/init.lua b/src/init.lua index 1004002..c6d5fb4 100644 --- a/src/init.lua +++ b/src/init.lua @@ -26,13 +26,6 @@ xplr.config.general.prompt.style.sub_modifiers = nil xplr.config.general.prompt.style.bg = nil xplr.config.general.prompt.style.fg = nil ------- Cursor -xplr.config.general.cursor.format = "█" -xplr.config.general.cursor.style.add_modifiers = nil -xplr.config.general.cursor.style.bg = nil -xplr.config.general.cursor.style.fg = nil -xplr.config.general.cursor.style.sub_modifiers = nil - ------ Initial layout xplr.config.general.initial_layout = "default" @@ -1170,26 +1163,10 @@ xplr.config.modes.builtin.create_directory = { extra_help = nil, key_bindings = { on_key = { - backspace = { - help = "remove last character", - messages = { "RemoveInputBufferLastCharacter" }, - }, ["ctrl-c"] = { help = "terminate", messages = { "Terminate" }, }, - ["ctrl-u"] = { - help = "remove line", - messages = { - { - SetInputBuffer = "", - }, - }, - }, - ["ctrl-w"] = { - help = "remove last word", - messages = { "RemoveInputBufferLastWord" }, - }, enter = { help = "create directory", messages = { @@ -1219,7 +1196,7 @@ xplr.config.modes.builtin.create_directory = { on_special_character = nil, default = { help = nil, - messages = { "BufferInputFromKey" }, + messages = { "UpdateInputBufferFromKey" }, }, }, } @@ -1231,26 +1208,10 @@ xplr.config.modes.builtin.create_file = { extra_help = nil, key_bindings = { on_key = { - backspace = { - help = "remove last character", - messages = { "RemoveInputBufferLastCharacter" }, - }, ["ctrl-c"] = { help = "terminate", messages = { "Terminate" }, }, - ["ctrl-u"] = { - help = "remove line", - messages = { - { - SetInputBuffer = "", - }, - }, - }, - ["ctrl-w"] = { - help = "remove last word", - messages = { "RemoveInputBufferLastWord" }, - }, enter = { help = "create file", messages = { @@ -1280,7 +1241,7 @@ xplr.config.modes.builtin.create_file = { on_special_character = nil, default = { help = nil, - messages = { "BufferInputFromKey" }, + messages = { "UpdateInputBufferFromKey" }, }, }, } @@ -1292,26 +1253,10 @@ xplr.config.modes.builtin.number = { extra_help = nil, key_bindings = { on_key = { - backspace = { - help = "remove last character", - messages = { "RemoveInputBufferLastCharacter" }, - }, ["ctrl-c"] = { help = "terminate", messages = { "Terminate" }, }, - ["ctrl-u"] = { - help = "remove line", - messages = { - { - SetInputBuffer = "", - }, - }, - }, - ["ctrl-w"] = { - help = "remove last word", - messages = { "RemoveInputBufferLastWord" }, - }, down = { help = "to down", messages = { "FocusNextByRelativeIndexFromInput", "PopMode" }, @@ -1332,7 +1277,7 @@ xplr.config.modes.builtin.number = { on_alphabet = nil, on_number = { help = "input", - messages = { "BufferInputFromKey" }, + messages = { "UpdateInputBufferFromKey" }, }, on_special_character = nil, default = nil, @@ -1404,26 +1349,10 @@ xplr.config.modes.builtin.rename = { extra_help = nil, key_bindings = { on_key = { - backspace = { - help = "remove last character", - messages = { "RemoveInputBufferLastCharacter" }, - }, ["ctrl-c"] = { help = "terminate", messages = { "Terminate" }, }, - ["ctrl-u"] = { - help = "remove line", - messages = { - { - SetInputBuffer = "", - }, - }, - }, - ["ctrl-w"] = { - help = "remove last word", - messages = { "RemoveInputBufferLastWord" }, - }, enter = { help = "rename", messages = { @@ -1450,7 +1379,7 @@ xplr.config.modes.builtin.rename = { on_special_character = nil, default = { help = nil, - messages = { "BufferInputFromKey" }, + messages = { "UpdateInputBufferFromKey" }, }, }, } @@ -1684,51 +1613,10 @@ xplr.config.modes.builtin.search = { extra_help = nil, key_bindings = { on_key = { - backspace = { - help = "remove last character", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesContain", - }, - "RemoveInputBufferLastCharacter", - { - AddNodeFilterFromInput = "IRelativePathDoesContain", - }, - "ExplorePwdAsync", - }, - }, ["ctrl-c"] = { help = "terminate", messages = { "Terminate" }, }, - ["ctrl-u"] = { - help = "remove line", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesContain", - }, - { - SetInputBuffer = "", - }, - { - AddNodeFilterFromInput = "IRelativePathDoesContain", - }, - "ExplorePwdAsync", - }, - }, - ["ctrl-w"] = { - help = "remove last word", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesContain", - }, - "RemoveInputBufferLastWord", - { - AddNodeFilterFromInput = "IRelativePathDoesContain", - }, - "ExplorePwdAsync", - }, - }, down = { help = "down", messages = { "FocusNext" }, @@ -1743,26 +1631,26 @@ xplr.config.modes.builtin.search = { "ExplorePwdAsync", }, }, - left = { - help = "back", + right = { + help = "enter", messages = { { RemoveNodeFilterFromInput = "IRelativePathDoesContain", }, - "Back", + "Enter", { SetInputBuffer = "", }, "ExplorePwdAsync", }, }, - right = { - help = "enter", + left = { + help = "back", messages = { { RemoveNodeFilterFromInput = "IRelativePathDoesContain", }, - "Enter", + "Back", { SetInputBuffer = "", }, @@ -1787,7 +1675,7 @@ xplr.config.modes.builtin.search = { { RemoveNodeFilterFromInput = "IRelativePathDoesContain", }, - "BufferInputFromKey", + "UpdateInputBufferFromKey", { AddNodeFilterFromInput = "IRelativePathDoesContain", }, @@ -1826,10 +1714,6 @@ xplr.config.modes.builtin.filter = { "ExplorePwdAsync", }, }, - backspace = { - help = "remove last filter", - messages = { "RemoveLastNodeFilter", "ExplorePwdAsync" }, - }, ["ctrl-c"] = { help = "terminate", messages = { "Terminate" }, @@ -1879,51 +1763,10 @@ xplr.config.modes.builtin.relative_path_does_contain = { extra_help = nil, key_bindings = { on_key = { - backspace = { - help = "remove last character", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesContain", - }, - "RemoveInputBufferLastCharacter", - { - AddNodeFilterFromInput = "IRelativePathDoesContain", - }, - "ExplorePwdAsync", - }, - }, ["ctrl-c"] = { help = "terminate", messages = { "Terminate" }, }, - ["ctrl-u"] = { - help = "remove line", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesContain", - }, - { - SetInputBuffer = "", - }, - { - AddNodeFilterFromInput = "IRelativePathDoesContain", - }, - "ExplorePwdAsync", - }, - }, - ["ctrl-w"] = { - help = "remove last word", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesContain", - }, - "RemoveInputBufferLastWord", - { - AddNodeFilterFromInput = "IRelativePathDoesContain", - }, - "ExplorePwdAsync", - }, - }, enter = { help = "apply filter", messages = { "PopMode" }, @@ -1948,7 +1791,7 @@ xplr.config.modes.builtin.relative_path_does_contain = { { RemoveNodeFilterFromInput = "IRelativePathDoesContain", }, - "BufferInputFromKey", + "UpdateInputBufferFromKey", { AddNodeFilterFromInput = "IRelativePathDoesContain", }, @@ -1965,51 +1808,10 @@ xplr.config.modes.builtin.relative_path_does_not_contain = { extra_help = nil, key_bindings = { on_key = { - backspace = { - help = "remove last character", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesNotContain", - }, - "RemoveInputBufferLastCharacter", - { - AddNodeFilterFromInput = "IRelativePathDoesNotContain", - }, - "ExplorePwdAsync", - }, - }, ["ctrl-c"] = { help = "terminate", messages = { "Terminate" }, }, - ["ctrl-u"] = { - help = "remove line", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesNotContain", - }, - { - SetInputBuffer = "", - }, - { - AddNodeFilterFromInput = "IRelativePathDoesNotContain", - }, - "ExplorePwdAsync", - }, - }, - ["ctrl-w"] = { - help = "remove last word", - messages = { - { - RemoveNodeFilterFromInput = "IRelativePathDoesNotContain", - }, - "RemoveInputBufferLastWord", - { - AddNodeFilterFromInput = "IRelativePathDoesNotContain", - }, - "ExplorePwdAsync", - }, - }, enter = { help = "apply filter", messages = { "PopMode" }, @@ -2034,7 +1836,7 @@ xplr.config.modes.builtin.relative_path_does_not_contain = { { RemoveNodeFilterFromInput = "IRelativePathDoesNotContain", }, - "BufferInputFromKey", + "UpdateInputBufferFromKey", { AddNodeFilterFromInput = "IRelativePathDoesNotContain", }, diff --git a/src/input.rs b/src/input.rs index 532de2c..dca00f2 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,6 +1,7 @@ use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; +use tui_input::InputRequest; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] @@ -111,6 +112,23 @@ pub enum Key { CtrlY, CtrlZ, + CtrlBackspace, + CtrlLeft, + CtrlRight, + CtrlUp, + CtrlDown, + CtrlHome, + CtrlEnd, + CtrlPageUp, + CtrlPageDown, + CtrlBackTab, + CtrlDelete, + CtrlInsert, + CtrlEnter, + CtrlSpace, + CtrlTab, + CtrlEsc, + AltA, AltB, AltC, @@ -190,6 +208,35 @@ impl std::fmt::Display for Key { } impl Key { + pub fn to_input_request(self) -> Option { + use InputRequest::*; + use Key::*; + + if self.is_alphabet() || self.is_number() || self.is_special_character() + { + self.to_char().map(InsertChar) + } else { + match self { + Backspace => Some(DeletePrevChar), + Delete => Some(DeleteNextChar), + Tab => Some(InsertChar('\t')), + Space => Some(InsertChar(' ')), + Left => Some(GoToPrevChar), + CtrlLeft => Some(GoToPrevWord), + Right => Some(GoToNextChar), + CtrlRight => Some(GoToNextWord), + CtrlU => Some(DeleteLine), + CtrlW => Some(DeletePrevWord), + CtrlDelete => Some(DeleteNextWord), + CtrlA => Some(GoToStart), + CtrlE => Some(GoToEnd), + Enter => Some(Submit), + Esc => Some(Escape), + _ => None, + } + } + } + pub fn from_event(key: KeyEvent) -> Self { match key.modifiers { KeyModifiers::CONTROL => match key.code { @@ -219,6 +266,23 @@ impl Key { KeyCode::Char('x') => Key::CtrlX, KeyCode::Char('y') => Key::CtrlY, KeyCode::Char('z') => Key::CtrlZ, + KeyCode::Char(' ') => Key::CtrlSpace, + + KeyCode::Backspace => Key::CtrlBackspace, + KeyCode::Left => Key::CtrlLeft, + KeyCode::Right => Key::CtrlRight, + KeyCode::Up => Key::CtrlUp, + KeyCode::Down => Key::CtrlDown, + KeyCode::Home => Key::CtrlHome, + KeyCode::End => Key::CtrlEnd, + KeyCode::PageUp => Key::CtrlPageUp, + KeyCode::PageDown => Key::CtrlPageDown, + KeyCode::BackTab => Key::CtrlBackTab, + KeyCode::Delete => Key::CtrlDelete, + KeyCode::Insert => Key::CtrlInsert, + KeyCode::Enter => Key::CtrlEnter, + KeyCode::Tab => Key::CtrlTab, + KeyCode::Esc => Key::CtrlEsc, KeyCode::Char(c) => c.into(), diff --git a/src/runner.rs b/src/runner.rs index 0de7c97..5eb1006 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -68,7 +68,10 @@ fn call(app: &app::App, cmd: app::Command, silent: bool) -> Result { .env("XPLR_PID", &app.pid.to_string()) .env( "XPLR_INPUT_BUFFER", - app.input_buffer.clone().unwrap_or_default(), + app.input + .as_ref() + .map(|i| i.value().to_string()) + .unwrap_or_default(), ) .env("XPLR_FOCUS_PATH", app.focused_node_str()) .env("XPLR_FOCUS_INDEX", focus_index) diff --git a/src/ui.rs b/src/ui.rs index 59e0f67..61fff77 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -769,6 +769,26 @@ fn draw_input_buffer( .default .to_owned() .extend(&panel_config.input_and_logs); + + let cursor_offset = if config + .borders + .as_ref() + .map(|b| b.contains(&Border::Right)) + .unwrap_or(false) + { + 3 + } else { + 2 + }; + + let input_val = app + .input + .as_ref() + .map(|i| i.value().to_string()) + .unwrap_or_default(); + let input_cursor = + app.input.as_ref().map(|i| i.cursor()).unwrap_or_default(); + let input_buf = Paragraph::new(Spans::from(vec![ Span::styled( app.config @@ -779,22 +799,20 @@ fn draw_input_buffer( .unwrap_or_default(), app.config.general.prompt.style.to_owned().into(), ), - Span::raw(app.input_buffer.clone().unwrap_or_else(|| "".into())), - Span::styled( - app.config - .general - .cursor - .format - .to_owned() - .unwrap_or_default(), - app.config.general.cursor.style.to_owned().into(), - ), + Span::raw(&input_val), ])) .block(block( config, format!(" Input [{}{}] ", app.mode.name, read_only_indicator(app)), )); + f.render_widget(input_buf, layout_size); + f.set_cursor( + // Put cursor past the end of the input text + layout_size.x + input_cursor as u16 + cursor_offset, + // Move one line down, from the border to the input line + layout_size.y + 1, + ); } fn draw_sort_n_filter( @@ -1202,7 +1220,7 @@ pub fn draw_layout( draw_selection(f, screen_size, layout_size, app, lua) } Layout::InputAndLogs => { - if app.input_buffer.is_some() { + if app.input.is_some() { draw_input_buffer(f, screen_size, layout_size, app, lua); } else { draw_logs(f, screen_size, layout_size, app, lua);