mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
WIP [no ci]
This commit is contained in:
parent
b749972908
commit
11d8ee6f5b
11 changed files with 124 additions and 116 deletions
|
|
@ -102,9 +102,15 @@ impl Exec {
|
|||
pub fn vec(self) -> Vec<Self> { 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
|
||||
}
|
||||
|
|
|
|||
5
yazi-core/src/completion/commands/mod.rs
Normal file
5
yazi-core/src/completion/commands/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
mod show;
|
||||
mod trigger;
|
||||
|
||||
pub use show::*;
|
||||
pub use trigger::*;
|
||||
32
yazi-core/src/completion/commands/show.rs
Normal file
32
yazi-core/src/completion/commands/show.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use yazi_config::keymap::Exec;
|
||||
|
||||
use crate::completion::Completion;
|
||||
|
||||
pub struct Opt<'a> {
|
||||
cands: &'a Vec<String>,
|
||||
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<Opt<'a>>) -> 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
|
||||
}
|
||||
}
|
||||
34
yazi-core/src/completion/commands/trigger.rs
Normal file
34
yazi-core/src/completion/commands/trigger.rs
Normal file
|
|
@ -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<Opt<'a>>) -> 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
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +1,16 @@
|
|||
use crate::{completion::CompletionOpt, Position};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Completion {
|
||||
pub items: Vec<String>,
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
mod commands;
|
||||
mod completion;
|
||||
mod option;
|
||||
|
||||
pub(super) use completion::Completion;
|
||||
pub use option::CompletionOpt;
|
||||
pub(super) use completion::*;
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
use ratatui::layout::Rect;
|
||||
|
||||
use crate::Position;
|
||||
|
||||
pub struct CompletionOpt {
|
||||
pub items: Vec<String>,
|
||||
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<String>) -> Self {
|
||||
self.items = items;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -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<UnboundedSender<Result<String, InputError>>>,
|
||||
realtime: bool,
|
||||
callback: Option<UnboundedSender<Result<String, InputError>>>,
|
||||
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
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<str>) -> 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<str>) -> 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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())));
|
||||
|
|
|
|||
|
|
@ -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" => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue