mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 14:51:03 +00:00
107 lines
2.8 KiB
Rust
107 lines
2.8 KiB
Rust
use anyhow::Result;
|
|
use unicode_width::UnicodeWidthStr;
|
|
use yazi_config::{KEYMAP, YAZI, keymap::{Chord, Key}};
|
|
use yazi_macro::{act, render, render_and};
|
|
use yazi_shared::Layer;
|
|
use yazi_term::{CursorStyle, TERM, event::KeyCode};
|
|
use yazi_widgets::Scrollable;
|
|
|
|
use crate::help::HELP_MARGIN;
|
|
|
|
#[derive(Default)]
|
|
pub struct Help {
|
|
pub visible: bool,
|
|
pub layer: Layer,
|
|
pub(super) bindings: Vec<&'static Chord>,
|
|
|
|
// Filter
|
|
pub keyword: String,
|
|
pub in_filter: Option<yazi_widgets::input::Input>,
|
|
|
|
pub offset: usize,
|
|
pub cursor: usize,
|
|
}
|
|
|
|
impl Help {
|
|
pub fn r#type(&mut self, key: &Key) -> Result<bool> {
|
|
let Some(input) = &mut self.in_filter else { return Ok(false) };
|
|
match key {
|
|
Key { code: KeyCode::Escape, shift: false, ctrl: false, alt: false, super_: false } => {
|
|
self.in_filter = None;
|
|
render!();
|
|
}
|
|
Key { code: KeyCode::Enter, shift: false, ctrl: false, alt: false, super_: false } => {
|
|
self.in_filter = None;
|
|
return Ok(render_and!(true)); // Don't do the `filter_apply` below, since we already have the filtered results.
|
|
}
|
|
Key { code: KeyCode::Backspace, shift: false, ctrl: false, alt: false, super_: false } => {
|
|
act!(backspace, input)?;
|
|
}
|
|
_ => {
|
|
input.r#type(key)?;
|
|
}
|
|
}
|
|
|
|
self.filter_apply();
|
|
Ok(true)
|
|
}
|
|
|
|
pub fn filter_apply(&mut self) {
|
|
let kw = self.in_filter.as_ref().map_or("", |i| i.value());
|
|
|
|
if kw.is_empty() {
|
|
self.keyword = String::new();
|
|
self.bindings = KEYMAP.get(self.layer).iter().collect();
|
|
} else if self.keyword != kw {
|
|
self.keyword = kw.to_owned();
|
|
self.bindings = KEYMAP.get(self.layer).iter().filter(|&c| c.contains(kw)).collect();
|
|
}
|
|
|
|
render!(self.scroll(0));
|
|
}
|
|
}
|
|
|
|
impl Help {
|
|
// --- Keyword
|
|
pub fn keyword(&self) -> Option<String> {
|
|
self
|
|
.in_filter
|
|
.as_ref()
|
|
.map(|i| i.value())
|
|
.or(Some(self.keyword.as_str()).filter(|&s| !s.is_empty()))
|
|
.map(|s| format!("Filter: {s}"))
|
|
}
|
|
|
|
// --- Bindings
|
|
pub fn window(&self) -> &[&Chord] {
|
|
let end = (self.offset + self.limit()).min(self.bindings.len());
|
|
&self.bindings[self.offset..end]
|
|
}
|
|
|
|
// --- Cursor
|
|
pub fn cursor(&self) -> Option<(u16, u16)> {
|
|
if !self.visible || self.in_filter.is_none() {
|
|
return None;
|
|
}
|
|
if let Some(kw) = self.keyword() {
|
|
return Some((kw.width() as u16, TERM.dimension().rows));
|
|
}
|
|
None
|
|
}
|
|
|
|
pub fn rel_cursor(&self) -> usize { self.cursor - self.offset }
|
|
|
|
pub fn cursor_shape(&self) -> CursorStyle {
|
|
if YAZI.input.cursor_blink { CursorStyle::BlinkingBlock } else { CursorStyle::SteadyBlock }
|
|
}
|
|
}
|
|
|
|
impl Scrollable for Help {
|
|
fn total(&self) -> usize { self.bindings.len() }
|
|
|
|
fn limit(&self) -> usize { TERM.dimension().rows.saturating_sub(HELP_MARGIN) as usize }
|
|
|
|
fn cursor_mut(&mut self) -> &mut usize { &mut self.cursor }
|
|
|
|
fn offset_mut(&mut self) -> &mut usize { &mut self.offset }
|
|
}
|