mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-07 01:51:14 -03:00
Fix autosuggestions on quoted subcommand keyword
The commandline "and fis" rightly gets command autosuggestions whereas "'and' fis" wrongly gets file autosuggestions. The former works via a hack. Extend it to quoted keywords.
This commit is contained in:
30
src/ast.rs
30
src/ast.rs
@@ -24,6 +24,7 @@
|
||||
TOK_ACCEPT_UNFINISHED, TOK_CONTINUE_AFTER_ERROR, TOK_SHOW_COMMENTS,
|
||||
};
|
||||
use crate::wchar::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
use std::ops::{ControlFlow, Index, IndexMut};
|
||||
|
||||
/**
|
||||
@@ -3965,11 +3966,11 @@ fn is_keyword_char(c: char) -> bool {
|
||||
|| c == '!'
|
||||
}
|
||||
|
||||
/// Given a token, returns the keyword it matches, or ParseKeyword::none.
|
||||
fn keyword_for_token(tok: TokenType, token: &wstr) -> ParseKeyword {
|
||||
/// Given a token, returns unescaped keyword, or the empty string.
|
||||
pub(crate) fn unescape_keyword(tok: TokenType, token: &wstr) -> Cow<'_, wstr> {
|
||||
/* Only strings can be keywords */
|
||||
if tok != TokenType::string {
|
||||
return ParseKeyword::none;
|
||||
return Cow::Borrowed(L!(""));
|
||||
}
|
||||
|
||||
// If token is clean (which most are), we can compare it directly. Otherwise we have to expand
|
||||
@@ -3977,27 +3978,26 @@ fn keyword_for_token(tok: TokenType, token: &wstr) -> ParseKeyword {
|
||||
// expansions. So we do our own "cleanliness" check; if we find a character not in our allowed
|
||||
// set we know it's not a keyword, and if we never find a quote we don't have to expand! Note
|
||||
// that this lowercase set could be shrunk to be just the characters that are in keywords.
|
||||
let mut result = ParseKeyword::none;
|
||||
let mut needs_expand = false;
|
||||
let mut all_chars_valid = true;
|
||||
for c in token.chars() {
|
||||
if !is_keyword_char(c) {
|
||||
all_chars_valid = false;
|
||||
break;
|
||||
return Cow::Borrowed(L!(""));
|
||||
}
|
||||
// If we encounter a quote, we need expansion.
|
||||
needs_expand = needs_expand || c == '"' || c == '\'' || c == '\\'
|
||||
}
|
||||
|
||||
if all_chars_valid {
|
||||
// Expand if necessary.
|
||||
if !needs_expand {
|
||||
result = ParseKeyword::from(token);
|
||||
} else if let Some(unescaped) = unescape_string(token, UnescapeStringStyle::default()) {
|
||||
result = ParseKeyword::from(&unescaped[..]);
|
||||
}
|
||||
// Expand if necessary.
|
||||
if !needs_expand {
|
||||
return Cow::Borrowed(token);
|
||||
}
|
||||
result
|
||||
|
||||
Cow::Owned(unescape_string(token, UnescapeStringStyle::default()).unwrap_or_default())
|
||||
}
|
||||
|
||||
/// Given a token, returns the keyword it matches, or ParseKeyword::none.
|
||||
fn keyword_for_token(tok: TokenType, token: &wstr) -> ParseKeyword {
|
||||
ParseKeyword::from(&unescape_keyword(tok, token)[..])
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast::unescape_keyword,
|
||||
common::charptr2wcstring,
|
||||
reader::{get_quote, is_backslashed},
|
||||
util::wcsfilecmp,
|
||||
@@ -669,7 +670,12 @@ fn perform_for_commandline_impl(&mut self, cmdline: WString) {
|
||||
if is_autosuggest {
|
||||
let prefixed_supercommand_count = tokens
|
||||
.iter()
|
||||
.take_while(|token| parser_keywords_is_subcommand(token.get_source(&cmdline)))
|
||||
.take_while(|token| {
|
||||
parser_keywords_is_subcommand(&unescape_keyword(
|
||||
token.type_,
|
||||
token.get_source(&cmdline),
|
||||
))
|
||||
})
|
||||
.count();
|
||||
tokens.drain(..prefixed_supercommand_count);
|
||||
}
|
||||
|
||||
@@ -66,8 +66,8 @@ fn reserved_word(cmd: &wstr) -> Option<&'static ReservedWord> {
|
||||
}
|
||||
|
||||
/// Tests if the specified command's parameters should be interpreted as another command.
|
||||
pub fn parser_keywords_is_subcommand(cmd: &wstr) -> bool {
|
||||
reserved_word(cmd).is_some_and(|reserved_word| reserved_word.is_super_command)
|
||||
pub fn parser_keywords_is_subcommand(cmd: &impl AsRef<wstr>) -> bool {
|
||||
reserved_word(cmd.as_ref()).is_some_and(|reserved_word| reserved_word.is_super_command)
|
||||
}
|
||||
|
||||
/// Tests if the specified command is a reserved word, i.e. if it is the name of one of the builtin
|
||||
|
||||
Reference in New Issue
Block a user