mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-03-17 20:28:03 +02:00
complete/fish: improve shell completions for fish
- Stop using `-n __fish_use_subcommand`. This had the effect of ignoring options if a positional argument has already been given, but that's not how ripgrep works. - Only suggest negation options if the option they're negating is passed (e.g., only complete `--no-pcre2` if `--pcre2` is present). The zsh completions already do this. - Take into account whether an option takes an argument. If an option is not a switch then it won't suggest further options until the argument is given, e.g. `-C<tab>` won't suggest options but `-i<tab>` will. - Suggest correct arguments for options. We already completed a fixed set of choices where available, but now we go further: - Filenames are only suggested for options that take filenames. - `--pre` and `--hostname-bin` suggest binaries from `$PATH`. - `-t`/`--type`/&c use `--type-list` for suggestions, like in zsh, with a preview of the glob patterns. - `--encoding` uses a hardcoded list extracted from the zsh completions. This has been refactored into a separate file, and the range globs (`{1..5}`) replaced by comma globs (`{1,2,3,4,5}`) since those work in both shells. I verified that this produces the same list as before in zsh, and the same list in fish (albeit in a different order). PR #2684
This commit is contained in:
parent
23af5fb043
commit
e0a85678e1
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,3 +1,13 @@
|
|||||||
|
14.1.0 (TBD)
|
||||||
|
============
|
||||||
|
This is a minor release with a few small new features and bug fixes.
|
||||||
|
|
||||||
|
Feature enhancements:
|
||||||
|
|
||||||
|
* [FEATURE #2684](https://github.com/BurntSushi/ripgrep/issues/2684):
|
||||||
|
Improve completions for the `fish` shell.
|
||||||
|
|
||||||
|
|
||||||
14.0.3 (2023-11-28)
|
14.0.3 (2023-11-28)
|
||||||
===================
|
===================
|
||||||
This is a patch release with a bug fix for the `--sortr` flag.
|
This is a patch release with a bug fix for the `--sortr` flag.
|
||||||
|
29
crates/core/flags/complete/encodings.sh
Normal file
29
crates/core/flags/complete/encodings.sh
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# This is impossible to read, but these encodings rarely if ever change, so
|
||||||
|
# it probably does not matter. They are derived from the list given here:
|
||||||
|
# https://encoding.spec.whatwg.org/#concept-encoding-get
|
||||||
|
#
|
||||||
|
# The globbing here works in both fish and zsh (though they expand it in
|
||||||
|
# different orders). It may work in other shells too.
|
||||||
|
|
||||||
|
{{,us-}ascii,arabic,chinese,cyrillic,greek{,8},hebrew,korean}
|
||||||
|
logical visual mac {,cs}macintosh x-mac-{cyrillic,roman,ukrainian}
|
||||||
|
866 ibm{819,866} csibm866
|
||||||
|
big5{,-hkscs} {cn-,cs}big5 x-x-big5
|
||||||
|
cp{819,866,125{0,1,2,3,4,5,6,7,8}} x-cp125{0,1,2,3,4,5,6,7,8}
|
||||||
|
csiso2022{jp,kr} csiso8859{6,8}{e,i}
|
||||||
|
csisolatin{1,2,3,4,5,6,9} csisolatin{arabic,cyrillic,greek,hebrew}
|
||||||
|
ecma-{114,118} asmo-708 elot_928 sun_eu_greek
|
||||||
|
euc-{jp,kr} x-euc-jp cseuckr cseucpkdfmtjapanese
|
||||||
|
{,x-}gbk csiso58gb231280 gb18030 {,cs}gb2312 gb_2312{,-80} hz-gb-2312
|
||||||
|
iso-2022-{cn,cn-ext,jp,kr}
|
||||||
|
iso8859{,-}{1,2,3,4,5,6,7,8,9,10,11,13,14,15}
|
||||||
|
iso-8859-{1,2,3,4,5,6,7,8,9,10,11,{6,8}-{e,i},13,14,15,16} iso_8859-{1,2,3,4,5,6,7,8,9,15}
|
||||||
|
iso_8859-{1,2,6,7}:1987 iso_8859-{3,4,5,8}:1988 iso_8859-9:1989
|
||||||
|
iso-ir-{58,100,101,109,110,126,127,138,144,148,149,157}
|
||||||
|
koi{,8,8-r,8-ru,8-u,8_r} cskoi8r
|
||||||
|
ks_c_5601-{1987,1989} ksc{,_}5691 csksc56011987
|
||||||
|
latin{1,2,3,4,5,6} l{1,2,3,4,5,6,9}
|
||||||
|
shift{-,_}jis csshiftjis {,x-}sjis ms_kanji ms932
|
||||||
|
utf{,-}8 utf-16{,be,le} unicode-1-1-utf-8
|
||||||
|
windows-{31j,874,949,125{0,1,2,3,4,5,6,7,8}} dos-874 tis-620 ansi_x3.4-1968
|
||||||
|
x-user-defined auto none
|
@ -2,17 +2,13 @@
|
|||||||
Provides completions for ripgrep's CLI for the fish shell.
|
Provides completions for ripgrep's CLI for the fish shell.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::flags::defs::FLAGS;
|
use crate::flags::{defs::FLAGS, CompletionType};
|
||||||
|
|
||||||
const TEMPLATE: &'static str =
|
const TEMPLATE: &'static str = "complete -c rg !SHORT! -l !LONG! -d '!DOC!'";
|
||||||
"complete -c rg -n '__fish_use_subcommand' !SHORT! !LONG! !DOC!\n";
|
const TEMPLATE_NEGATED: &'static str =
|
||||||
const TEMPLATE_CHOICES: &'static str =
|
"complete -c rg -l !NEGATED! -n '__fish_contains_opt !SHORT! !LONG!' -d '!DOC!'\n";
|
||||||
"complete -c rg -n '__fish_use_subcommand' !SHORT! !LONG! !DOC! -r -f -a '!CHOICES!'\n";
|
|
||||||
|
|
||||||
/// Generate completions for Fish.
|
/// Generate completions for Fish.
|
||||||
///
|
|
||||||
/// Note that these completions are based on what was produced for ripgrep <=13
|
|
||||||
/// using Clap 2.x. Improvements on this are welcome.
|
|
||||||
pub(crate) fn generate() -> String {
|
pub(crate) fn generate() -> String {
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
for flag in FLAGS.iter() {
|
for flag in FLAGS.iter() {
|
||||||
@ -20,25 +16,49 @@ pub(crate) fn generate() -> String {
|
|||||||
None => "".to_string(),
|
None => "".to_string(),
|
||||||
Some(byte) => format!("-s {}", char::from(byte)),
|
Some(byte) => format!("-s {}", char::from(byte)),
|
||||||
};
|
};
|
||||||
let long = format!("-l '{}'", flag.name_long().replace("'", "\\'"));
|
let long = flag.name_long();
|
||||||
let doc = format!("-d '{}'", flag.doc_short().replace("'", "\\'"));
|
let doc = flag.doc_short().replace("'", "\\'");
|
||||||
let template = if flag.doc_choices().is_empty() {
|
let mut completion = TEMPLATE
|
||||||
TEMPLATE.to_string()
|
|
||||||
} else {
|
|
||||||
TEMPLATE_CHOICES
|
|
||||||
.replace("!CHOICES!", &flag.doc_choices().join(" "))
|
|
||||||
};
|
|
||||||
out.push_str(
|
|
||||||
&template
|
|
||||||
.replace("!SHORT!", &short)
|
.replace("!SHORT!", &short)
|
||||||
.replace("!LONG!", &long)
|
.replace("!LONG!", &long)
|
||||||
.replace("!DOC!", &doc),
|
.replace("!DOC!", &doc);
|
||||||
|
|
||||||
|
match flag.completion_type() {
|
||||||
|
CompletionType::Filename => {
|
||||||
|
completion.push_str(" -r -F");
|
||||||
|
}
|
||||||
|
CompletionType::Executable => {
|
||||||
|
completion.push_str(" -r -f -a '(__fish_complete_command)'");
|
||||||
|
}
|
||||||
|
CompletionType::Filetype => {
|
||||||
|
completion.push_str(
|
||||||
|
" -r -f -a '(rg --type-list | string replace : \\t)'",
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
CompletionType::Encoding => {
|
||||||
|
completion.push_str(" -r -f -a '");
|
||||||
|
completion.push_str(super::ENCODINGS);
|
||||||
|
completion.push_str("'");
|
||||||
|
}
|
||||||
|
CompletionType::Other if !flag.doc_choices().is_empty() => {
|
||||||
|
completion.push_str(" -r -f -a '");
|
||||||
|
completion.push_str(&flag.doc_choices().join(" "));
|
||||||
|
completion.push_str("'");
|
||||||
|
}
|
||||||
|
CompletionType::Other if !flag.is_switch() => {
|
||||||
|
completion.push_str(" -r -f");
|
||||||
|
}
|
||||||
|
CompletionType::Other => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
completion.push('\n');
|
||||||
|
out.push_str(&completion);
|
||||||
|
|
||||||
if let Some(negated) = flag.name_negated() {
|
if let Some(negated) = flag.name_negated() {
|
||||||
let long = format!("-l '{}'", negated.replace("'", "\\'"));
|
|
||||||
out.push_str(
|
out.push_str(
|
||||||
&TEMPLATE
|
&TEMPLATE_NEGATED
|
||||||
.replace("!SHORT!", "")
|
.replace("!NEGATED!", &negated)
|
||||||
|
.replace("!SHORT!", &short)
|
||||||
.replace("!LONG!", &long)
|
.replace("!LONG!", &long)
|
||||||
.replace("!DOC!", &doc),
|
.replace("!DOC!", &doc),
|
||||||
);
|
);
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
Modules for generating completions for various shells.
|
Modules for generating completions for various shells.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static ENCODINGS: &'static str = include_str!("encodings.sh");
|
||||||
|
|
||||||
pub(super) mod bash;
|
pub(super) mod bash;
|
||||||
pub(super) mod fish;
|
pub(super) mod fish;
|
||||||
pub(super) mod powershell;
|
pub(super) mod powershell;
|
||||||
|
@ -413,32 +413,8 @@ _rg_encodings() {
|
|||||||
local -a expl
|
local -a expl
|
||||||
local -aU _encodings
|
local -aU _encodings
|
||||||
|
|
||||||
# This is impossible to read, but these encodings rarely if ever change, so it
|
|
||||||
# probably doesn't matter. They are derived from the list given here:
|
|
||||||
# https://encoding.spec.whatwg.org/#concept-encoding-get
|
|
||||||
_encodings=(
|
_encodings=(
|
||||||
{{,us-}ascii,arabic,chinese,cyrillic,greek{,8},hebrew,korean}
|
!ENCODINGS!
|
||||||
logical visual mac {,cs}macintosh x-mac-{cyrillic,roman,ukrainian}
|
|
||||||
866 ibm{819,866} csibm866
|
|
||||||
big5{,-hkscs} {cn-,cs}big5 x-x-big5
|
|
||||||
cp{819,866,125{0..8}} x-cp125{0..8}
|
|
||||||
csiso2022{jp,kr} csiso8859{6,8}{e,i}
|
|
||||||
csisolatin{{1..6},9} csisolatin{arabic,cyrillic,greek,hebrew}
|
|
||||||
ecma-{114,118} asmo-708 elot_928 sun_eu_greek
|
|
||||||
euc-{jp,kr} x-euc-jp cseuckr cseucpkdfmtjapanese
|
|
||||||
{,x-}gbk csiso58gb231280 gb18030 {,cs}gb2312 gb_2312{,-80} hz-gb-2312
|
|
||||||
iso-2022-{cn,cn-ext,jp,kr}
|
|
||||||
iso8859{,-}{{1..11},13,14,15}
|
|
||||||
iso-8859-{{1..11},{6,8}-{e,i},13,14,15,16} iso_8859-{{1..9},15}
|
|
||||||
iso_8859-{1,2,6,7}:1987 iso_8859-{3,4,5,8}:1988 iso_8859-9:1989
|
|
||||||
iso-ir-{58,100,101,109,110,126,127,138,144,148,149,157}
|
|
||||||
koi{,8,8-r,8-ru,8-u,8_r} cskoi8r
|
|
||||||
ks_c_5601-{1987,1989} ksc{,_}5691 csksc56011987
|
|
||||||
latin{1..6} l{{1..6},9}
|
|
||||||
shift{-,_}jis csshiftjis {,x-}sjis ms_kanji ms932
|
|
||||||
utf{,-}8 utf-16{,be,le} unicode-1-1-utf-8
|
|
||||||
windows-{31j,874,949,125{0..8}} dos-874 tis-620 ansi_x3.4-1968
|
|
||||||
x-user-defined auto none
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_wanted encodings expl encoding compadd -a "$@" - _encodings
|
_wanted encodings expl encoding compadd -a "$@" - _encodings
|
||||||
|
@ -19,5 +19,5 @@ long as it meets criteria 3 and 4 above.
|
|||||||
|
|
||||||
/// Generate completions for zsh.
|
/// Generate completions for zsh.
|
||||||
pub(crate) fn generate() -> String {
|
pub(crate) fn generate() -> String {
|
||||||
include_str!("rg.zsh").to_string()
|
include_str!("rg.zsh").replace("!ENCODINGS!", super::ENCODINGS.trim_end())
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@ use crate::flags::{
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::flags::parse::parse_low_raw;
|
use crate::flags::parse::parse_low_raw;
|
||||||
|
|
||||||
|
use super::CompletionType;
|
||||||
|
|
||||||
/// A list of all flags in ripgrep via implementations of `Flag`.
|
/// A list of all flags in ripgrep via implementations of `Flag`.
|
||||||
///
|
///
|
||||||
/// The order of these flags matter. It determines the order of the flags in
|
/// The order of these flags matter. It determines the order of the flags in
|
||||||
@ -1582,6 +1584,9 @@ The encoding detection that ripgrep uses can be reverted to its automatic mode
|
|||||||
via the \flag-negate{encoding} flag.
|
via the \flag-negate{encoding} flag.
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
fn completion_type(&self) -> CompletionType {
|
||||||
|
CompletionType::Encoding
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
||||||
let value = match v {
|
let value = match v {
|
||||||
@ -1977,6 +1982,9 @@ When \flag{file} or \flag{regexp} is used, then ripgrep treats all positional
|
|||||||
arguments as files or directories to search.
|
arguments as files or directories to search.
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
fn completion_type(&self) -> CompletionType {
|
||||||
|
CompletionType::Filename
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
||||||
let path = PathBuf::from(v.unwrap_value());
|
let path = PathBuf::from(v.unwrap_value());
|
||||||
@ -2808,6 +2816,9 @@ to calling \fBgethostname\fP. On Windows, this corresponds to calling
|
|||||||
ripgrep uses your system's hostname for producing hyperlinks.
|
ripgrep uses your system's hostname for producing hyperlinks.
|
||||||
"#
|
"#
|
||||||
}
|
}
|
||||||
|
fn completion_type(&self) -> CompletionType {
|
||||||
|
CompletionType::Executable
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
||||||
let path = PathBuf::from(v.unwrap_value());
|
let path = PathBuf::from(v.unwrap_value());
|
||||||
@ -3141,6 +3152,9 @@ If you are looking for a way to include or exclude files and directories
|
|||||||
directly on the command line, then use \flag{glob} instead.
|
directly on the command line, then use \flag{glob} instead.
|
||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
fn completion_type(&self) -> CompletionType {
|
||||||
|
CompletionType::Filename
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
||||||
let path = PathBuf::from(v.unwrap_value());
|
let path = PathBuf::from(v.unwrap_value());
|
||||||
@ -5410,6 +5424,9 @@ format, then \fBpzstd\fP is used to decompress the contents to stdout.
|
|||||||
This overrides the \flag{search-zip} flag.
|
This overrides the \flag{search-zip} flag.
|
||||||
"#
|
"#
|
||||||
}
|
}
|
||||||
|
fn completion_type(&self) -> CompletionType {
|
||||||
|
CompletionType::Executable
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
||||||
let path = match v {
|
let path = match v {
|
||||||
@ -6781,6 +6798,9 @@ any rules found in ignore files.
|
|||||||
To see the list of available file types, use the \flag{type-list} flag.
|
To see the list of available file types, use the \flag{type-list} flag.
|
||||||
"#
|
"#
|
||||||
}
|
}
|
||||||
|
fn completion_type(&self) -> CompletionType {
|
||||||
|
CompletionType::Filetype
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
||||||
args.type_changes.push(TypeChange::Select {
|
args.type_changes.push(TypeChange::Select {
|
||||||
@ -7000,6 +7020,9 @@ will only search files that are unrecognized by its type definitions.
|
|||||||
To see the list of available file types, use the \flag{type-list} flag.
|
To see the list of available file types, use the \flag{type-list} flag.
|
||||||
"#
|
"#
|
||||||
}
|
}
|
||||||
|
fn completion_type(&self) -> CompletionType {
|
||||||
|
CompletionType::Filetype
|
||||||
|
}
|
||||||
|
|
||||||
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
fn update(&self, v: FlagValue, args: &mut LowArgs) -> anyhow::Result<()> {
|
||||||
args.type_changes.push(TypeChange::Negate {
|
args.type_changes.push(TypeChange::Negate {
|
||||||
|
@ -70,7 +70,7 @@ mod parse;
|
|||||||
/// value. Flags that accept multiple values are an unsupported abberation.
|
/// value. Flags that accept multiple values are an unsupported abberation.
|
||||||
trait Flag: Debug + Send + Sync + UnwindSafe + RefUnwindSafe + 'static {
|
trait Flag: Debug + Send + Sync + UnwindSafe + RefUnwindSafe + 'static {
|
||||||
/// Returns true if this flag is a switch. When a flag is a switch, the
|
/// Returns true if this flag is a switch. When a flag is a switch, the
|
||||||
/// CLI parser will look for a value after the flag is seen.
|
/// CLI parser will not look for a value after the flag is seen.
|
||||||
fn is_switch(&self) -> bool;
|
fn is_switch(&self) -> bool;
|
||||||
|
|
||||||
/// A short single byte name for this flag. This returns `None` by default,
|
/// A short single byte name for this flag. This returns `None` by default,
|
||||||
@ -150,6 +150,10 @@ trait Flag: Debug + Send + Sync + UnwindSafe + RefUnwindSafe + 'static {
|
|||||||
&[]
|
&[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn completion_type(&self) -> CompletionType {
|
||||||
|
CompletionType::Other
|
||||||
|
}
|
||||||
|
|
||||||
/// Given the parsed value (which might just be a switch), this should
|
/// Given the parsed value (which might just be a switch), this should
|
||||||
/// update the state in `args` based on the value given for this flag.
|
/// update the state in `args` based on the value given for this flag.
|
||||||
///
|
///
|
||||||
@ -228,6 +232,21 @@ impl Category {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The kind of argument a flag accepts, to be used for shell completions.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum CompletionType {
|
||||||
|
/// No special category. is_switch() and doc_choices() may apply.
|
||||||
|
Other,
|
||||||
|
/// A path to a file.
|
||||||
|
Filename,
|
||||||
|
/// A command in $PATH.
|
||||||
|
Executable,
|
||||||
|
/// The name of a file type, as used by e.g. --type.
|
||||||
|
Filetype,
|
||||||
|
/// The name of an encoding_rs encoding, as used by --encoding.
|
||||||
|
Encoding,
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents a value parsed from the command line.
|
/// Represents a value parsed from the command line.
|
||||||
///
|
///
|
||||||
/// This doesn't include the corresponding flag, but values come in one of
|
/// This doesn't include the corresponding flag, but values come in one of
|
||||||
|
Loading…
x
Reference in New Issue
Block a user