mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-05-31 03:51:14 -03:00
Expand tildes and variables in command for custom completions
A «complete -C '~/fish-shell/build/fish '» fails to load custom completions because we do not expand the ~, so complete_param_for_command() thinks that this command is invalid. Expand command tokens before loading custom completions. Fixes #8442
This commit is contained in:
@@ -1406,6 +1406,14 @@ void completer_t::complete_custom(const wcstring &cmd, const wcstring &cmdline,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool expand_command_token(const operation_context_t &ctx, wcstring &cmd_tok) {
|
||||||
|
// TODO: we give up if the first token expands to more than one argument. We could handle
|
||||||
|
// that case by propagating arguments.
|
||||||
|
// Also we could expand wildcards.
|
||||||
|
return expand_one(cmd_tok, {expand_flag::skip_cmdsubst, expand_flag::skip_wildcards}, ctx,
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// Invoke command-specific completions given by \p arg_data.
|
// Invoke command-specific completions given by \p arg_data.
|
||||||
// Then, for each target wrapped by the given command, update the command
|
// Then, for each target wrapped by the given command, update the command
|
||||||
// line with that target and invoke this recursively.
|
// line with that target and invoke this recursively.
|
||||||
@@ -1445,6 +1453,7 @@ void completer_t::walk_wrap_chain(const wcstring &cmd, const wcstring &cmdline,
|
|||||||
} else {
|
} else {
|
||||||
wrapped_command_offset_in_wt = tok->offset;
|
wrapped_command_offset_in_wt = tok->offset;
|
||||||
wrapped_command = std::move(tok_src);
|
wrapped_command = std::move(tok_src);
|
||||||
|
expand_command_token(ctx, wrapped_command);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1670,15 +1679,15 @@ void completer_t::perform_for_commandline(wcstring cmdline) {
|
|||||||
source_range_t command_range = {static_cast<uint32_t>(cmd_tok.offset),
|
source_range_t command_range = {static_cast<uint32_t>(cmd_tok.offset),
|
||||||
static_cast<uint32_t>(cmd_tok.length)};
|
static_cast<uint32_t>(cmd_tok.length)};
|
||||||
|
|
||||||
wcstring unesc_command;
|
wcstring exp_command = cmd_tok.get_source(cmdline);
|
||||||
bool unescaped =
|
bool unescaped =
|
||||||
unescape_string(cmd_tok.get_source(cmdline), &unesc_command, UNESCAPE_DEFAULT) &&
|
expand_command_token(ctx, exp_command) &&
|
||||||
unescape_string(previous_argument, &arg_data.previous_argument, UNESCAPE_DEFAULT) &&
|
unescape_string(previous_argument, &arg_data.previous_argument, UNESCAPE_DEFAULT) &&
|
||||||
unescape_string(current_argument, &arg_data.current_argument, UNESCAPE_INCOMPLETE);
|
unescape_string(current_argument, &arg_data.current_argument, UNESCAPE_INCOMPLETE);
|
||||||
if (unescaped) {
|
if (unescaped) {
|
||||||
// Have to walk over the command and its entire wrap chain. If any command
|
// Have to walk over the command and its entire wrap chain. If any command
|
||||||
// disables do_file, then they all do.
|
// disables do_file, then they all do.
|
||||||
walk_wrap_chain(unesc_command, cmdline, command_range, &arg_data);
|
walk_wrap_chain(exp_command, cmdline, command_range, &arg_data);
|
||||||
do_file = arg_data.do_file;
|
do_file = arg_data.do_file;
|
||||||
|
|
||||||
// If we're autosuggesting, and the token is empty, don't do file suggestions.
|
// If we're autosuggesting, and the token is empty, don't do file suggestions.
|
||||||
@@ -1689,7 +1698,7 @@ void completer_t::perform_for_commandline(wcstring cmdline) {
|
|||||||
|
|
||||||
// Hack. If we're cd, handle it specially (issue #1059, others).
|
// Hack. If we're cd, handle it specially (issue #1059, others).
|
||||||
handle_as_special_cd =
|
handle_as_special_cd =
|
||||||
(unesc_command == L"cd") || arg_data.visited_wrapped_commands.count(L"cd");
|
(exp_command == L"cd") || arg_data.visited_wrapped_commands.count(L"cd");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maybe apply variable assignments.
|
// Maybe apply variable assignments.
|
||||||
|
|||||||
@@ -410,6 +410,12 @@ complete -p $PWD/command-not-in-path -xa relative-path
|
|||||||
complete -C './command-not-in-path '
|
complete -C './command-not-in-path '
|
||||||
# CHECK: relative-path
|
# CHECK: relative-path
|
||||||
|
|
||||||
|
# Expand variables and tildes in command.
|
||||||
|
complete -C '$PWD/command-not-in-path '
|
||||||
|
# CHECK: relative-path
|
||||||
|
HOME=$PWD complete -C '~/command-not-in-path '
|
||||||
|
# CHECK: relative-path
|
||||||
|
|
||||||
# Non-canonical command path
|
# Non-canonical command path
|
||||||
mkdir -p subdir
|
mkdir -p subdir
|
||||||
: >subdir/command-in-subdir
|
: >subdir/command-in-subdir
|
||||||
@@ -427,3 +433,24 @@ end
|
|||||||
|
|
||||||
cd -
|
cd -
|
||||||
rm -r $dir
|
rm -r $dir
|
||||||
|
|
||||||
|
# Expand variables and tildes in command.
|
||||||
|
complete cat -xa +pet
|
||||||
|
set -l path_to_cat (command -v cat)
|
||||||
|
complete -C '$path_to_cat '
|
||||||
|
# CHECK: +pet
|
||||||
|
HOME=$path_to_cat/.. complete -C '~/cat '
|
||||||
|
# CHECK: +pet
|
||||||
|
|
||||||
|
# Do not expand command substitutions.
|
||||||
|
complete -C '(echo cat) ' | string match +pet
|
||||||
|
# Give up if we expand to multiple arguments (we'd need to handle the arguments).
|
||||||
|
complete -C '{cat,arg1,arg2} ' | string match +pet
|
||||||
|
# Don't expand wildcards though we could.
|
||||||
|
complete -C '$path_to_cat* ' | string match +pet
|
||||||
|
|
||||||
|
# Also expand wrap targets.
|
||||||
|
function crookshanks --wraps '$path_to_cat'
|
||||||
|
end
|
||||||
|
complete -C 'crookshanks '
|
||||||
|
# CHECK: +pet
|
||||||
|
|||||||
Reference in New Issue
Block a user