From 11d8ee6f5b7c07c69496ef0c99c7a65917f83cf9 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Wed, 1 Nov 2023 21:58:23 +0800 Subject: [PATCH] WIP [no ci] --- yazi-config/src/keymap/exec.rs | 10 ++++- yazi-core/src/completion/commands/mod.rs | 5 +++ yazi-core/src/completion/commands/show.rs | 32 +++++++++++++++ yazi-core/src/completion/commands/trigger.rs | 34 ++++++++++++++++ yazi-core/src/completion/completion.rs | 31 +-------------- yazi-core/src/completion/mod.rs | 5 +-- yazi-core/src/completion/option.rs | 42 -------------------- yazi-core/src/input/input.rs | 35 ++++++++-------- yazi-core/src/input/option.rs | 37 ++++++++--------- yazi-core/src/tab/commands/cd.rs | 5 ++- yazi-fm/src/executor.rs | 4 +- 11 files changed, 124 insertions(+), 116 deletions(-) create mode 100644 yazi-core/src/completion/commands/mod.rs create mode 100644 yazi-core/src/completion/commands/show.rs create mode 100644 yazi-core/src/completion/commands/trigger.rs delete mode 100644 yazi-core/src/completion/option.rs diff --git a/yazi-config/src/keymap/exec.rs b/yazi-config/src/keymap/exec.rs index 207088a5..9548470a 100644 --- a/yazi-config/src/keymap/exec.rs +++ b/yazi-config/src/keymap/exec.rs @@ -102,9 +102,15 @@ impl Exec { pub fn vec(self) -> Vec { vec![self] } #[inline] - pub fn with_bool(mut self, name: &str, state: bool) -> Self { + pub fn with(mut self, name: impl ToString, value: impl ToString) -> Self { + self.named.insert(name.to_string(), value.to_string()); + self + } + + #[inline] + pub fn with_bool(mut self, name: impl ToString, state: bool) -> Self { if state { - self.named.insert(name.to_string(), "".to_string()); + self.named.insert(name.to_string(), Default::default()); } self } diff --git a/yazi-core/src/completion/commands/mod.rs b/yazi-core/src/completion/commands/mod.rs new file mode 100644 index 00000000..c026b752 --- /dev/null +++ b/yazi-core/src/completion/commands/mod.rs @@ -0,0 +1,5 @@ +mod show; +mod trigger; + +pub use show::*; +pub use trigger::*; diff --git a/yazi-core/src/completion/commands/show.rs b/yazi-core/src/completion/commands/show.rs new file mode 100644 index 00000000..1102d225 --- /dev/null +++ b/yazi-core/src/completion/commands/show.rs @@ -0,0 +1,32 @@ +use yazi_config::keymap::Exec; + +use crate::completion::Completion; + +pub struct Opt<'a> { + cands: &'a Vec, + version: usize, +} + +impl<'a> From<&'a Exec> for Opt<'a> { + fn from(e: &'a Exec) -> Self { + Self { + cands: &e.args, + version: e.named.get("version").and_then(|v| v.parse().ok()).unwrap_or(0), + } + } +} + +impl Completion { + pub fn show<'a>(&mut self, opt: impl Into>) -> bool { + let opt = opt.into(); + if self.version != opt.version { + return false; + } + + self.close(false); + self.items = opt.cands.clone(); + self.version = opt.version; + self.visible = true; + true + } +} diff --git a/yazi-core/src/completion/commands/trigger.rs b/yazi-core/src/completion/commands/trigger.rs new file mode 100644 index 00000000..ac977004 --- /dev/null +++ b/yazi-core/src/completion/commands/trigger.rs @@ -0,0 +1,34 @@ +use tracing::info; +use yazi_config::keymap::Exec; + +use crate::completion::Completion; + +pub struct Opt<'a> { + word: &'a str, + version: usize, +} + +impl<'a> From<&'a Exec> for Opt<'a> { + fn from(e: &'a Exec) -> Self { + Self { + word: e.args.get(0).map(|w| w.as_str()).unwrap_or_default(), + version: e.named.get("version").and_then(|v| v.parse().ok()).unwrap_or(0), + } + } +} + +impl Completion { + pub fn trigger<'a>(&mut self, opt: impl Into>) -> bool { + let opt = opt.into(); + if self.version >= opt.version { + return false; + } + + self.close(false); + self.version = opt.version; + + info!("trigger completion: {}", opt.word); + tokio::spawn(async move {}); + false + } +} diff --git a/yazi-core/src/completion/completion.rs b/yazi-core/src/completion/completion.rs index 4b41f2dc..d25198cf 100644 --- a/yazi-core/src/completion/completion.rs +++ b/yazi-core/src/completion/completion.rs @@ -1,43 +1,16 @@ -use crate::{completion::CompletionOpt, Position}; - #[derive(Default)] pub struct Completion { pub items: Vec, pub cursor: usize, - pub identifier: String, - pub visible: bool, - - // TODO: remove these - pub position: Position, - pub column_cnt: u8, - pub max_width: u16, + pub version: usize, + pub visible: bool, } impl Completion { - pub fn show(&mut self, opt: CompletionOpt) { - self.close(false); - self.items = opt.items; - - self.identifier = format!( - "{}", - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap_or_default() - .as_millis() - ); - self.visible = true; - - // TODO: remove these - self.position = opt.position; - self.column_cnt = opt.column_cnt; - self.max_width = opt.max_width; - } - pub fn close(&mut self, submit: bool) -> bool { self.cursor = 0; - self.identifier = String::new(); self.visible = false; true } diff --git a/yazi-core/src/completion/mod.rs b/yazi-core/src/completion/mod.rs index 434f45ed..daf831ad 100644 --- a/yazi-core/src/completion/mod.rs +++ b/yazi-core/src/completion/mod.rs @@ -1,5 +1,4 @@ +mod commands; mod completion; -mod option; -pub(super) use completion::Completion; -pub use option::CompletionOpt; +pub(super) use completion::*; diff --git a/yazi-core/src/completion/option.rs b/yazi-core/src/completion/option.rs deleted file mode 100644 index f6c3e1c0..00000000 --- a/yazi-core/src/completion/option.rs +++ /dev/null @@ -1,42 +0,0 @@ -use ratatui::layout::Rect; - -use crate::Position; - -pub struct CompletionOpt { - pub items: Vec, - pub position: Position, - pub column_cnt: u8, - pub max_width: u16, -} - -impl CompletionOpt { - pub fn top() -> Self { - Self { - items: vec![], - position: Position::Top( - // TODO: hardcode - Rect { x: 0, y: 5, width: 80, height: 10 }, - ), - column_cnt: 4, - max_width: 20, - } - } - - pub fn hover() -> Self { - Self { - items: vec![], - position: Position::Hovered( - // TODO: hardcode - Rect { x: 0, y: 3, width: 80, height: 10 }, - ), - column_cnt: 4, - max_width: 20, - } - } - - #[inline] - pub fn with_items(mut self, items: Vec) -> Self { - self.items = items; - self - } -} diff --git a/yazi-core/src/input/input.rs b/yazi-core/src/input/input.rs index 649218a2..fbe39bba 100644 --- a/yazi-core/src/input/input.rs +++ b/yazi-core/src/input/input.rs @@ -3,11 +3,11 @@ use std::ops::Range; use crossterm::event::KeyCode; use tokio::sync::mpsc::UnboundedSender; use unicode_width::UnicodeWidthStr; -use yazi_config::keymap::Key; +use yazi_config::keymap::{Exec, Key, KeymapLayer}; use yazi_shared::{CharKind, InputError}; use super::{mode::InputMode, op::InputOp, InputOpt, InputSnap, InputSnaps}; -use crate::{external, Position}; +use crate::{emit, external, Position}; #[derive(Default)] pub struct Input { @@ -18,8 +18,9 @@ pub struct Input { pub position: Position, // Typing - callback: Option>>, - realtime: bool, + callback: Option>>, + realtime: bool, + completion: bool, // Shell pub(super) highlight: bool, @@ -37,6 +38,7 @@ impl Input { // Typing self.callback = Some(tx); self.realtime = opt.realtime; + self.completion = opt.completion; // Shell self.highlight = opt.highlight; @@ -190,7 +192,8 @@ impl Input { } if let Some(c) = key.plain() { - return self.type_char(c); + let mut bits = [0; 4]; + return self.type_str(c.encode_utf8(&mut bits)); } match key { @@ -199,12 +202,6 @@ impl Input { } } - #[inline] - pub fn type_char(&mut self, c: char) -> bool { - let mut bits = [0; 4]; - self.type_str(c.encode_utf8(&mut bits)) - } - pub fn type_str(&mut self, s: &str) -> bool { let snap = self.snaps.current_mut(); if snap.cursor < 1 { @@ -278,9 +275,7 @@ impl Input { } self.insert(!before); - for c in s.to_string_lossy().chars() { - self.type_char(c); - } + self.type_str(&s.to_string_lossy()); self.escape(); true } @@ -305,10 +300,6 @@ impl Input { snap.op = InputOp::None; snap.mode = if insert { InputMode::Insert } else { InputMode::Normal }; snap.cursor = range.start; - - if self.realtime { - self.callback.as_ref().unwrap().send(Err(InputError::Typed(snap.value.clone()))).ok(); - } } InputOp::Yank(_) => { let range = snap.op.range(cursor, include).unwrap(); @@ -325,7 +316,7 @@ impl Input { return false; } if !matches!(old.op, InputOp::None | InputOp::Select(_)) { - self.snaps.tag(); + self.snaps.tag().then(|| self.flush_value()); } true } @@ -336,6 +327,12 @@ impl Input { let value = self.snap().value.clone(); self.callback.as_ref().unwrap().send(Err(InputError::Typed(value))).ok(); } + if self.completion { + emit!(Call( + Exec::call("complete", vec!["".to_string()]).with("version", 1).vec(), + KeymapLayer::Input + )); + } } } diff --git a/yazi-core/src/input/option.rs b/yazi-core/src/input/option.rs index 7424df87..f8bb6e64 100644 --- a/yazi-core/src/input/option.rs +++ b/yazi-core/src/input/option.rs @@ -2,35 +2,33 @@ use ratatui::prelude::Rect; use crate::Position; +#[derive(Default)] pub struct InputOpt { - pub title: String, - pub value: String, - pub position: Position, - pub realtime: bool, - pub highlight: bool, + pub title: String, + pub value: String, + pub position: Position, + pub realtime: bool, + pub completion: bool, + pub highlight: bool, } impl InputOpt { pub fn top(title: impl AsRef) -> Self { Self { - title: title.as_ref().to_owned(), - value: String::new(), - position: Position::Top(/* TODO: hardcode */ Rect { x: 0, y: 2, width: 50, height: 3 }), - realtime: false, - highlight: false, + title: title.as_ref().to_owned(), + position: Position::Top(/* TODO: hardcode */ Rect { x: 0, y: 2, width: 50, height: 3 }), + ..Default::default() } } pub fn hovered(title: impl AsRef) -> Self { Self { - title: title.as_ref().to_owned(), - value: String::new(), - position: Position::Hovered( + title: title.as_ref().to_owned(), + position: Position::Hovered( // TODO: hardcode Rect { x: 0, y: 1, width: 50, height: 3 }, ), - realtime: false, - highlight: false, + ..Default::default() } } @@ -47,11 +45,14 @@ impl InputOpt { } #[inline] - pub fn with_highlight(mut self) -> Self { - self.highlight = true; + pub fn with_completion(mut self) -> Self { + self.completion = true; self } #[inline] - pub fn with_completion(mut self) -> Self { todo!() } + pub fn with_highlight(mut self) -> Self { + self.highlight = true; + self + } } diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index 90ec2388..e7fc6b37 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -59,8 +59,9 @@ impl Tab { pub fn cd_interactive(&mut self, target: Url) -> bool { tokio::spawn(async move { - let mut result = - emit!(Input(InputOpt::top("Change directory:").with_value(target.to_string_lossy()))); + let mut result = emit!(Input( + InputOpt::top("Change directory:").with_value(target.to_string_lossy()).with_completion() + )); if let Some(Ok(s)) = result.recv().await { emit!(Cd(Url::from(s.trim()))); diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 6be2f567..0631dfd0 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -235,7 +235,7 @@ impl Executor { return if in_operating { cx.input.move_in_operating(step) } else { cx.input.move_(step) }; } - "complete" => todo!(), + "complete" => return cx.completion.trigger(exec), _ => {} } @@ -281,6 +281,8 @@ impl Executor { fn completion(cx: &mut Ctx, exec: &Exec) -> bool { match exec.cmd.as_str() { + "trigger" => cx.completion.trigger(exec), + "show" => cx.completion.show(exec), "close" => cx.completion.close(exec.named.contains_key("submit")), "arrow" => {