feat: numeric hotkeys for selection in pick (#3252)

This commit is contained in:
Krystof Gartner 2025-10-16 23:00:14 +02:00 committed by Kryštof Gärtner
parent f6408656b4
commit 392bc32620
No known key found for this signature in database
GPG key ID: C8E74747890C8819
10 changed files with 85 additions and 10 deletions

View file

@ -1 +1 @@
yazi_macro::mod_flat!(arrow close show); yazi_macro::mod_flat!(arrow close select show);

View file

@ -0,0 +1,31 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::pick::SelectForm;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};
pub struct Select;
impl Actor for Select {
type Form = SelectForm;
const NAME: &str = "select";
fn act(cx: &mut Ctx, opt: Self::Form) -> Result<Data> {
let pick = &mut cx.pick;
if opt.index >= pick.items.len() {
succ!();
}
if let Some(cb) = pick.callback.take() {
_ = cb.send(Some(opt.index));
}
pick.cursor = 0;
pick.offset = 0;
pick.visible = false;
succ!(render!());
}
}

View file

@ -220,6 +220,16 @@ keymap = [
{ on = "<Up>", run = "arrow prev", desc = "Previous option" }, { on = "<Up>", run = "arrow prev", desc = "Previous option" },
{ on = "<Down>", run = "arrow next", desc = "Next option" }, { on = "<Down>", run = "arrow next", desc = "Next option" },
{ on = "1", run = "select 0", desc = "Select first option" },
{ on = "2", run = "select 1", desc = "Select second option" },
{ on = "3", run = "select 2", desc = "Select third option" },
{ on = "4", run = "select 3", desc = "Select fourth option" },
{ on = "5", run = "select 4", desc = "Select fifth option" },
{ on = "6", run = "select 5", desc = "Select sixth option" },
{ on = "7", run = "select 6", desc = "Select seventh option" },
{ on = "8", run = "select 7", desc = "Select eighth option" },
{ on = "9", run = "select 8", desc = "Select ninth option" },
# Help # Help
{ on = "~", run = "help", desc = "Open help" }, { on = "~", run = "help", desc = "Open help" },
{ on = "<F1>", run = "help", desc = "Open help" }, { on = "<F1>", run = "help", desc = "Open help" },

View file

@ -238,6 +238,7 @@ quit_offset = [ 0, 0, 50, 15 ]
open_title = "Open with:" open_title = "Open with:"
open_origin = "hovered" open_origin = "hovered"
open_offset = [ 0, 1, 50, 7 ] open_offset = [ 0, 1, 50, 7 ]
line_numbers = true
[which] [which]
sort_by = "none" sort_by = "none"

View file

@ -6,9 +6,10 @@ use super::{Offset, Origin};
#[derive(Deserialize, DeserializeOver2)] #[derive(Deserialize, DeserializeOver2)]
pub struct Pick { pub struct Pick {
// open // open
pub open_title: String, pub open_title: String,
pub open_origin: Origin, pub open_origin: Origin,
pub open_offset: Offset, pub open_offset: Offset,
pub line_numbers: bool,
} }
impl Pick { impl Pick {

View file

@ -235,6 +235,7 @@ impl<'a> Executor<'a> {
} }
on!(show); on!(show);
on!(select);
on!(close); on!(close);
on!(arrow); on!(arrow);

View file

@ -1,5 +1,5 @@
use ratatui::{buffer::Buffer, layout::{Margin, Rect}, widgets::{ListItem, Scrollbar, ScrollbarOrientation, ScrollbarState, StatefulWidget, Widget}}; use ratatui::{buffer::Buffer, layout::{Margin, Rect}, widgets::{ListItem, Scrollbar, ScrollbarOrientation, ScrollbarState, StatefulWidget, Widget}};
use yazi_config::THEME; use yazi_config::{THEME, YAZI};
use yazi_core::Core; use yazi_core::Core;
use yazi_widgets::Scrollable; use yazi_widgets::Scrollable;
@ -27,11 +27,16 @@ impl Widget for List<'_> {
// List content // List content
let inner = area.inner(Margin::new(1, 0)); let inner = area.inner(Margin::new(1, 0));
let items = pick.window().map(|(i, v)| { let items = pick.window().map(|(i, v)| {
if i == pick.cursor { let (prefix, style) =
ListItem::new(format!("{v}")).style(THEME.pick.active) if i == pick.cursor { ("", THEME.pick.active) } else { (" ", THEME.pick.inactive) };
let index_str = if !YAZI.pick.line_numbers {
"".to_string()
} else { } else {
ListItem::new(format!(" {v}")).style(THEME.pick.inactive) if i < 9 { format!("{:>2}", i + 1) } else { " ".to_string() }
} };
ListItem::new(format!("{prefix}{index_str} {v}")).style(style)
}); });
Widget::render(ratatui::widgets::List::new(items), inner, buf); Widget::render(ratatui::widgets::List::new(items), inner, buf);
} }

View file

@ -1 +1 @@
yazi_macro::mod_flat!(close show); yazi_macro::mod_flat!(close select show);

View file

@ -0,0 +1,23 @@
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_shared::event::ActionCow;
#[derive(Debug)]
pub struct SelectForm {
pub index: usize,
}
impl From<ActionCow> for SelectForm {
fn from(c: ActionCow) -> Self { Self { index: c.first().unwrap_or(0) } }
}
impl From<usize> for SelectForm {
fn from(index: usize) -> Self { Self { index } }
}
impl FromLua for SelectForm {
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> { Err("unsupported".into_lua_err()) }
}
impl IntoLua for SelectForm {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -132,6 +132,7 @@ pub enum Spark<'a> {
// Pick // Pick
PickArrow(crate::ArrowForm), PickArrow(crate::ArrowForm),
PickClose(crate::pick::CloseForm), PickClose(crate::pick::CloseForm),
PickSelect(crate::pick::SelectForm),
PickShow(crate::pick::ShowForm), PickShow(crate::pick::ShowForm),
// Spot // Spot
@ -316,6 +317,7 @@ impl<'a> IntoLua for Spark<'a> {
// Pick // Pick
Self::PickArrow(b) => b.into_lua(lua), Self::PickArrow(b) => b.into_lua(lua),
Self::PickClose(b) => b.into_lua(lua), Self::PickClose(b) => b.into_lua(lua),
Self::PickSelect(b) => b.into_lua(lua),
Self::PickShow(b) => b.into_lua(lua), Self::PickShow(b) => b.into_lua(lua),
// Spot // Spot
@ -432,6 +434,7 @@ try_from_spark!(crate::mgr::YankForm, mgr:yank);
try_from_spark!(crate::notify::PushForm, notify:push); try_from_spark!(crate::notify::PushForm, notify:push);
try_from_spark!(crate::notify::TickForm, notify:tick); try_from_spark!(crate::notify::TickForm, notify:tick);
try_from_spark!(crate::pick::CloseForm, pick:close); try_from_spark!(crate::pick::CloseForm, pick:close);
try_from_spark!(crate::pick::SelectForm, pick: select);
try_from_spark!(crate::pick::ShowForm, pick:show); try_from_spark!(crate::pick::ShowForm, pick:show);
try_from_spark!(crate::spot::CopyForm, spot:copy); try_from_spark!(crate::spot::CopyForm, spot:copy);
try_from_spark!(crate::tasks::ProcessOpenForm, tasks:process_open); try_from_spark!(crate::tasks::ProcessOpenForm, tasks:process_open);