mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
Co-authored-by: Alastair Scheuermann <alastairsounds@users.noreply.github.com> Co-authored-by: sxyazi <sxyazi@gmail.com>
108 lines
2.6 KiB
Rust
108 lines
2.6 KiB
Rust
use anyhow::Result;
|
|
use ratatui_widgets::block::Padding;
|
|
use yazi_binding::position::Position;
|
|
use yazi_config::{KEYMAP, keymap::ChordArc};
|
|
use yazi_macro::render;
|
|
use yazi_shared::Layer;
|
|
use yazi_term::event::KeyEvent;
|
|
use yazi_tty::sequence::SetCursorStyle;
|
|
use yazi_widgets::{Scrollable, input::Input};
|
|
|
|
#[derive(Default)]
|
|
pub struct Help {
|
|
pub visible: bool,
|
|
pub layer: Layer,
|
|
pub position: Position,
|
|
pub bindings: Vec<ChordArc>,
|
|
|
|
// Filter
|
|
pub input: Input,
|
|
pub keyword: String,
|
|
|
|
pub offset: usize,
|
|
pub cursor: usize,
|
|
pub height: u16,
|
|
}
|
|
|
|
impl Help {
|
|
pub fn r#type(&mut self, key: KeyEvent) -> Result<bool> {
|
|
if !self.input.r#type(key)? {
|
|
return Ok(false);
|
|
}
|
|
|
|
self.filter_apply();
|
|
Ok(true)
|
|
}
|
|
|
|
pub fn filter_apply(&mut self) {
|
|
let kw = self.input.value();
|
|
|
|
if kw.is_empty() {
|
|
self.keyword.clear();
|
|
self.bindings = KEYMAP.chords(self.layer).iter().cloned().collect();
|
|
} else if self.keyword != kw {
|
|
self.keyword = kw.to_owned();
|
|
self.bindings = Self::filter_chords(&KEYMAP.chords(self.layer), kw);
|
|
}
|
|
|
|
render!(self.scroll(0));
|
|
}
|
|
|
|
fn filter_chords(chords: &[ChordArc], kw: &str) -> Vec<ChordArc> {
|
|
let lowercased = kw.to_lowercase();
|
|
let mut exact = vec![];
|
|
let mut icase = vec![];
|
|
let mut contains = vec![];
|
|
let mut desc = vec![];
|
|
|
|
for c in chords {
|
|
let on = c.on();
|
|
if on.starts_with(kw) {
|
|
exact.push(c.clone());
|
|
} else if on.to_lowercase().starts_with(&lowercased) {
|
|
icase.push(c.clone());
|
|
} else if on.to_lowercase().contains(&lowercased) {
|
|
contains.push(c.clone());
|
|
} else if c.desc_or_run().to_lowercase().contains(&lowercased) {
|
|
desc.push(c.clone());
|
|
}
|
|
}
|
|
|
|
exact.extend(icase);
|
|
exact.extend(contains);
|
|
exact.extend(desc);
|
|
exact
|
|
}
|
|
}
|
|
|
|
impl Help {
|
|
pub fn padding(&self) -> Padding { Padding::new(1, 1, 1, 1) }
|
|
|
|
// --- Bindings
|
|
pub fn window(&self) -> &[ChordArc] {
|
|
let end = (self.offset + self.limit()).min(self.bindings.len());
|
|
&self.bindings[self.offset..end]
|
|
}
|
|
|
|
// --- Cursor
|
|
pub fn cursor(&self) -> Option<u16> { self.visible.then_some(self.input.cursor()) }
|
|
|
|
pub fn rel_cursor(&self) -> usize { self.cursor - self.offset }
|
|
|
|
pub fn cursor_shape(&self) -> Option<SetCursorStyle> {
|
|
self.visible.then_some(self.input.cursor_shape())
|
|
}
|
|
}
|
|
|
|
impl Scrollable for Help {
|
|
fn total(&self) -> usize { self.bindings.len() }
|
|
|
|
fn limit(&self) -> usize {
|
|
let p = self.padding();
|
|
self.height.saturating_sub(p.top + /* input */ 1 + /* divider */ 1 + p.bottom) as usize
|
|
}
|
|
|
|
fn cursor_mut(&mut self) -> &mut usize { &mut self.cursor }
|
|
|
|
fn offset_mut(&mut self) -> &mut usize { &mut self.offset }
|
|
}
|