From 6a31ed14cef84e2d49c64a2da6b909611ebd1019 Mon Sep 17 00:00:00 2001 From: XOR-op <17672363+XOR-op@users.noreply.github.com> Date: Thu, 26 Oct 2023 21:37:48 -0400 Subject: [PATCH] WIP(completion): render components --- yazi-core/src/completion/completion.rs | 4 ++++ yazi-core/src/completion/option.rs | 14 +++++++++-- yazi-core/src/input/completion.rs | 7 ++++-- yazi-core/src/input/input.rs | 4 ++++ yazi-core/src/input/option.rs | 9 ++++++++ yazi-core/src/tab/commands/cd.rs | 7 ++++-- yazi-fm/src/completion/completion.rs | 32 ++++++++++++++++++++------ 7 files changed, 64 insertions(+), 13 deletions(-) diff --git a/yazi-core/src/completion/completion.rs b/yazi-core/src/completion/completion.rs index 49147664..ee67e1c1 100644 --- a/yazi-core/src/completion/completion.rs +++ b/yazi-core/src/completion/completion.rs @@ -33,6 +33,8 @@ impl Completion { let old = self.cursor; self.cursor = (self.cursor + step).min(len - 1); + eprintln!("Cur: {}", self.items.get(self.cursor).unwrap()); + old != self.cursor } @@ -44,4 +46,6 @@ impl Completion { } pub fn list(&self) -> Vec { self.items.clone() } + + pub fn selected_cursor(&self) -> usize { self.cursor } } diff --git a/yazi-core/src/completion/option.rs b/yazi-core/src/completion/option.rs index 94e16285..03b59f74 100644 --- a/yazi-core/src/completion/option.rs +++ b/yazi-core/src/completion/option.rs @@ -8,12 +8,22 @@ pub struct CompletionOpt { } impl CompletionOpt { - pub fn hovered() -> Self { + pub fn top() -> Self { + Self { + items: vec![], + position: Position::Top( + // TODO: hardcode + Rect { x: 0, y: 5, width: 100, height: 10 }, + ), + } + } + + pub fn hover() -> Self { Self { items: vec![], position: Position::Hovered( // TODO: hardcode - Rect { x: 0, y: 1, width: 50, height: 3 }, + Rect { x: 0, y: 3, width: 40, height: 4 }, ), } } diff --git a/yazi-core/src/input/completion.rs b/yazi-core/src/input/completion.rs index 237c86db..4d1900fa 100644 --- a/yazi-core/src/input/completion.rs +++ b/yazi-core/src/input/completion.rs @@ -3,17 +3,20 @@ use crate::{completion::CompletionOpt, input::Input}; impl Input { pub fn complete(&mut self) -> bool { if !self.completion.visible { + eprintln!("Completing 1: {}", self.completion_callback.is_some()); let current = self.snaps.current().value.clone(); let result = self.completion_callback.as_ref().map(|f| f(current)).unwrap_or_default(); + eprintln!("Completing {:?}", result); match result.len() { 0 => false, 1 => self.type_str(result.get(0).unwrap()), _ => { - self.completion.show(CompletionOpt::hovered().with_items(result)); - false + self.completion.show(CompletionOpt::top().with_items(result)); + true } } } else { + eprintln!("Completing @"); self.completion.next(1) } } diff --git a/yazi-core/src/input/input.rs b/yazi-core/src/input/input.rs index e895fc8a..479c2d0c 100644 --- a/yazi-core/src/input/input.rs +++ b/yazi-core/src/input/input.rs @@ -43,6 +43,8 @@ impl Input { // Shell self.highlight = opt.highlight; + + self.completion_callback = opt.completion_callback } pub fn close(&mut self, submit: bool) -> bool { @@ -52,6 +54,7 @@ impl Input { } self.visible = false; + self.completion.close(false); true } @@ -192,6 +195,7 @@ impl Input { return false; } + eprintln!("Type key {:?}", key); match key { Key { code: KeyCode::Tab, shift: false, ctrl: false, alt: false } => return self.complete(), _ => (), diff --git a/yazi-core/src/input/option.rs b/yazi-core/src/input/option.rs index d615b160..04fa3eb6 100644 --- a/yazi-core/src/input/option.rs +++ b/yazi-core/src/input/option.rs @@ -57,4 +57,13 @@ impl InputOpt { self.highlight = true; self } + + #[inline] + pub fn with_completion Vec + Send + 'static>( + mut self, + callback: F, + ) -> Self { + self.completion_callback = Some(Box::new(callback)); + self + } } diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index 90ec2388..9b3dc016 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -59,8 +59,11 @@ 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(|s| vec![s, "Hi".to_string()]) + )); if let Some(Ok(s)) = result.recv().await { emit!(Cd(Url::from(s.trim()))); diff --git a/yazi-fm/src/completion/completion.rs b/yazi-fm/src/completion/completion.rs index 80838cee..7cd4d154 100644 --- a/yazi-fm/src/completion/completion.rs +++ b/yazi-fm/src/completion/completion.rs @@ -1,6 +1,6 @@ use std::mem; -use ratatui::{buffer::Buffer, layout::Rect, widgets::{Block, BorderType, Borders, Clear, Row, Table, Widget}}; +use ratatui::{buffer::Buffer, layout::{Constraint, Rect}, widgets::{Block, BorderType, Borders, Cell, Clear, Row, Table, Widget}}; use yazi_config::THEME; use yazi_core::Ctx; @@ -17,24 +17,42 @@ impl<'a> Widget for Completion<'a> { let completion = &self.cx.input.completion; let area = self.cx.area(&completion.position); + const COLUMN_CNT: usize = 4; + const MAX_WIDTH: usize = 20; + let constraint = + (0..COLUMN_CNT).map(|_| Constraint::Ratio(1, MAX_WIDTH as u32)).collect::>(); let table = { let mut table = vec![]; let mut cur_row = vec![]; - const COLUMN_CNT: usize = 4; for (idx, s) in completion.list().into_iter().enumerate() { if idx != 0 && idx % COLUMN_CNT == 0 { let t = mem::take(&mut cur_row); table.push(Row::new(t)); } - cur_row.push(s); + // todo + cur_row.push( + Cell::from(if s.len() < MAX_WIDTH { + s + } else { + s.split_at(MAX_WIDTH - 1).0.to_string() + "…" + }) + .style(if completion.selected_cursor() == idx { + THEME.select.active.into() + } else { + THEME.select.inactive.into() + }), + ); } - Table::new(table).block( - Block::new() + table.push(Row::new(cur_row)); + Table::new(table) + .block( + Block::new() .borders(Borders::ALL) - .border_type(BorderType::Rounded) + .border_type(BorderType::Double) // todo .border_style(THEME.select.border.into()), - ) + ) + .widths(&constraint) }; Clear.render(area, buf);