diff --git a/src/complete.cpp b/src/complete.cpp index 2b4cf9963..03e2e5a81 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1294,9 +1294,9 @@ void complete(const wcstring &cmd_with_subcmds, std::vector *out_c while (position_in_statement > 0 && cmd.at(position_in_statement - 1) == L' ') { position_in_statement--; } - auto plain_statement = tnode_t{ - &tree, tree.find_node_matching_source_location(symbol_plain_statement, - position_in_statement, NULL)}; + auto plain_statement = + tnode_t::find_node_matching_source_location( + &tree, position_in_statement, nullptr); if (!plain_statement) { // Not part of a plain statement. This could be e.g. a for loop header, case expression, // etc. Do generic file completions (issue #1309). If we had to backtrack, it means @@ -1368,15 +1368,14 @@ void complete(const wcstring &cmd_with_subcmds, std::vector *out_c use_implicit_cd); } else { // Get all the arguments. - const parse_node_tree_t::parse_node_list_t all_arguments = - tree.find_nodes(*plain_statement, symbol_argument); + auto all_arguments = tnode_t::find_nodes(&tree, plain_statement); // See whether we are in an argument. We may also be in a redirection, or nothing at // all. size_t matching_arg_index = -1; for (size_t i = 0; i < all_arguments.size(); i++) { - const parse_node_t *node = all_arguments.at(i); - if (node->location_in_or_at_end_of_source_range(position_in_statement)) { + tnode_t arg = all_arguments.at(i); + if (arg.location_in_or_at_end_of_source_range(position_in_statement)) { matching_arg_index = i; break; } @@ -1386,7 +1385,7 @@ void complete(const wcstring &cmd_with_subcmds, std::vector *out_c wcstring current_argument, previous_argument; if (matching_arg_index != (size_t)(-1)) { const wcstring matching_arg = - all_arguments.at(matching_arg_index)->get_source(cmd); + all_arguments.at(matching_arg_index).get_source(cmd); // If the cursor is in whitespace, then the "current" argument is empty and the // previous argument is the matching one. But if the cursor was in or at the end @@ -1401,13 +1400,13 @@ void complete(const wcstring &cmd_with_subcmds, std::vector *out_c current_argument = matching_arg; if (matching_arg_index > 0) { previous_argument = - all_arguments.at(matching_arg_index - 1)->get_source(cmd); + all_arguments.at(matching_arg_index - 1).get_source(cmd); } } // Check to see if we have a preceding double-dash. for (size_t i = 0; i < matching_arg_index; i++) { - if (all_arguments.at(i)->get_source(cmd) == L"--") { + if (all_arguments.at(i).get_source(cmd) == L"--") { had_ddash = true; break; } @@ -1417,9 +1416,10 @@ void complete(const wcstring &cmd_with_subcmds, std::vector *out_c // If we are not in an argument, we may be in a redirection. bool in_redirection = false; if (matching_arg_index == (size_t)(-1)) { - const parse_node_t *redirection = tree.find_node_matching_source_location( - symbol_redirection, position_in_statement, plain_statement); - in_redirection = (redirection != NULL); + if (tnode_t::find_node_matching_source_location( + &tree, position_in_statement, plain_statement)) { + in_redirection = true; + } } bool do_file = false, handle_as_special_cd = false; diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index b965f6f27..4ec7ea313 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -3394,14 +3394,12 @@ static bool test_1_parse_ll2(const wcstring &src, wcstring *out_cmd, wcstring *o } // Get the statement. Should only have one. - const parse_node_tree_t::parse_node_list_t stmt_nodes = - tree.find_nodes(tree.at(0), symbol_plain_statement); - if (stmt_nodes.size() != 1) { - say(L"Unexpected number of statements (%lu) found in '%ls'", stmt_nodes.size(), - src.c_str()); + auto stmts = tnode_t::find_nodes(&tree, &tree.at(0)); + if (stmts.size() != 1) { + say(L"Unexpected number of statements (%lu) found in '%ls'", stmts.size(), src.c_str()); return false; } - const parse_node_t &stmt = *stmt_nodes.at(0); + tnode_t stmt = stmts.at(0); // Return its decoration. *out_deco = tree.decoration_for_plain_statement(stmt); diff --git a/src/parse_tree.h b/src/parse_tree.h index 09729f007..478b31da7 100644 --- a/src/parse_tree.h +++ b/src/parse_tree.h @@ -166,7 +166,7 @@ class parse_node_tree_t : public std::vector { // Find all the nodes of a given type underneath a given node, up to max_count of them. typedef std::vector parse_node_list_t; parse_node_list_t find_nodes(const parse_node_t &parent, parse_token_type_t type, - size_t max_count = (size_t)(-1)) const; + size_t max_count = size_t(-1)) const; // Finds the last node of a given type underneath a given node, or NULL if it could not be // found. If parent is NULL, this finds the last node in the tree of that type. @@ -286,6 +286,14 @@ class tnode_t { return nodeptr && nodeptr->location_in_or_at_end_of_source_range(loc); } + static tnode_t find_node_matching_source_location(const parse_node_tree_t *tree, + size_t source_loc, + const parse_node_t *parent) { + assert(tree && "null tree"); + return tnode_t{tree, + tree->find_node_matching_source_location(Type::token, source_loc, parent)}; + } + /// Type-safe access to a child at the given index. template tnode_t> child() const { @@ -303,6 +311,20 @@ class tnode_t { if (!nodeptr) return {}; return {tree, tree->get_parent(*nodeptr, ParentType::token)}; } + + static std::vector find_nodes(const parse_node_tree_t *tree, + const parse_node_t *parent, + size_t max_count = size_t(-1)) { + assert(tree && "null tree"); + assert(parent && "null parent"); + auto ptrs = tree->find_nodes(*parent, Type::token, max_count); + std::vector result; + result.reserve(ptrs.size()); + for (const parse_node_t *np : ptrs) { + result.emplace_back(tree, np); + } + return result; + } }; /// The big entry point. Parse a string, attempting to produce a tree for the given goal type.