From 78383de9b29a67c64bc21047caf57559f7061e26 Mon Sep 17 00:00:00 2001 From: dana Date: Sun, 13 Jul 2025 01:50:38 -0500 Subject: [PATCH] complete/zsh: improve --hyperlink-format completion Also don't re-define helper functions if they exist. Closes #3102 --- CHANGELOG.md | 2 + crates/core/flags/complete/rg.zsh | 47 +++++++++++++++- crates/core/flags/complete/zsh.rs | 11 +++- crates/printer/src/hyperlink/aliases.rs | 71 ++++++++++++++++++++----- crates/printer/src/hyperlink/mod.rs | 6 +++ 5 files changed, 121 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65ed698..1bb6e84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,8 @@ Feature enhancements: Globs in ripgrep (and the `globset` crate) now support nested alternates. * [FEATURE #3096](https://github.com/BurntSushi/ripgrep/pull/3096): Improve completions for `--hyperlink-format` in bash and fish. +* [FEATURE #3102](https://github.com/BurntSushi/ripgrep/pull/3102): + Improve completions for `--hyperlink-format` in zsh. 14.1.1 (2024-09-08) diff --git a/crates/core/flags/complete/rg.zsh b/crates/core/flags/complete/rg.zsh index a4b63d2..ae9f119 100644 --- a/crates/core/flags/complete/rg.zsh +++ b/crates/core/flags/complete/rg.zsh @@ -319,7 +319,7 @@ _rg() { '--field-context-separator[set string to delimit fields in context lines]' '--field-match-separator[set string to delimit fields in matching lines]' '--hostname-bin=[executable for getting system hostname]:hostname executable:_command_names -e' - '--hyperlink-format=[specify pattern for hyperlinks]:pattern' + '--hyperlink-format=[specify pattern for hyperlinks]: :_rg_hyperlink_formats' '--trace[show more verbose debug messages]' '--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)' "(1 stats)--files[show each file that would be searched (but don't search)]" @@ -410,6 +410,7 @@ _rg() { } # Complete encodings +(( $+functions[_rg_encodings] )) || _rg_encodings() { local -a expl local -aU _encodings @@ -422,6 +423,7 @@ _rg_encodings() { } # Complete file types +(( $+functions[_rg_types] )) || _rg_types() { local -a expl local -aU _types @@ -435,6 +437,49 @@ _rg_types() { fi } +# Complete hyperlink format-string aliases +(( $+functions[_rg_hyperlink_format_aliases] )) || +_rg_hyperlink_format_aliases() { + _describe -t format-aliases 'hyperlink format alias' '( +!HYPERLINK_ALIASES! + )' +} + +# Complete custom hyperlink format strings +(( $+functions[_rg_hyperlink_format_strings] )) || +_rg_hyperlink_format_strings() { + local op='{' ed='}' + local -a pfx sfx rmv + + compquote op ed + + sfx=( -S $ed ) + rmv=( -r ${(q)ed[1]} ) + + compset -S "$op*" + compset -S "$ed*" && sfx=( -S '' ) + compset -P "*$ed" + compset -p ${#PREFIX%$op*} + compset -P $op || pfx=( -P $op ) + + WSL_DISTRO_NAME=${WSL_DISTRO_NAME:-\$WSL_DISTRO_NAME} \ + _describe -t format-variables 'hyperlink format variable' '( + path:"absolute path to file containing match (required)" + host:"system host name or output of --hostname-bin executable" + line:"line number of match" + column:"column of match (requires {line})" + wslprefix:"\"wsl$/$WSL_DISTRO_NAME\" (for WSL share)" + )' "${(@)pfx}" "${(@)sfx}" "${(@)rmv}" +} + +# Complete hyperlink formats +(( $+functions[_rg_hyperlink_formats] )) || +_rg_hyperlink_formats() { + _alternative \ + 'format-string-aliases: :_rg_hyperlink_format_aliases' \ + 'format-strings: :_rg_hyperlink_format_strings' +} + # Don't run the completion function when being sourced by itself. # # See https://github.com/BurntSushi/ripgrep/issues/2956 diff --git a/crates/core/flags/complete/zsh.rs b/crates/core/flags/complete/zsh.rs index 7475c0c..0aa8b9c 100644 --- a/crates/core/flags/complete/zsh.rs +++ b/crates/core/flags/complete/zsh.rs @@ -19,5 +19,14 @@ long as it meets criteria 3 and 4 above. /// Generate completions for zsh. pub(crate) fn generate() -> String { - include_str!("rg.zsh").replace("!ENCODINGS!", super::ENCODINGS.trim_end()) + let hyperlink_alias_descriptions = grep::printer::hyperlink_aliases() + .iter() + .map(|alias| { + format!(r#" {}:"{}""#, alias.name(), alias.description()) + }) + .collect::>() + .join("\n"); + include_str!("rg.zsh") + .replace("!ENCODINGS!", super::ENCODINGS.trim_end()) + .replace("!HYPERLINK_ALIASES!", &hyperlink_alias_descriptions) } diff --git a/crates/printer/src/hyperlink/aliases.rs b/crates/printer/src/hyperlink/aliases.rs index 5444d8f..faefb20 100644 --- a/crates/printer/src/hyperlink/aliases.rs +++ b/crates/printer/src/hyperlink/aliases.rs @@ -4,41 +4,84 @@ use crate::hyperlink::HyperlinkAlias; /// /// These need to be sorted by name. pub(super) const HYPERLINK_PATTERN_ALIASES: &[HyperlinkAlias] = &[ - #[cfg(not(windows))] - prioritized_alias(0, "default", "file://{host}{path}"), - #[cfg(windows)] - prioritized_alias(0, "default", "file://{path}"), - alias("file", "file://{host}{path}"), + prioritized_alias( + 0, + "default", + "RFC 8089 scheme (file://) (platform-aware)", + { + #[cfg(not(windows))] + { + "file://{host}{path}" + } + #[cfg(windows)] + { + "file://{path}" + } + }, + ), + alias( + "file", + "RFC 8089 scheme (file://) with host", + "file://{host}{path}", + ), // https://github.com/misaki-web/grepp - alias("grep+", "grep+://{path}:{line}"), - alias("kitty", "file://{host}{path}#{line}"), + alias("grep+", "grep+ scheme (grep+://)", "grep+://{path}:{line}"), + alias( + "kitty", + "kitty-style RFC 8089 scheme (file://) with line number", + "file://{host}{path}#{line}", + ), // https://macvim.org/docs/gui_mac.txt.html#mvim%3A%2F%2F alias( "macvim", + "MacVim scheme (mvim://)", "mvim://open?url=file://{path}&line={line}&column={column}", ), - prioritized_alias(1, "none", ""), + prioritized_alias(1, "none", "disable hyperlinks", ""), // https://macromates.com/blog/2007/the-textmate-url-scheme/ alias( "textmate", + "TextMate scheme (txmt://)", "txmt://open?url=file://{path}&line={line}&column={column}", ), // https://code.visualstudio.com/docs/editor/command-line#_opening-vs-code-with-urls - alias("vscode", "vscode://file{path}:{line}:{column}"), - alias("vscode-insiders", "vscode-insiders://file{path}:{line}:{column}"), - alias("vscodium", "vscodium://file{path}:{line}:{column}"), + alias( + "vscode", + "VS Code scheme (vscode://)", + "vscode://file{path}:{line}:{column}", + ), + alias( + "vscode-insiders", + "VS Code Insiders scheme (vscode-insiders://)", + "vscode-insiders://file{path}:{line}:{column}", + ), + alias( + "vscodium", + "VSCodium scheme (vscodium://)", + "vscodium://file{path}:{line}:{column}", + ), ]; /// Creates a [`HyperlinkAlias`]. -const fn alias(name: &'static str, format: &'static str) -> HyperlinkAlias { - HyperlinkAlias { name, format, display_priority: None } +const fn alias( + name: &'static str, + description: &'static str, + format: &'static str, +) -> HyperlinkAlias { + HyperlinkAlias { name, description, format, display_priority: None } } /// Creates a [`HyperlinkAlias`] with a display priority. const fn prioritized_alias( priority: i16, name: &'static str, + description: &'static str, format: &'static str, ) -> HyperlinkAlias { - HyperlinkAlias { name, format, display_priority: Some(priority) } + HyperlinkAlias { + name, + description, + format, + display_priority: Some(priority), + } } diff --git a/crates/printer/src/hyperlink/mod.rs b/crates/printer/src/hyperlink/mod.rs index 7bd1871..e2b74fb 100644 --- a/crates/printer/src/hyperlink/mod.rs +++ b/crates/printer/src/hyperlink/mod.rs @@ -190,6 +190,7 @@ impl std::fmt::Display for HyperlinkFormat { #[derive(Clone, Debug)] pub struct HyperlinkAlias { name: &'static str, + description: &'static str, format: &'static str, display_priority: Option, } @@ -200,6 +201,11 @@ impl HyperlinkAlias { self.name } + /// Returns a very short description of this hyperlink alias. + pub const fn description(&self) -> &str { + self.description + } + /// Returns the display priority of this alias. /// /// If no priority is set, then `None` is returned.