Autosuggestions to validate the first command, not the last command

When considering an autosuggestion from history, we attempt to validate the
command to ensure that we don't suggest invalid (e.g. path-dependent)
commands. Prior to this fix, we would validate the last command in the
command line (e.g. in `cd /bin && ./stuff` we would validate "./stuff".
This doesn't really make sense; we should be validating the first command
because it has the potential to change the PWD. Switch to validating the
first command.

Also remove some helper functions that became dead through this change.
This commit is contained in:
ridiculousfish
2019-11-02 13:40:31 -07:00
parent 4dbb209421
commit 151e75d141
4 changed files with 18 additions and 42 deletions

View File

@@ -395,23 +395,31 @@ static bool has_expand_reserved(const wcstring &str) {
return result;
}
// Parse a command line. Return by reference the last command, and the last argument to that command
// (as a string), if any. This is used by autosuggestions.
// Parse a command line. Return by reference the first command, and the first argument to that
// command (as a string), if any. This is used to validate autosuggestions.
static bool autosuggest_parse_command(const wcstring &buff, const environment_t &vars,
wcstring *out_expanded_command, wcstring *out_last_arg) {
wcstring *out_expanded_command, wcstring *out_arg) {
// Parse the buffer.
parse_node_tree_t parse_tree;
parse_tree_from_string(buff,
parse_flag_continue_after_error | parse_flag_accept_incomplete_tokens,
&parse_tree, NULL);
// Find the last statement.
auto last_statement = parse_tree.find_last_node<g::plain_statement>();
if (last_statement &&
plain_statement_get_expanded_command(buff, last_statement, vars, out_expanded_command)) {
// Find the last argument. If we don't get one, return an invalid node.
if (auto last_arg = parse_tree.find_last_node<g::argument>(last_statement)) {
*out_last_arg = last_arg.get_source(buff);
// Find the first statement.
tnode_t<g::plain_statement> first_statement{};
for (const auto &node : parse_tree) {
if (node.type == symbol_plain_statement) {
first_statement = tnode_t<g::plain_statement>(&parse_tree, &node);
break;
}
}
if (first_statement &&
plain_statement_get_expanded_command(buff, first_statement, vars, out_expanded_command)) {
// Find the first argument.
auto args_and_redirs = first_statement.child<1>();
if (auto arg = args_and_redirs.next_in_list<grammar::argument>()) {
*out_arg = arg.get_source(buff);
}
return true;
}