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
9a67c0150e
commit
802aa86e23
11 changed files with 137 additions and 246 deletions
|
|
@ -237,3 +237,18 @@ keymap = [
|
||||||
# Filtering
|
# Filtering
|
||||||
{ on = [ "/" ], exec = "filter", desc = "Apply a filter for the help items" },
|
{ on = [ "/" ], exec = "filter", desc = "Apply a filter for the help items" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[completion]
|
||||||
|
|
||||||
|
keymap = [
|
||||||
|
{ on = [ "<C-q>" ], exec = "close", desc = "Cancel completion" },
|
||||||
|
{ on = [ "<Enter>" ], exec = "close --submit", desc = "Submit the completion" },
|
||||||
|
|
||||||
|
{ on = [ "k" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||||
|
{ on = [ "j" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||||
|
|
||||||
|
{ on = [ "<Up>" ], exec = "arrow -1", desc = "Move cursor up" },
|
||||||
|
{ on = [ "<Down>" ], exec = "arrow 1", desc = "Move cursor down" },
|
||||||
|
|
||||||
|
{ on = [ "~" ], exec = "help", desc = "Open help" }
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,12 @@ use crate::MERGED_KEYMAP;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Keymap {
|
pub struct Keymap {
|
||||||
pub manager: Vec<Control>,
|
pub manager: Vec<Control>,
|
||||||
pub tasks: Vec<Control>,
|
pub tasks: Vec<Control>,
|
||||||
pub select: Vec<Control>,
|
pub select: Vec<Control>,
|
||||||
pub input: Vec<Control>,
|
pub input: Vec<Control>,
|
||||||
pub help: Vec<Control>,
|
pub help: Vec<Control>,
|
||||||
|
pub completion: Vec<Control>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Keymap {
|
impl<'de> Deserialize<'de> for Keymap {
|
||||||
|
|
@ -21,11 +22,12 @@ impl<'de> Deserialize<'de> for Keymap {
|
||||||
{
|
{
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Shadow {
|
struct Shadow {
|
||||||
manager: Inner,
|
manager: Inner,
|
||||||
tasks: Inner,
|
tasks: Inner,
|
||||||
select: Inner,
|
select: Inner,
|
||||||
input: Inner,
|
input: Inner,
|
||||||
help: Inner,
|
help: Inner,
|
||||||
|
completion: Inner,
|
||||||
}
|
}
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Inner {
|
struct Inner {
|
||||||
|
|
@ -34,11 +36,12 @@ impl<'de> Deserialize<'de> for Keymap {
|
||||||
|
|
||||||
let shadow = Shadow::deserialize(deserializer)?;
|
let shadow = Shadow::deserialize(deserializer)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
manager: shadow.manager.keymap,
|
manager: shadow.manager.keymap,
|
||||||
tasks: shadow.tasks.keymap,
|
tasks: shadow.tasks.keymap,
|
||||||
select: shadow.select.keymap,
|
select: shadow.select.keymap,
|
||||||
input: shadow.input.keymap,
|
input: shadow.input.keymap,
|
||||||
help: shadow.help.keymap,
|
help: shadow.help.keymap,
|
||||||
|
completion: shadow.completion.keymap,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -56,6 +59,7 @@ impl Keymap {
|
||||||
KeymapLayer::Select => &self.select,
|
KeymapLayer::Select => &self.select,
|
||||||
KeymapLayer::Input => &self.input,
|
KeymapLayer::Input => &self.input,
|
||||||
KeymapLayer::Help => &self.help,
|
KeymapLayer::Help => &self.help,
|
||||||
|
KeymapLayer::Completion => &self.completion,
|
||||||
KeymapLayer::Which => unreachable!(),
|
KeymapLayer::Which => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,6 +73,7 @@ pub enum KeymapLayer {
|
||||||
Select,
|
Select,
|
||||||
Input,
|
Input,
|
||||||
Help,
|
Help,
|
||||||
|
Completion,
|
||||||
Which,
|
Which,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,6 +85,7 @@ impl Display for KeymapLayer {
|
||||||
KeymapLayer::Select => write!(f, "select"),
|
KeymapLayer::Select => write!(f, "select"),
|
||||||
KeymapLayer::Input => write!(f, "input"),
|
KeymapLayer::Input => write!(f, "input"),
|
||||||
KeymapLayer::Help => write!(f, "help"),
|
KeymapLayer::Help => write!(f, "help"),
|
||||||
|
KeymapLayer::Completion => write!(f, "completion"),
|
||||||
KeymapLayer::Which => write!(f, "which"),
|
KeymapLayer::Which => write!(f, "which"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,26 +3,28 @@ use ratatui::prelude::Rect;
|
||||||
use yazi_config::keymap::KeymapLayer;
|
use yazi_config::keymap::KeymapLayer;
|
||||||
use yazi_shared::Term;
|
use yazi_shared::Term;
|
||||||
|
|
||||||
use crate::{help::Help, input::Input, manager::Manager, select::Select, tasks::Tasks, which::Which, Position};
|
use crate::{completion::Completion, help::Help, input::Input, manager::Manager, select::Select, tasks::Tasks, which::Which, Position};
|
||||||
|
|
||||||
pub struct Ctx {
|
pub struct Ctx {
|
||||||
pub manager: Manager,
|
pub manager: Manager,
|
||||||
pub which: Which,
|
pub tasks: Tasks,
|
||||||
pub help: Help,
|
pub select: Select,
|
||||||
pub input: Input,
|
pub input: Input,
|
||||||
pub select: Select,
|
pub help: Help,
|
||||||
pub tasks: Tasks,
|
pub completion: Completion,
|
||||||
|
pub which: Which,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx {
|
impl Ctx {
|
||||||
pub fn make() -> Self {
|
pub fn make() -> Self {
|
||||||
Self {
|
Self {
|
||||||
manager: Manager::make(),
|
manager: Manager::make(),
|
||||||
which: Default::default(),
|
tasks: Tasks::start(),
|
||||||
help: Default::default(),
|
select: Default::default(),
|
||||||
input: Default::default(),
|
input: Default::default(),
|
||||||
select: Default::default(),
|
help: Default::default(),
|
||||||
tasks: Tasks::start(),
|
completion: Default::default(),
|
||||||
|
which: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -72,6 +74,8 @@ impl Ctx {
|
||||||
pub fn layer(&self) -> KeymapLayer {
|
pub fn layer(&self) -> KeymapLayer {
|
||||||
if self.which.visible {
|
if self.which.visible {
|
||||||
KeymapLayer::Which
|
KeymapLayer::Which
|
||||||
|
} else if self.completion.visible {
|
||||||
|
KeymapLayer::Completion
|
||||||
} else if self.help.visible {
|
} else if self.help.visible {
|
||||||
KeymapLayer::Help
|
KeymapLayer::Help
|
||||||
} else if self.input.visible {
|
} else if self.input.visible {
|
||||||
|
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
use crossterm::event::KeyCode;
|
|
||||||
use yazi_config::keymap::{Exec, Key, KeymapLayer};
|
|
||||||
|
|
||||||
use crate::{completion::CompletionOpt, emit, input::Input};
|
|
||||||
|
|
||||||
impl Input {
|
|
||||||
pub fn complete(&mut self) -> bool {
|
|
||||||
if !self.completion.visible {
|
|
||||||
if let Some(f) = self.init_completion.as_ref() {
|
|
||||||
let future = f(self.snaps.current().value.clone());
|
|
||||||
let id = self.completion.identifier.clone();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
let result = future.await;
|
|
||||||
let mut exec = Exec::call("complete", result);
|
|
||||||
exec.named.insert("identifier".to_string(), id);
|
|
||||||
emit!(Call(exec.vec(), KeymapLayer::Input));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill_completion(&mut self, exec: &Exec) -> bool {
|
|
||||||
if !exec.named.get("identifier").is_some_and(|id| *id == self.completion.identifier) {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
match exec.args.len() {
|
|
||||||
0 => false,
|
|
||||||
1 => {
|
|
||||||
if let Some(f) = self.finish_completion.as_ref() {
|
|
||||||
self
|
|
||||||
.replace_str(f(self.snaps.current().value.as_str(), exec.args.get(0).unwrap()).as_str())
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.completion.show(CompletionOpt::top().with_items(exec.args.clone()));
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn navigate_completion(&mut self, key: &Key) -> bool {
|
|
||||||
match key.code {
|
|
||||||
KeyCode::Up => self.completion.prev(self.completion.column_cnt as usize),
|
|
||||||
KeyCode::Down => self.completion.next(self.completion.column_cnt as usize),
|
|
||||||
KeyCode::Left => self.completion.prev(1),
|
|
||||||
KeyCode::Right | KeyCode::Tab => self.completion.next(1),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn finish_completion(&mut self) -> bool {
|
|
||||||
if let (Some(val), Some(f)) = (self.completion.selected(), &self.finish_completion) {
|
|
||||||
let final_val = f(self.snaps.current().value.as_str(), val.as_str());
|
|
||||||
self.replace_str(final_val.as_str());
|
|
||||||
}
|
|
||||||
self.completion.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,8 +6,8 @@ use unicode_width::UnicodeWidthStr;
|
||||||
use yazi_config::keymap::Key;
|
use yazi_config::keymap::Key;
|
||||||
use yazi_shared::{CharKind, InputError};
|
use yazi_shared::{CharKind, InputError};
|
||||||
|
|
||||||
use super::{mode::InputMode, op::InputOp, FinishCompletionType, InitCompletionType, InputOpt, InputSnap, InputSnaps};
|
use super::{mode::InputMode, op::InputOp, InputOpt, InputSnap, InputSnaps};
|
||||||
use crate::{completion::Completion, external, Position};
|
use crate::{external, Position};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
|
|
@ -23,10 +23,6 @@ pub struct Input {
|
||||||
|
|
||||||
// Shell
|
// Shell
|
||||||
pub(super) highlight: bool,
|
pub(super) highlight: bool,
|
||||||
|
|
||||||
pub completion: Completion,
|
|
||||||
pub(super) init_completion: Option<InitCompletionType>,
|
|
||||||
pub(super) finish_completion: Option<FinishCompletionType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
|
|
@ -44,9 +40,6 @@ impl Input {
|
||||||
|
|
||||||
// Shell
|
// Shell
|
||||||
self.highlight = opt.highlight;
|
self.highlight = opt.highlight;
|
||||||
|
|
||||||
self.init_completion = opt.init_completion;
|
|
||||||
self.finish_completion = opt.finish_completion;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&mut self, submit: bool) -> bool {
|
pub fn close(&mut self, submit: bool) -> bool {
|
||||||
|
|
@ -56,7 +49,6 @@ impl Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.visible = false;
|
self.visible = false;
|
||||||
self.completion.close();
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,25 +189,6 @@ impl Input {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.completion.visible {
|
|
||||||
match key {
|
|
||||||
Key {
|
|
||||||
code: KeyCode::Tab | KeyCode::Up | KeyCode::Down | KeyCode::Left | KeyCode::Right,
|
|
||||||
shift: false,
|
|
||||||
ctrl: false,
|
|
||||||
alt: false,
|
|
||||||
} => return self.navigate_completion(key),
|
|
||||||
Key { code: KeyCode::Enter, shift: false, ctrl: false, alt: false } => {
|
|
||||||
return self.finish_completion();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.completion.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if matches!(key, Key { code: KeyCode::Tab, shift: false, ctrl: false, alt: false }) {
|
|
||||||
return self.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(c) = key.plain() {
|
if let Some(c) = key.plain() {
|
||||||
return self.type_char(c);
|
return self.type_char(c);
|
||||||
}
|
}
|
||||||
|
|
@ -244,13 +217,6 @@ impl Input {
|
||||||
self.move_(s.chars().count() as isize)
|
self.move_(s.chars().count() as isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn replace_str(&mut self, s: &str) -> bool {
|
|
||||||
let snap = self.snaps.current_mut();
|
|
||||||
snap.value = s.to_string();
|
|
||||||
self.flush_value();
|
|
||||||
self.move_(s.chars().count() as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn backspace(&mut self) -> bool {
|
pub fn backspace(&mut self) -> bool {
|
||||||
let snap = self.snaps.current_mut();
|
let snap = self.snaps.current_mut();
|
||||||
if snap.cursor < 1 {
|
if snap.cursor < 1 {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
mod completion;
|
|
||||||
mod input;
|
mod input;
|
||||||
mod mode;
|
mod mode;
|
||||||
mod op;
|
mod op;
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,39 @@
|
||||||
use std::{future::Future, pin::Pin};
|
|
||||||
|
|
||||||
use ratatui::prelude::Rect;
|
use ratatui::prelude::Rect;
|
||||||
|
|
||||||
use crate::Position;
|
use crate::Position;
|
||||||
|
|
||||||
pub type InitCompletionType =
|
|
||||||
Box<dyn Fn(String) -> Pin<Box<dyn Future<Output = Vec<String>> + Send>> + Send>;
|
|
||||||
pub type FinishCompletionType = Box<dyn Fn(&str, &str) -> String + Send>;
|
|
||||||
|
|
||||||
pub struct InputOpt {
|
pub struct InputOpt {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
pub realtime: bool,
|
pub realtime: bool,
|
||||||
pub highlight: bool,
|
pub highlight: bool,
|
||||||
pub init_completion: Option<InitCompletionType>,
|
|
||||||
pub finish_completion: Option<FinishCompletionType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputOpt {
|
impl InputOpt {
|
||||||
pub fn top(title: impl AsRef<str>) -> Self {
|
pub fn top(title: impl AsRef<str>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: title.as_ref().to_owned(),
|
title: title.as_ref().to_owned(),
|
||||||
value: String::new(),
|
value: String::new(),
|
||||||
position: Position::Top(
|
position: Position::Top(
|
||||||
// TODO: hardcode
|
// TODO: hardcode
|
||||||
Rect { x: 0, y: 2, width: 50, height: 3 },
|
Rect { x: 0, y: 2, width: 50, height: 3 },
|
||||||
),
|
),
|
||||||
realtime: false,
|
realtime: false,
|
||||||
highlight: false,
|
highlight: false,
|
||||||
init_completion: None,
|
|
||||||
finish_completion: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hovered(title: impl AsRef<str>) -> Self {
|
pub fn hovered(title: impl AsRef<str>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: title.as_ref().to_owned(),
|
title: title.as_ref().to_owned(),
|
||||||
value: String::new(),
|
value: String::new(),
|
||||||
position: Position::Hovered(
|
position: Position::Hovered(
|
||||||
// TODO: hardcode
|
// TODO: hardcode
|
||||||
Rect { x: 0, y: 1, width: 50, height: 3 },
|
Rect { x: 0, y: 1, width: 50, height: 3 },
|
||||||
),
|
),
|
||||||
realtime: false,
|
realtime: false,
|
||||||
highlight: false,
|
highlight: false,
|
||||||
init_completion: None,
|
|
||||||
finish_completion: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,16 +56,5 @@ impl InputOpt {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_completion<
|
pub fn with_completion(mut self) -> Self { todo!() }
|
||||||
F1: Fn(String) -> Pin<Box<dyn Future<Output = Vec<String>> + Send>> + Send + 'static,
|
|
||||||
F2: Fn(&str, &str) -> String + Send + 'static,
|
|
||||||
>(
|
|
||||||
mut self,
|
|
||||||
init_completion: F1,
|
|
||||||
finish_completion: F2,
|
|
||||||
) -> Self {
|
|
||||||
self.init_completion = Some(Box::new(init_completion));
|
|
||||||
self.finish_completion = Some(Box::new(finish_completion));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,38 +59,8 @@ impl Tab {
|
||||||
|
|
||||||
pub fn cd_interactive(&mut self, target: Url) -> bool {
|
pub fn cd_interactive(&mut self, target: Url) -> bool {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut result = emit!(Input(
|
let mut result =
|
||||||
InputOpt::top("Change directory:").with_value(target.to_string_lossy()).with_completion(
|
emit!(Input(InputOpt::top("Change directory:").with_value(target.to_string_lossy())));
|
||||||
|prefix| {
|
|
||||||
Box::pin(async move {
|
|
||||||
let mut cmp_prefix = prefix.as_str();
|
|
||||||
let mut result = vec![];
|
|
||||||
if let Ok(mut list) = if prefix.contains('/') {
|
|
||||||
let (old_prefix, old_file_prefix) = prefix.rsplit_once('/').unwrap();
|
|
||||||
cmp_prefix = old_file_prefix;
|
|
||||||
tokio::fs::read_dir(old_prefix.to_string() + "/").await
|
|
||||||
} else {
|
|
||||||
tokio::fs::read_dir(".").await
|
|
||||||
} {
|
|
||||||
while let Ok(Some(f)) = list.next_entry().await {
|
|
||||||
let name = f.file_name().to_string_lossy().to_string();
|
|
||||||
if f.metadata().await.is_ok_and(|m| m.is_dir()) && name.starts_with(cmp_prefix) {
|
|
||||||
result.push(name.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|current, new| {
|
|
||||||
if let Some((prefix, _)) = current.rsplit_once('/') {
|
|
||||||
format!("{prefix}/{new}/")
|
|
||||||
} else {
|
|
||||||
format!("{new}/")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
));
|
|
||||||
|
|
||||||
if let Some(Ok(s)) = result.recv().await {
|
if let Some(Ok(s)) = result.recv().await {
|
||||||
emit!(Cd(Url::from(s.trim())));
|
emit!(Cd(Url::from(s.trim())));
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,4 @@
|
||||||
use std::mem;
|
use ratatui::{buffer::Buffer, layout::Rect, widgets::{Block, BorderType, Borders, Cell, 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;
|
use yazi_core::Ctx;
|
||||||
|
|
||||||
pub(crate) struct Completion<'a> {
|
pub(crate) struct Completion<'a> {
|
||||||
|
|
@ -14,46 +11,47 @@ impl<'a> Completion<'a> {
|
||||||
|
|
||||||
impl<'a> Widget for Completion<'a> {
|
impl<'a> Widget for Completion<'a> {
|
||||||
fn render(self, _: Rect, buf: &mut Buffer) {
|
fn render(self, _: Rect, buf: &mut Buffer) {
|
||||||
let completion = &self.cx.input.completion;
|
todo!()
|
||||||
let area = self.cx.area(&completion.position);
|
// let completion = &self.cx.input.completion;
|
||||||
|
// let area = self.cx.area(&completion.position);
|
||||||
|
|
||||||
let constraint = (0..completion.column_cnt)
|
// let constraint = (0..completion.column_cnt)
|
||||||
.map(|_| Constraint::Percentage(completion.max_width))
|
// .map(|_| Constraint::Percentage(completion.max_width))
|
||||||
.collect::<Vec<Constraint>>();
|
// .collect::<Vec<Constraint>>();
|
||||||
let table = {
|
// let table = {
|
||||||
let max_width = completion.max_width as usize;
|
// let max_width = completion.max_width as usize;
|
||||||
let mut table = vec![];
|
// let mut table = vec![];
|
||||||
let mut cur_row = vec![];
|
// let mut cur_row = vec![];
|
||||||
for (idx, s) in completion.items.iter().enumerate() {
|
// for (idx, s) in completion.items.iter().enumerate() {
|
||||||
if idx != 0 && idx % completion.column_cnt as usize == 0 {
|
// if idx != 0 && idx % completion.column_cnt as usize == 0 {
|
||||||
let t = mem::take(&mut cur_row);
|
// let t = mem::take(&mut cur_row);
|
||||||
table.push(Row::new(t));
|
// table.push(Row::new(t));
|
||||||
}
|
// }
|
||||||
cur_row.push(
|
// cur_row.push(
|
||||||
Cell::from(if s.len() < max_width {
|
// Cell::from(if s.len() < max_width {
|
||||||
s.to_owned()
|
// s.to_owned()
|
||||||
} else {
|
// } else {
|
||||||
s.split_at(max_width - 1).0.to_string() + "…"
|
// s.split_at(max_width - 1).0.to_string() + "…"
|
||||||
})
|
// })
|
||||||
.style(if completion.cursor == idx {
|
// .style(if completion.cursor == idx {
|
||||||
THEME.completion.active.into()
|
// THEME.completion.active.into()
|
||||||
} else {
|
// } else {
|
||||||
THEME.completion.inactive.into()
|
// THEME.completion.inactive.into()
|
||||||
}),
|
// }),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
table.push(Row::new(cur_row));
|
// table.push(Row::new(cur_row));
|
||||||
Table::new(table)
|
// Table::new(table)
|
||||||
.block(
|
// .block(
|
||||||
Block::new()
|
// Block::new()
|
||||||
.borders(Borders::ALL)
|
// .borders(Borders::ALL)
|
||||||
.border_type(BorderType::Double)
|
// .border_type(BorderType::Double)
|
||||||
.border_style(THEME.completion.border.into()),
|
// .border_style(THEME.completion.border.into()),
|
||||||
)
|
// )
|
||||||
.widths(&constraint)
|
// .widths(&constraint)
|
||||||
};
|
// };
|
||||||
|
|
||||||
Clear.render(area, buf);
|
// Clear.render(area, buf);
|
||||||
table.render(area, buf);
|
// table.render(area, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ impl Executor {
|
||||||
KeymapLayer::Select => Self::select(cx, e),
|
KeymapLayer::Select => Self::select(cx, e),
|
||||||
KeymapLayer::Input => Self::input(cx, e),
|
KeymapLayer::Input => Self::input(cx, e),
|
||||||
KeymapLayer::Help => Self::help(cx, e),
|
KeymapLayer::Help => Self::help(cx, e),
|
||||||
|
KeymapLayer::Completion => Self::completion(cx, e),
|
||||||
KeymapLayer::Which => unreachable!(),
|
KeymapLayer::Which => unreachable!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -234,8 +235,7 @@ impl Executor {
|
||||||
return if in_operating { cx.input.move_in_operating(step) } else { cx.input.move_(step) };
|
return if in_operating { cx.input.move_in_operating(step) } else { cx.input.move_(step) };
|
||||||
}
|
}
|
||||||
|
|
||||||
// asynchronized completion
|
"complete" => todo!(),
|
||||||
"complete" => return cx.input.fill_completion(exec),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,4 +278,21 @@ impl Executor {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn completion(cx: &mut Ctx, exec: &Exec) -> bool {
|
||||||
|
match exec.cmd.as_str() {
|
||||||
|
"close" => cx.completion.close(),
|
||||||
|
|
||||||
|
"arrow" => {
|
||||||
|
let step: isize = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0);
|
||||||
|
if step > 0 {
|
||||||
|
cx.completion.next(step as usize)
|
||||||
|
} else {
|
||||||
|
cx.completion.prev(step.unsigned_abs())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,14 @@ impl<'a> Widget for Root<'a> {
|
||||||
input::Input::new(self.cx).render(area, buf);
|
input::Input::new(self.cx).render(area, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.cx.input.completion.visible {
|
|
||||||
completion::Completion::new(self.cx).render(area, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.cx.help.visible {
|
if self.cx.help.visible {
|
||||||
help::Layout::new(self.cx).render(area, buf);
|
help::Layout::new(self.cx).render(area, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.cx.completion.visible {
|
||||||
|
completion::Completion::new(self.cx).render(area, buf);
|
||||||
|
}
|
||||||
|
|
||||||
if self.cx.which.visible {
|
if self.cx.which.visible {
|
||||||
which::Which::new(self.cx).render(area, buf);
|
which::Which::new(self.cx).render(area, buf);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue