aboutsummaryrefslogtreecommitdiffstats
path: root/default-plugins
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2026-03-20 17:28:36 +0100
committerGitHub <noreply@github.com>2026-03-20 17:28:36 +0100
commit4ba41c085ab9207ed31e72a1ba331bff2bebed99 (patch)
treeaf832d3e2b1c4577525f0276bda83fc9a12612b3 /default-plugins
parentadjust badges location in readme (diff)
downloadsl0ppij-4ba41c085ab9207ed31e72a1ba331bff2bebed99.tar.gz
sl0ppij-4ba41c085ab9207ed31e72a1ba331bff2bebed99.tar.xz
sl0ppij-4ba41c085ab9207ed31e72a1ba331bff2bebed99.zip
Release notes and fixes (#4879)
* release notes * fix some link issues * rustfmt * fix click wording
Diffstat (limited to 'default-plugins')
-rw-r--r--default-plugins/about/src/active_component.rs17
-rw-r--r--default-plugins/about/src/pages.rs380
-rw-r--r--default-plugins/link/src/main.rs15
3 files changed, 298 insertions, 114 deletions
diff --git a/default-plugins/about/src/active_component.rs b/default-plugins/about/src/active_component.rs
index 6e6c716a..7041ca5a 100644
--- a/default-plugins/about/src/active_component.rs
+++ b/default-plugins/about/src/active_component.rs
@@ -55,6 +55,16 @@ impl ActiveComponent {
run_command(&[&executable.borrow(), &link], Default::default());
None
},
+ Some(ClickAction::LaunchPlugin(plugin_url)) => {
+ open_plugin_pane_floating(
+ &plugin_url,
+ Default::default(),
+ None,
+ Default::default(),
+ );
+ self.left_click_action = Some(ClickAction::LaunchPlugin(plugin_url));
+ None
+ },
None => None,
}
}
@@ -125,6 +135,7 @@ impl ComponentCoordinates {
pub enum ClickAction {
ChangePage(Box<dyn FnOnce() -> Page>),
OpenLink(String, Rc<RefCell<String>>), // (destination, executable)
+ LaunchPlugin(String), // plugin URL (e.g. "zellij:share")
}
impl std::fmt::Debug for ClickAction {
@@ -134,6 +145,9 @@ impl std::fmt::Debug for ClickAction {
ClickAction::OpenLink(destination, executable) => {
write!(f, "OpenLink: {}, {:?}", destination, executable)
},
+ ClickAction::LaunchPlugin(url) => {
+ write!(f, "LaunchPlugin: {}", url)
+ },
}
}
}
@@ -148,4 +162,7 @@ impl ClickAction {
pub fn new_open_link(destination: String, executable: Rc<RefCell<String>>) -> Self {
ClickAction::OpenLink(destination, executable)
}
+ pub fn new_launch_plugin(plugin_url: String) -> Self {
+ ClickAction::LaunchPlugin(plugin_url)
+ }
}
diff --git a/default-plugins/about/src/pages.rs b/default-plugins/about/src/pages.rs
index a1107da3..849e7c26 100644
--- a/default-plugins/about/src/pages.rs
+++ b/default-plugins/about/src/pages.rs
@@ -27,51 +27,70 @@ impl Page {
.with_title(main_screen_title(zellij_version.clone(), is_release_notes))
.with_bulletin_list(BulletinList::new(whats_new_title()).with_items(vec![
ActiveComponent::new(TextOrCustomRender::Text(main_menu_item(
- "Web Client",
+ "Windows Support",
)))
.with_hover(TextOrCustomRender::Text(
- main_menu_item("Web Client").selected(),
+ main_menu_item("Windows Support").selected(),
+ ))
+ .with_left_click_action(ClickAction::new_change_page({
+ move || Page::new_windows_support()
+ })),
+ ActiveComponent::new(TextOrCustomRender::Text(main_menu_item(
+ "Remote Sessions",
+ )))
+ .with_hover(TextOrCustomRender::Text(
+ main_menu_item("Remote Sessions").selected(),
))
.with_left_click_action(ClickAction::new_change_page({
let link_executable = link_executable.clone();
- move || Page::new_web_client(link_executable.clone())
+ move || Page::new_remote_sessions(link_executable.clone())
})),
ActiveComponent::new(TextOrCustomRender::Text(main_menu_item(
- "Multiple Pane Select",
+ "Read-Only Session Sharing",
)))
.with_hover(TextOrCustomRender::Text(
- main_menu_item("Multiple Pane Select").selected(),
+ main_menu_item("Read-Only Session Sharing").selected(),
))
- .with_left_click_action(ClickAction::new_change_page(move || {
- Page::new_multiple_select()
+ .with_left_click_action(ClickAction::new_change_page({
+ let link_executable = link_executable.clone();
+ move || Page::new_read_only_sharing(link_executable.clone())
})),
ActiveComponent::new(TextOrCustomRender::Text(main_menu_item(
- "Key Tooltips for the compact-bar",
+ "CLI Automation",
)))
.with_hover(TextOrCustomRender::Text(
- main_menu_item("Key Tooltips for the compact-bar").selected(),
+ main_menu_item("CLI Automation").selected(),
))
.with_left_click_action(ClickAction::new_change_page({
let link_executable = link_executable.clone();
- move || Page::new_key_tooltips_for_compact_bar(link_executable.clone())
+ move || Page::new_cli_automation(link_executable.clone())
})),
ActiveComponent::new(TextOrCustomRender::Text(main_menu_item(
- "Stack Keybinding",
+ "Mouse Resize",
)))
.with_hover(TextOrCustomRender::Text(
- main_menu_item("Stack Keybinding").selected(),
+ main_menu_item("Mouse Resize").selected(),
))
.with_left_click_action(ClickAction::new_change_page(move || {
- Page::new_stack_keybinding()
+ Page::new_mouse_resize()
})),
ActiveComponent::new(TextOrCustomRender::Text(main_menu_item(
- "Performance Improvements",
+ "Click-to-Open File Paths",
)))
.with_hover(TextOrCustomRender::Text(
- main_menu_item("Performance Improvements").selected(),
+ main_menu_item("Click-to-Open File Paths").selected(),
))
.with_left_click_action(ClickAction::new_change_page({
- move || Page::new_performance_improvements()
+ move || Page::new_click_to_open()
+ })),
+ ActiveComponent::new(TextOrCustomRender::Text(main_menu_item(
+ "Layout Manager",
+ )))
+ .with_hover(TextOrCustomRender::Text(
+ main_menu_item("Layout Manager").selected(),
+ ))
+ .with_left_click_action(ClickAction::new_change_page({
+ move || Page::new_layout_manager()
})),
]))
.with_paragraph(vec![ComponentLine::new(vec![
@@ -113,110 +132,183 @@ impl Page {
})
})
}
- pub fn new_web_client(link_executable: Rc<RefCell<String>>) -> Page {
+ fn new_windows_support() -> Page {
Page::new()
- .with_title(Text::new("Web Client").color_range(0, ..))
+ .with_title(Text::new("Windows Support").color_range(0, ..))
.with_paragraph(vec![
- ComponentLine::new(vec![
- // ActiveComponent::new(TextOrCustomRender::Text(Text::new("This version includes a new resizing algorithm that helps better manage panes"))),
- ActiveComponent::new(TextOrCustomRender::Text(Text::new("This version includes a web client, allowing you to share sessions in the browser."))),
- ]),
- ])
- .with_bulletin_list(BulletinList::new(Text::new("The web client:").color_range(2, ..))
- .with_items(vec![
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("Allows you to bookmark sessions")
- .color_substring(3, "bookmark sessions")
- )),
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("Includes built-in authentication")
- )),
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("Can be used as a daily-driver, making your terminal emulator optional")
- )),
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("Is completely opt-in")
- )),
- ])
- )
- .with_paragraph(vec![
- ComponentLine::new(vec![
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("For more details, see: ")
- .color_range(2, ..)
- )),
- ActiveComponent::new(TextOrCustomRender::Text(Text::new("https://zellij.dev/tutorials/web-client")))
- .with_hover(TextOrCustomRender::CustomRender(Box::new(web_client_screencast_link_selected), Box::new(web_client_screencast_link_selected_len)))
- .with_left_click_action(ClickAction::new_open_link("https://zellij.dev/tutorials/web-client".to_owned(), link_executable.clone()))
- ])
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Zellij now runs natively on Windows."),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Windows users can now enjoy the same workspace management, plugin ecosystem"),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("and multiplayer capabilities that have been available on Linux and macOS."),
+ ))]),
])
- .with_help(Box::new(|hovering_over_link, menu_item_is_selected| esc_go_back_plus_link_hover(hovering_over_link, menu_item_is_selected)))
+ .with_help(Box::new(|_hovering_over_link, _menu_item_is_selected| {
+ esc_to_go_back_help()
+ }))
}
- fn new_multiple_select() -> Page {
+ pub fn new_remote_sessions(link_executable: Rc<RefCell<String>>) -> Page {
Page::new()
- .with_title(Text::new("Multiple Pane Select").color_range(0, ..))
+ .with_title(Text::new("Remote Sessions").color_range(0, ..))
.with_paragraph(vec![
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("This version adds the ability to perform bulk operations on panes"),
+ Text::new("Attach to remote Zellij sessions over HTTPS, directly from the terminal."),
))]),
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("eg. close, make floating, break to a new tab, etc."),
+ Text::new("The remote session needs to be running the Zellij web client."),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Zellij will attach to it exactly as a browser would, through the same interface."),
))]),
])
.with_bulletin_list(
- BulletinList::new(
- Text::new(format!("To select multiple panes: ")).color_range(2, ..),
- )
- .with_items(vec![
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new(format!("Alt <left-click> them"))
- .color_substring(3, "Alt <left-click>"),
- )),
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new(format!("Toggle with Alt p")).color_substring(3, "Alt p"),
- )),
- ]),
+ BulletinList::new(Text::new("Try it:").color_range(2, ..))
+ .with_items(vec![
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Run the Zellij web server on one machine")
+ .color_substring(3, "Zellij web server"),
+ ))
+ .with_hover(TextOrCustomRender::Text(
+ Text::new("Run the Zellij web server on one machine")
+ .color_substring(3, "Zellij web server")
+ .selected(),
+ ))
+ .with_left_click_action(ClickAction::new_launch_plugin(
+ "zellij:share".to_owned(),
+ )),
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("From another: zellij attach https://<ip>/<session-name>")
+ .color_substring(3, "zellij attach")
+ .color_substring(2, "https://<ip>/<session-name>"),
+ )),
+ ]),
)
+ .with_paragraph(vec![ComponentLine::new(vec![
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Learn more about the web client: ").color_range(2, ..),
+ )),
+ ActiveComponent::new(TextOrCustomRender::Text(Text::new(
+ "https://zellij.dev/tutorials/web-client/",
+ )))
+ .with_hover(TextOrCustomRender::CustomRender(
+ Box::new(web_client_link_selected),
+ Box::new(web_client_link_selected_len),
+ ))
+ .with_left_click_action(ClickAction::new_open_link(
+ "https://zellij.dev/tutorials/web-client/".to_owned(),
+ link_executable.clone(),
+ )),
+ ])])
+ .with_help(Box::new(|hovering_over_link, menu_item_is_selected| {
+ esc_go_back_plus_link_hover(hovering_over_link, menu_item_is_selected)
+ }))
+ }
+ fn new_read_only_sharing(link_executable: Rc<RefCell<String>>) -> Page {
+ Page::new()
+ .with_title(Text::new("Read-Only Session Sharing").color_range(0, ..))
.with_paragraph(vec![
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("To disable this behavior (and the associated hover effects)"),
+ Text::new("Sessions can now be shared in read-only mode."),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new(
+ "Useful for demonstrations, teaching, monitoring and pair programming",
+ )
+ .color_substring(2, "demonstrations")
+ .color_substring(2, "teaching")
+ .color_substring(2, "monitoring")
+ .color_substring(2, "pair programming"),
))]),
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new(format!("add advanced_mouse_actions false to the config."))
- .color_substring(3, "advanced_mouse_actions false"),
+ Text::new("where one participant should observe without interfering."),
))]),
])
- .with_help(Box::new(|_hovering_over_link, _menu_item_is_selected| {
- esc_to_go_back_help()
+ .with_paragraph(vec![
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Create a read-only web token with:")
+ .color_substring(2, "read-only web token"),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("zellij web --create-read-only-token").color_range(3, ..),
+ ))]),
+ ])
+ .with_paragraph(vec![ComponentLine::new(vec![ActiveComponent::new(
+ TextOrCustomRender::Text(Text::new(
+ "Share the token for view-only access without risk of unintended input.",
+ )),
+ )])])
+ .with_paragraph(vec![ComponentLine::new(vec![
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Learn more: ").color_range(2, ..),
+ )),
+ ActiveComponent::new(TextOrCustomRender::Text(Text::new(
+ "https://zellij.dev/tutorials/web-client/",
+ )))
+ .with_hover(TextOrCustomRender::CustomRender(
+ Box::new(web_client_link_selected),
+ Box::new(web_client_link_selected_len),
+ ))
+ .with_left_click_action(ClickAction::new_open_link(
+ "https://zellij.dev/tutorials/web-client/".to_owned(),
+ link_executable.clone(),
+ )),
+ ])])
+ .with_help(Box::new(|hovering_over_link, menu_item_is_selected| {
+ esc_go_back_plus_link_hover(hovering_over_link, menu_item_is_selected)
}))
}
- fn new_key_tooltips_for_compact_bar(link_executable: Rc<RefCell<String>>) -> Page {
+ fn new_cli_automation(link_executable: Rc<RefCell<String>>) -> Page {
Page::new()
- .with_title(Text::new("Key Tooltips for the compact-bar").color_range(0, ..))
+ .with_title(Text::new("CLI Automation").color_range(0, ..))
.with_paragraph(vec![
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new(
- "Starting this version, it's possible to add toggle-able key tooltips",
- )
- .color_range(3, 37..=58),
+ Text::new("This release significantly expands the CLI's control surface,"),
))]),
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("when using the compact-bar.").color_substring(3, "compact-bar"),
+ Text::new("enabling the building of powerful workspace automations."),
))]),
])
+ .with_bulletin_list(
+ BulletinList::new(Text::new("New and expanded capabilities:").color_range(2, ..))
+ .with_items(vec![
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("list-panes, list-tabs, dump-screen, dump-layout with --json output")
+ .color_substring(3, "list-panes")
+ .color_substring(3, "list-tabs")
+ .color_substring(3, "dump-screen")
+ .color_substring(3, "dump-layout")
+ .color_substring(3, "--json"),
+ )),
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("zellij run optionally blocks until success/failure")
+ .color_substring(3, "zellij run"),
+ )),
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("zellij subscribe can stream pane scrollback in real time")
+ .color_substring(3, "zellij subscribe"),
+ )),
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("zellij send-keys/paste can send human readable keys to other panes or sessions")
+ .color_substring(3, "zellij send-keys/paste"),
+ )),
+ ]),
+ )
.with_paragraph(vec![ComponentLine::new(vec![
ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("For more information: ").color_range(2, ..),
+ Text::new("Learn more: ").color_range(2, ..),
)),
ActiveComponent::new(TextOrCustomRender::Text(Text::new(
- "https://zellij.dev/documentation/faq.html",
+ "https://zellij.dev/documentation/controlling-zellij-through-cli.html",
)))
.with_hover(TextOrCustomRender::CustomRender(
- Box::new(compact_bar_link_selected),
- Box::new(compact_bar_link_selected_len),
+ Box::new(cli_automation_link_selected),
+ Box::new(cli_automation_link_selected_len),
))
.with_left_click_action(ClickAction::new_open_link(
- "https://zellij.dev/documentation/faq.html".to_owned(),
+ "https://zellij.dev/documentation/controlling-zellij-through-cli.html".to_owned(),
link_executable.clone(),
)),
])])
@@ -224,44 +316,107 @@ impl Page {
esc_go_back_plus_link_hover(hovering_over_link, menu_item_is_selected)
}))
}
- fn new_stack_keybinding() -> Page {
+ fn new_mouse_resize() -> Page {
Page::new()
- .with_title(Text::new("New Stack Keybinding").color_range(0, ..))
+ .with_title(Text::new("Mouse Resize").color_range(0, ..))
.with_paragraph(vec![
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("It's now possible to open a stacked pane directly on top of the current pane").color_substring(2, "stacked pane"),
+ Text::new("Panes can now be resized by dragging their borders with the mouse."),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Tiled panes can be resized with or without Ctrl held down.")
+ .color_substring(3, "Ctrl"),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Floating panes require Ctrl+drag to resize.")
+ .color_substring(3, "Ctrl+drag"),
))]),
])
+ .with_paragraph(vec![ComponentLine::new(vec![ActiveComponent::new(
+ TextOrCustomRender::Text(
+ Text::new("Try it: Ctrl+drag on the borders of this pane.")
+ .color_substring(2, "Try it:")
+ .color_substring(3, "Ctrl+drag"),
+ ),
+ )])])
+ .with_help(Box::new(|_hovering_over_link, _menu_item_is_selected| {
+ esc_to_go_back_help()
+ }))
+ }
+ fn new_click_to_open() -> Page {
+ Page::new()
+ .with_title(Text::new("Click-to-Open File Paths").color_range(0, ..))
.with_paragraph(vec![
- ComponentLine::new(vec![
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("By default: Ctrl p + s").color_substring(3, "Ctrl p").color_substring(3, " s"),
- )),
- ]),
- ComponentLine::new(vec![
- ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("In unlock first: Ctrl g + p + s").color_substring(3, "Ctrl g").color_substring(3, " p").color_substring(3, " s"),
- )),
- ]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Zellij now detects file paths in the terminal viewport."),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Alt-Click on a file path to open it.")
+ .color_substring(3, "Alt-Click"),
+ ))]),
+ ])
+ .with_paragraph(vec![
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("Useful for navigating compiler errors, grep results,")
+ .color_substring(2, "compiler errors")
+ .color_substring(2, "grep results"),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("log files, or any output containing file paths.")
+ .color_substring(2, "log files"),
+ ))]),
])
.with_paragraph(vec![
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("To add to an existing config, see the release notes.")
+ Text::new("Plugins can also highlight arbitrary text in the viewport,"),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("opening possibilities for custom link handlers")
+ .color_substring(3, "custom link handlers"),
+ ))]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("and interactive overlays.")
+ .color_substring(3, "interactive overlays"),
))]),
])
.with_help(Box::new(|_hovering_over_link, _menu_item_is_selected| {
esc_to_go_back_help()
}))
}
- fn new_performance_improvements() -> Page {
+ fn new_layout_manager() -> Page {
Page::new()
- .with_title(Text::new("Performance Improvements").color_range(0, ..))
+ .with_title(Text::new("Layout Manager").color_range(0, ..))
+ .with_paragraph(vec![
+ ComponentLine::new(vec![
+ ActiveComponent::new(TextOrCustomRender::Text(Text::new("A new "))),
+ ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new("layout-manager interface").color_range(3, ..),
+ ))
+ .with_hover(TextOrCustomRender::Text(
+ Text::new("layout-manager interface")
+ .color_range(3, ..)
+ .selected(),
+ ))
+ .with_left_click_action(ClickAction::new_launch_plugin(
+ "zellij:layout-manager".to_owned(),
+ )),
+ ActiveComponent::new(TextOrCustomRender::Text(Text::new(
+ " allows overriding layouts at runtime.",
+ ))),
+ ]),
+ ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
+ Text::new(
+ "Workspaces can be reconfigured dynamically without restarting sessions.",
+ ),
+ ))]),
+ ])
.with_paragraph(vec![
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("This version adds a debounced asynchronous render mechanism"),
+ Text::new("Access it through the session menu, or run:")
+ .color_substring(2, "session menu"),
))]),
ComponentLine::new(vec![ActiveComponent::new(TextOrCustomRender::Text(
- Text::new("making rendering much smoother across the whole application."),
+ Text::new("zellij plugin -- zellij:layout-manager").color_range(3, ..),
))]),
])
.with_help(Box::new(|_hovering_over_link, _menu_item_is_selected| {
@@ -597,29 +752,30 @@ fn sponsors_link_text_selected_len() -> usize {
34
}
-fn web_client_screencast_link_selected(x: usize, y: usize) -> usize {
+fn cli_automation_link_selected(x: usize, y: usize) -> usize {
print!(
- "\u{1b}[{};{}H\u{1b}[m\u{1b}[1;4mhttps://zellij.dev/tutorials/web-client",
+ "\u{1b}[{};{}H\u{1b}[m\u{1b}[1;4mhttps://zellij.dev/documentation/controlling-zellij-through-cli.html",
y + 1,
x + 1
);
- 39
+ 68
}
-fn web_client_screencast_link_selected_len() -> usize {
- 39
+fn cli_automation_link_selected_len() -> usize {
+ 68
}
-fn compact_bar_link_selected(x: usize, y: usize) -> usize {
+fn web_client_link_selected(x: usize, y: usize) -> usize {
print!(
- "\u{1b}[{};{}H\u{1b}[m\u{1b}[1;4mhttps://zellij.dev/documentation/faq.html",
+ "\u{1b}[{};{}H\u{1b}[m\u{1b}[1;4mhttps://zellij.dev/tutorials/web-client/",
y + 1,
x + 1
);
- 41
+ 40
}
-fn compact_bar_link_selected_len() -> usize {
- 41
+
+fn web_client_link_selected_len() -> usize {
+ 40
}
// Text components
diff --git a/default-plugins/link/src/main.rs b/default-plugins/link/src/main.rs
index f2127d44..f27076b5 100644
--- a/default-plugins/link/src/main.rs
+++ b/default-plugins/link/src/main.rs
@@ -2,7 +2,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use std::path::{Path, PathBuf};
use zellij_tile::prelude::*;
-const FILE_PATH_REGEX: &str = r#"(?:(?:\./|\.\./|/)[A-Za-z0-9_./\-+@%,#=~!\$\{\}\[\]]+|~/[A-Za-z0-9_./\-+@%,#=~!\$\{\}\[\]]+|\$\{?[A-Za-z_][A-Za-z0-9_]*\}?/[A-Za-z0-9_./\-+@%,#=~!\$\{\}\[\]]+|[a-zA-Z0-9_][a-zA-Z0-9_.\-]*/[A-Za-z0-9_./\-+@%,#=~!\$\{\}\[\]]+)(?::\d+(?::\d+)?)?"#;
+const FILE_PATH_REGEX: &str = r#"(?:^|\s)((?:(?:\./|\.\./|/)[A-Za-z0-9_./\-+@%,#=~!\$\{\}\[\]]+|~/[A-Za-z0-9_./\-+@%,#=~!\$\{\}\[\]]+|\$\{?[A-Za-z_][A-Za-z0-9_]*\}?/[A-Za-z0-9_./\-+@%,#=~!\$\{\}\[\]]+)(?::\d+(?::\d+)?)?)(?:\s|$)"#;
const CWD_CONTEXT_KEY: &str = "cwd";
@@ -187,7 +187,11 @@ impl State {
// Directory-entry patterns for the pane's current CWD
if let Some(entries) = self.pane_dir_entries.get(&pane_id) {
for entry_name in entries {
- let pattern = regex_escape(entry_name);
+ let path_chars = r#"[A-Za-z0-9_./\-+@%,#=~!\$\{\}\[\]]"#;
+ let pattern = format!(
+ "(?:^|\\s)({}(?:/{path_chars}+)?(?::\\d+(?::\\d+)?)?)(?:\\s|$)",
+ regex_escape(entry_name),
+ );
highlights.push(RegexHighlight {
pattern,
style: HighlightStyle::None,
@@ -222,6 +226,10 @@ impl State {
/// Scan a directory for first-level file and folder names.
/// Returns an empty vec on any error.
+/// Maximum number of directory entries to scan. Directories with more entries
+/// than this are skipped entirely to avoid excessive regex pattern count.
+const MAX_DIR_ENTRIES: usize = 500;
+
fn scan_directory(path: &Path) -> Vec<String> {
let mut entries = Vec::new();
let read_dir = match std::fs::read_dir(path) {
@@ -232,6 +240,9 @@ fn scan_directory(path: &Path) -> Vec<String> {
if let Ok(entry) = entry {
if let Some(name) = entry.file_name().to_str() {
entries.push(name.to_owned());
+ if entries.len() > MAX_DIR_ENTRIES {
+ return Vec::new();
+ }
}
}
}