mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat!: custom tab name (#3666)
This commit is contained in:
parent
dc66f79cef
commit
0aeeb3b0f7
16 changed files with 148 additions and 23 deletions
|
|
@ -16,12 +16,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|||
|
||||
- Allow using `ps.sub()` in `init.lua` directly without a plugin ([#3638])
|
||||
- New `relay-notify-push` DDS event to allow custom notification handlers ([#3642])
|
||||
- Custom tab name ([#3666])
|
||||
- New `cx.which` API to access the which component state ([#3617])
|
||||
- New `ind-which-activate` DDS event to change the which component behavior ([#3608])
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade Lua to 5.5 ([#3633])
|
||||
- Change preset <kbd>t</kbd> for creating tabs to <kbd>t</kbd> ⇒ <kbd>t</kbd> to avoid conflict with new <kbd>t</kbd> ⇒ <kbd>r</kbd> for renaming tabs ([#3666])
|
||||
- Remove `micro_workers` and `macro_workers` in favor of finer control over concurrent workers ([#3661])
|
||||
|
||||
### Fixed
|
||||
|
|
@ -1642,3 +1644,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|||
[#3642]: https://github.com/sxyazi/yazi/pull/3642
|
||||
[#3648]: https://github.com/sxyazi/yazi/pull/3648
|
||||
[#3661]: https://github.com/sxyazi/yazi/pull/3661
|
||||
[#3666]: https://github.com/sxyazi/yazi/pull/3666
|
||||
|
|
|
|||
4
Cargo.lock
generated
4
Cargo.lock
generated
|
|
@ -2404,9 +2404,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
|||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "memmem"
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@ use super::{Lives, PtrCell};
|
|||
pub(super) struct Preference {
|
||||
inner: PtrCell<yazi_core::tab::Preference>,
|
||||
|
||||
v_sort_by: Option<Value>,
|
||||
v_name: Option<Value>,
|
||||
v_linemode: Option<Value>,
|
||||
|
||||
v_sort_by: Option<Value>,
|
||||
}
|
||||
|
||||
impl Deref for Preference {
|
||||
|
|
@ -20,19 +22,29 @@ impl Deref for Preference {
|
|||
|
||||
impl Preference {
|
||||
pub(super) fn make(inner: &yazi_core::tab::Preference) -> mlua::Result<AnyUserData> {
|
||||
Lives::scoped_userdata(Self { inner: inner.into(), v_sort_by: None, v_linemode: None })
|
||||
Lives::scoped_userdata(Self {
|
||||
inner: inner.into(),
|
||||
|
||||
v_name: None,
|
||||
v_linemode: None,
|
||||
|
||||
v_sort_by: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Preference {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
// Display
|
||||
cached_field!(fields, name, |lua, me| lua.create_string(&me.name));
|
||||
cached_field!(fields, linemode, |lua, me| lua.create_string(&me.linemode));
|
||||
fields.add_field_method_get("show_hidden", |_, me| Ok(me.show_hidden));
|
||||
|
||||
// Sorting
|
||||
cached_field!(fields, sort_by, |_, me| Ok(me.sort_by.to_string()));
|
||||
fields.add_field_method_get("sort_sensitive", |_, me| Ok(me.sort_sensitive));
|
||||
fields.add_field_method_get("sort_reverse", |_, me| Ok(me.sort_reverse));
|
||||
fields.add_field_method_get("sort_dir_first", |_, me| Ok(me.sort_dir_first));
|
||||
fields.add_field_method_get("sort_translit", |_, me| Ok(me.sort_translit));
|
||||
|
||||
cached_field!(fields, linemode, |lua, me| lua.create_string(&me.linemode));
|
||||
fields.add_field_method_get("show_hidden", |_, me| Ok(me.show_hidden));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use std::ops::Deref;
|
||||
use std::{borrow::Cow, ops::Deref};
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods, Value};
|
||||
use yazi_binding::{Id, UrlRef, cached_field};
|
||||
use yazi_shared::url::UrlLike;
|
||||
|
||||
use super::{Finder, Folder, Lives, Mode, Preference, Preview, PtrCell, Selected};
|
||||
|
||||
|
|
@ -46,8 +45,10 @@ impl UserData for Tab {
|
|||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
cached_field!(fields, name, |lua, me| {
|
||||
let url = &me.current.url;
|
||||
lua.create_string(url.name().map_or_else(|| url.loc().encoded_bytes(), |n| n.encoded_bytes()))
|
||||
match me.name() {
|
||||
Cow::Borrowed(s) => lua.create_string(s),
|
||||
Cow::Owned(s) => lua.create_external_string(s),
|
||||
}
|
||||
});
|
||||
|
||||
cached_field!(fields, mode, |_, me| Mode::make(&me.mode));
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ yazi_macro::mod_flat!(
|
|||
suspend
|
||||
tab_close
|
||||
tab_create
|
||||
tab_rename
|
||||
tab_swap
|
||||
tab_switch
|
||||
toggle
|
||||
|
|
|
|||
38
yazi-actor/src/mgr/tab_rename.rs
Normal file
38
yazi-actor/src/mgr/tab_rename.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_macro::{render, succ};
|
||||
use yazi_parser::mgr::TabRenameOpt;
|
||||
use yazi_proxy::{InputProxy, MgrProxy};
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct TabRename;
|
||||
|
||||
impl Actor for TabRename {
|
||||
type Options = TabRenameOpt;
|
||||
|
||||
const NAME: &str = "tab_rename";
|
||||
|
||||
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
|
||||
let tab = cx.tab().id;
|
||||
let pref = &mut cx.tab_mut().pref;
|
||||
|
||||
if !opt.interactive {
|
||||
pref.name = opt.name.unwrap_or_default().into_owned();
|
||||
succ!(render!());
|
||||
}
|
||||
|
||||
let mut input = InputProxy::show(
|
||||
InputCfg::tab_rename().with_value(opt.name.unwrap_or(Cow::Borrowed(&pref.name))),
|
||||
);
|
||||
tokio::spawn(async move {
|
||||
if let Some(Ok(name)) = input.recv().await {
|
||||
MgrProxy::tab_rename(tab, name);
|
||||
}
|
||||
});
|
||||
succ!();
|
||||
}
|
||||
}
|
||||
|
|
@ -131,7 +131,8 @@ keymap = [
|
|||
{ on = [ "g", "f" ], run = "follow", desc = "Follow hovered symlink" },
|
||||
|
||||
# Tabs
|
||||
{ on = "t", run = "tab_create --current", desc = "Create a new tab with CWD" },
|
||||
{ on = [ "t", "t" ], run = "tab_create --current", desc = "Create a new tab in CWD" },
|
||||
{ on = [ "t", "r" ], run = "tab_rename --interactive", desc = "Rename current tab" },
|
||||
|
||||
{ on = "1", run = "tab_switch 0", desc = "Switch to first tab" },
|
||||
{ on = "2", run = "tab_switch 1", desc = "Switch to second tab" },
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use ratatui::{text::{Line, Text}, widgets::{Paragraph, Wrap}};
|
|||
use yazi_shared::{scheme::Encode as EncodeScheme, strand::ToStrand, url::{Url, UrlBuf}};
|
||||
|
||||
use super::{Offset, Position};
|
||||
use crate::YAZI;
|
||||
use crate::{YAZI, popup::Origin};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct InputCfg {
|
||||
|
|
@ -91,6 +91,19 @@ impl InputCfg {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn tab_rename() -> Self {
|
||||
Self {
|
||||
title: "Rename tab:".to_owned(),
|
||||
position: Position::new(Origin::TopCenter, Offset {
|
||||
x: 0,
|
||||
y: 2,
|
||||
width: 50,
|
||||
height: 3,
|
||||
}),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_value(mut self, value: impl Into<String>) -> Self {
|
||||
self.value = value.into();
|
||||
|
|
|
|||
|
|
@ -3,31 +3,33 @@ use yazi_fs::{FilesSorter, SortBy};
|
|||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Preference {
|
||||
// Display
|
||||
pub name: String,
|
||||
pub linemode: String,
|
||||
pub show_hidden: bool,
|
||||
|
||||
// Sorting
|
||||
pub sort_by: SortBy,
|
||||
pub sort_sensitive: bool,
|
||||
pub sort_reverse: bool,
|
||||
pub sort_dir_first: bool,
|
||||
pub sort_translit: bool,
|
||||
|
||||
// Display
|
||||
pub linemode: String,
|
||||
pub show_hidden: bool,
|
||||
}
|
||||
|
||||
impl Default for Preference {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// Display
|
||||
name: String::new(),
|
||||
linemode: YAZI.mgr.linemode.clone(),
|
||||
show_hidden: YAZI.mgr.show_hidden.get(),
|
||||
|
||||
// Sorting
|
||||
sort_by: YAZI.mgr.sort_by.get(),
|
||||
sort_sensitive: YAZI.mgr.sort_sensitive.get(),
|
||||
sort_reverse: YAZI.mgr.sort_reverse.get(),
|
||||
sort_dir_first: YAZI.mgr.sort_dir_first.get(),
|
||||
sort_translit: YAZI.mgr.sort_translit.get(),
|
||||
|
||||
// Display
|
||||
linemode: YAZI.mgr.linemode.clone(),
|
||||
show_hidden: YAZI.mgr.show_hidden.get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::Result;
|
||||
use ratatui::layout::Rect;
|
||||
use tokio::task::JoinHandle;
|
||||
use yazi_config::{LAYOUT, popup::{Origin, Position}};
|
||||
use yazi_emulator::Dimension;
|
||||
use yazi_fs::File;
|
||||
use yazi_shared::{Id, Ids, url::UrlBuf};
|
||||
use yazi_shared::{Id, Ids, url::{UrlBuf, UrlLike}};
|
||||
|
||||
use super::{Backstack, Finder, Folder, History, Mode, Preference, Preview};
|
||||
use crate::{spot::Spot, tab::Selected};
|
||||
|
|
@ -61,6 +63,17 @@ impl Tab {
|
|||
#[inline]
|
||||
pub fn cwd(&self) -> &UrlBuf { &self.current.url }
|
||||
|
||||
pub fn name(&self) -> Cow<'_, str> {
|
||||
let url = &self.current.url;
|
||||
if !self.pref.name.is_empty() {
|
||||
Cow::Borrowed(&self.pref.name)
|
||||
} else if let Some(s) = url.name() {
|
||||
s.to_string_lossy()
|
||||
} else {
|
||||
url.loc().to_string_lossy()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hovered(&self) -> Option<&File> { self.current.hovered() }
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ pub enum Spark<'a> {
|
|||
Suspend(yazi_parser::VoidOpt),
|
||||
TabClose(yazi_parser::mgr::TabCloseOpt),
|
||||
TabCreate(yazi_parser::mgr::TabCreateOpt),
|
||||
TabRename(yazi_parser::mgr::TabRenameOpt),
|
||||
TabSwap(yazi_parser::ArrowOpt),
|
||||
TabSwitch(yazi_parser::mgr::TabSwitchOpt),
|
||||
Toggle(yazi_parser::mgr::ToggleOpt),
|
||||
|
|
@ -245,6 +246,7 @@ impl<'a> IntoLua for Spark<'a> {
|
|||
Self::Suspend(b) => b.into_lua(lua),
|
||||
Self::TabClose(b) => b.into_lua(lua),
|
||||
Self::TabCreate(b) => b.into_lua(lua),
|
||||
Self::TabRename(b) => b.into_lua(lua),
|
||||
Self::TabSwap(b) => b.into_lua(lua),
|
||||
Self::TabSwitch(b) => b.into_lua(lua),
|
||||
Self::Toggle(b) => b.into_lua(lua),
|
||||
|
|
@ -396,6 +398,7 @@ try_from_spark!(yazi_parser::mgr::SpotOpt, mgr:spot);
|
|||
try_from_spark!(yazi_parser::mgr::StashOpt, mgr:stash);
|
||||
try_from_spark!(yazi_parser::mgr::TabCloseOpt, mgr:tab_close);
|
||||
try_from_spark!(yazi_parser::mgr::TabCreateOpt, mgr:tab_create);
|
||||
try_from_spark!(yazi_parser::mgr::TabRenameOpt, mgr:tab_rename);
|
||||
try_from_spark!(yazi_parser::mgr::TabSwitchOpt, mgr:tab_switch);
|
||||
try_from_spark!(yazi_parser::mgr::ToggleAllOpt, mgr:toggle_all);
|
||||
try_from_spark!(yazi_parser::mgr::ToggleOpt, mgr:toggle);
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ impl<'a> Executor<'a> {
|
|||
|
||||
// Tabs
|
||||
on!(tab_create);
|
||||
on!(tab_rename);
|
||||
on!(tab_close);
|
||||
on!(tab_switch);
|
||||
on!(tab_swap);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ yazi_macro::mod_flat!(
|
|||
stash
|
||||
tab_close
|
||||
tab_create
|
||||
tab_rename
|
||||
tab_switch
|
||||
toggle
|
||||
toggle_all
|
||||
|
|
|
|||
32
yazi-parser/src/mgr/tab_rename.rs
Normal file
32
yazi-parser/src/mgr/tab_rename.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use anyhow::bail;
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
use yazi_shared::{SStr, event::CmdCow};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TabRenameOpt {
|
||||
pub name: Option<SStr>,
|
||||
pub interactive: bool,
|
||||
}
|
||||
|
||||
impl TryFrom<CmdCow> for TabRenameOpt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
|
||||
let name = c.take_first().ok();
|
||||
let interactive = c.bool("interactive");
|
||||
|
||||
if name.is_none() && !interactive {
|
||||
bail!("either name or interactive must be specified in TabRenameOpt");
|
||||
}
|
||||
|
||||
Ok(Self { name, interactive })
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for TabRenameOpt {
|
||||
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> { Err("unsupported".into_lua_err()) }
|
||||
}
|
||||
|
||||
impl IntoLua for TabRenameOpt {
|
||||
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
|
||||
}
|
||||
|
|
@ -54,6 +54,10 @@ impl MgrProxy {
|
|||
));
|
||||
}
|
||||
|
||||
pub fn tab_rename(tab: Id, name: impl Into<SStr>) {
|
||||
emit!(Call(relay!(mgr:tab_rename, [name.into()]).with("tab", tab)));
|
||||
}
|
||||
|
||||
pub fn update_paged_by(page: usize, only_if: &UrlBuf) {
|
||||
emit!(Call(relay!(mgr:update_paged, [page]).with("only-if", only_if)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ dyn-clone = { workspace = true }
|
|||
foldhash = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
memchr = "2.7.6"
|
||||
memchr = "2.8.0"
|
||||
ordered-float = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
percent-encoding = { workspace = true }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue