WIP [no ci]

This commit is contained in:
sxyazi 2023-11-01 21:58:23 +08:00
parent b749972908
commit 11d8ee6f5b
No known key found for this signature in database
11 changed files with 124 additions and 116 deletions

View file

@ -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
}

View file

@ -0,0 +1,5 @@
mod show;
mod trigger;
pub use show::*;
pub use trigger::*;

View 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
}
}

View 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
}
}

View file

@ -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 version: usize,
pub visible: bool,
// TODO: remove these
pub position: Position,
pub column_cnt: u8,
pub max_width: u16,
}
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
}

View file

@ -1,5 +1,4 @@
mod commands;
mod completion;
mod option;
pub(super) use completion::Completion;
pub use option::CompletionOpt;
pub(super) use completion::*;

View file

@ -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
}
}

View file

@ -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 {
@ -20,6 +20,7 @@ pub struct Input {
// Typing
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
));
}
}
}

View file

@ -2,11 +2,13 @@ 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 completion: bool,
pub highlight: bool,
}
@ -14,23 +16,19 @@ 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,
..Default::default()
}
}
pub fn hovered(title: impl AsRef<str>) -> Self {
Self {
title: title.as_ref().to_owned(),
value: String::new(),
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
}
}

View file

@ -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())));

View file

@ -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" => {