mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 14:51:03 +00:00
feat: context-aware icons for inputs (#4080)
This commit is contained in:
parent
2a106aa231
commit
ef654f4420
7 changed files with 59 additions and 11 deletions
|
|
@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|||
- Bulk create ([#3793])
|
||||
- Make help menu a command palette ([#4074])
|
||||
- H/M/L Vim-like motion for moving cursor relative to viewport ([#3970])
|
||||
- Context-aware icons for inputs ([#4080])
|
||||
- Dynamic keymap Lua API ([#4031])
|
||||
- New `ui.Input` element ([#4040])
|
||||
- Image preview with Überzug++ on Niri ([#3990])
|
||||
|
|
@ -1763,3 +1764,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|||
[#4067]: https://github.com/sxyazi/yazi/pull/4067
|
||||
[#4068]: https://github.com/sxyazi/yazi/pull/4068
|
||||
[#4074]: https://github.com/sxyazi/yazi/pull/4074
|
||||
[#4080]: https://github.com/sxyazi/yazi/pull/4080
|
||||
|
|
|
|||
|
|
@ -21,9 +21,10 @@ impl Actor for Show {
|
|||
|
||||
let area = cx.mgr.area(opt.position).padding(cx.input.padding());
|
||||
let input = &mut cx.input;
|
||||
input.main.visible = true;
|
||||
input.main.id = opt.id.clone();
|
||||
input.main.title = opt.title.clone();
|
||||
input.main.position = opt.position;
|
||||
input.main.visible = true;
|
||||
|
||||
opt.styles = (&THEME.input).into();
|
||||
opt.blinking = YAZI.input.cursor_blink;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ impl Actor for Rename {
|
|||
};
|
||||
|
||||
let (tab, old) = (cx.tab().id, hovered.url_owned());
|
||||
let mut input = input!(cx, YAZI.input.rename().with_value(name).with_cursor(cursor))?;
|
||||
let mut input =
|
||||
input!(cx, YAZI.input.rename(hovered.is_dir()).with_value(name).with_cursor(cursor))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let Some(InputEvent::Submit(name)) = input.recv().await else { return };
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ pub struct Input {
|
|||
impl Input {
|
||||
pub fn cd(&self, cwd: Url) -> InputOpt {
|
||||
InputOpt {
|
||||
id: "cd".to_owned(),
|
||||
title: self.cd_title.clone(),
|
||||
value: if cwd.kind().is_local() { String::new() } else { EncodeScheme(cwd).to_string() },
|
||||
position: Position::new(self.cd_origin, self.cd_offset),
|
||||
|
|
@ -57,14 +58,16 @@ impl Input {
|
|||
|
||||
pub fn create(&self, dir: bool) -> InputOpt {
|
||||
InputOpt {
|
||||
id: "create".to_owned(),
|
||||
title: self.create_title[dir as usize].clone(),
|
||||
position: Position::new(self.create_origin, self.create_offset),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rename(&self) -> InputOpt {
|
||||
pub fn rename(&self, is_dir: bool) -> InputOpt {
|
||||
InputOpt {
|
||||
id: format!("rename-{}", if is_dir { "dir" } else { "file" }),
|
||||
title: self.rename_title.clone(),
|
||||
position: Position::new(self.rename_origin, self.rename_offset),
|
||||
..Default::default()
|
||||
|
|
@ -73,6 +76,7 @@ impl Input {
|
|||
|
||||
pub fn filter(&self) -> InputOpt {
|
||||
InputOpt {
|
||||
id: "filter".to_owned(),
|
||||
title: self.filter_title.clone(),
|
||||
position: Position::new(self.filter_origin, self.filter_offset),
|
||||
realtime: true,
|
||||
|
|
@ -82,6 +86,7 @@ impl Input {
|
|||
|
||||
pub fn find(&self, prev: bool) -> InputOpt {
|
||||
InputOpt {
|
||||
id: "find".to_owned(),
|
||||
title: self.find_title[prev as usize].clone(),
|
||||
position: Position::new(self.find_origin, self.find_offset),
|
||||
realtime: true,
|
||||
|
|
@ -91,6 +96,7 @@ impl Input {
|
|||
|
||||
pub fn search(&self, name: &str) -> InputOpt {
|
||||
InputOpt {
|
||||
id: "search".to_owned(),
|
||||
title: self.search_title.replace("{n}", name),
|
||||
position: Position::new(self.search_origin, self.search_offset),
|
||||
..Default::default()
|
||||
|
|
@ -99,6 +105,7 @@ impl Input {
|
|||
|
||||
pub fn shell(&self, block: bool) -> InputOpt {
|
||||
InputOpt {
|
||||
id: "shell".to_owned(),
|
||||
title: self.shell_title[block as usize].clone(),
|
||||
position: Position::new(self.shell_origin, self.shell_offset),
|
||||
..Default::default()
|
||||
|
|
@ -107,6 +114,7 @@ impl Input {
|
|||
|
||||
pub fn tab_rename(&self) -> InputOpt {
|
||||
InputOpt {
|
||||
id: "tab-rename".to_owned(),
|
||||
title: "Rename tab:".to_owned(),
|
||||
position: Position::new(Origin::TopCenter, Offset {
|
||||
x: 0,
|
||||
|
|
|
|||
|
|
@ -52,9 +52,10 @@ impl Input {
|
|||
#[derive(Default)]
|
||||
pub struct InputMain {
|
||||
inner: yazi_widgets::input::Input,
|
||||
pub visible: bool,
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub position: Position,
|
||||
pub visible: bool,
|
||||
}
|
||||
|
||||
impl Deref for InputMain {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
use std::path::Path;
|
||||
|
||||
use ratatui_core::{buffer::Buffer, layout::{Margin, Rect}, text::Line, widgets::Widget};
|
||||
use ratatui_widgets::{block::Block, borders::BorderType};
|
||||
use yazi_config::THEME;
|
||||
use yazi_config::{Icon, THEME};
|
||||
use yazi_core::Core;
|
||||
use yazi_fs::{cha::{Cha, ChaKind}, file::File};
|
||||
use yazi_shim::path::CROSS_SEPARATOR;
|
||||
|
||||
pub(crate) struct Input<'a> {
|
||||
core: &'a Core,
|
||||
|
|
@ -9,21 +13,50 @@ pub(crate) struct Input<'a> {
|
|||
|
||||
impl<'a> Input<'a> {
|
||||
pub(crate) fn new(core: &'a Core) -> Self { Self { core } }
|
||||
|
||||
fn icon(&self) -> Option<Icon> {
|
||||
let input = &self.core.input.main;
|
||||
|
||||
let is_dir = input.value().ends_with(CROSS_SEPARATOR);
|
||||
let is_hovered = input.id.starts_with("rename-");
|
||||
|
||||
let (path, mode): (&str, u16) = match input.id.as_str() {
|
||||
"cd" => (input.value(), if is_dir { 0o40755 } else { 0o100644 }),
|
||||
"create" => (input.value(), if is_dir { 0o40755 } else { 0o100644 }),
|
||||
"rename-file" => (input.value(), 0o100644),
|
||||
"rename-dir" => (input.value(), 0o40755),
|
||||
"shell" => ("icon.sh", 0o100644),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
THEME.icon.matches(
|
||||
&File {
|
||||
url: Path::new(path).into(),
|
||||
cha: Cha { kind: ChaKind::empty(), mode: mode.try_into().ok()?, ..Default::default() },
|
||||
link_to: None,
|
||||
},
|
||||
is_hovered,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Input<'_> {
|
||||
fn render(self, _: Rect, buf: &mut Buffer) {
|
||||
let input = &self.core.input;
|
||||
let input = &self.core.input.main;
|
||||
|
||||
let outer = self.core.mgr.area(input.main.position);
|
||||
let outer = self.core.mgr.area(input.position);
|
||||
yazi_widgets::clear::Clear::default().render(outer, buf);
|
||||
|
||||
Block::bordered()
|
||||
let mut block = Block::bordered()
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(THEME.input.border.get())
|
||||
.title(Line::styled(&input.main.title, THEME.input.title.get()))
|
||||
.render(outer, buf);
|
||||
.title(Line::styled(&input.title, THEME.input.title.get()));
|
||||
|
||||
input.main.render(outer.inner(Margin::new(1, 1)), buf);
|
||||
if let Some(i) = self.icon() {
|
||||
block = block.title_bottom(Line::raw(format!("{} ", i.text)).style(i.style).right_aligned());
|
||||
}
|
||||
|
||||
block.render(outer, buf);
|
||||
input.render(outer.inner(Margin::new(1, 1)), buf);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use crate::input::{InputCallback, InputStyles};
|
|||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct InputOpt {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
pub value: String,
|
||||
pub styles: InputStyles,
|
||||
|
|
@ -42,6 +43,7 @@ impl TryFrom<&Table> for InputOpt {
|
|||
|
||||
fn try_from(t: &Table) -> Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
id: t.raw_get("id").unwrap_or_default(),
|
||||
title: t.raw_get("title").unwrap_or_default(),
|
||||
value: t.raw_get("value").unwrap_or_default(),
|
||||
styles: t.raw_get("styles")?,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue