New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix completion for subcommands of builtins #6249
Conversation
I would expect this to be what you want for completions (because the decorator is irrelevant there) but not other uses of I think a better solution would be to fake the commandline in completions, like we already do for |
OK I think it's fair to maintain that behavior of |
6e733d9
to
e65067a
Compare
I have pushed a quite different approach and changed the description. I believe this works fine. (I was thinking that instead of the AST we could just use the tokenizer here but then we'd probably have to add some hacks that reimplement parsing. for example to handle |
23f0bc4
to
dbbb0a0
Compare
This also makes completions for |
dbbb0a0
to
e39d9a7
Compare
|
e39d9a7
to
430826d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the idea here is to make completions forget that command
, not
, etc. are keywords and just pretend everything is a command. This is how fish used to work and in hindsight was better - conceptually simpler. I like this direction.
One downside of moving logic from C++ to script is that we lose autosuggestion support. For example I expect that and
will now autosuggest arbitrary file paths instead of only executables. However this is probably acceptable and there's other ways to fix this.
src/complete.cpp
Outdated
/// | ||
/// The returned nodes are string nodes (keywords for builtins like "if" | ||
/// and "not" and the command string), and a number of argument nodes at the end. | ||
static std::vector<const parse_node_t *> collect_tokens_of_command_at_location( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this is more complicated than necessary. Is all you hope to do collect the string-type nodes? You can do that with a stack, traversing without concern for the type:
std::vector<const parse_node_t *> result;
std::vector<const parse_node_t *> to_visit = {start};
while (! to_visit.empty()) {
// Append to result if type is parse_token_type_string
// Pop it off and push all of its children on
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use tnode_t::descendants()
for this:
auto strings = statement.descendants<grammar::tok_string>();
This gives you all the string nodes under a given node (recursively).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I didn't realize the same can be done with one tnode_t::descendants()
.
But what I am doing now is even simpler, I'm just using the tokenizer because with this change the completion does not need to use the AST, it just needs the string tokens in a process. So this seems good enough for now.
5cad77d
to
4c6e6ca
Compare
Yep, I added a small workaround for autosuggestion of builtins in |
Presently the completion engine ignores builtins that are part of the fish syntax. This can be a problem when completing a string that was based on the output of `commandline -p`. This changes completions to treat these builtins like any other command. This also disables generic (filename) completion inside comments and after strings that do not tokenize. Additionally, comments are stripped off the output of `commandline -p`. Fixes fish-shell#5415 Fixes fish-shell#2705
4c6e6ca
to
c9a403f
Compare
This fixes #2705 - broken subcommand completion for builtins, and #5415 - completions for
function
.Back when the complete builtin was introduced, builtins like
builtin
,exec
,command
,not
,if
,while
,or
andand
couldbe handled by the completion engine just like any other command.
Much has changed, now we are using a grammar that contains dedicated
AST nodes for those commands.
The completion engine works on plain_statement nodes and has some
special handling for builtins like exec and builtin. However,
__fish_complete_subcommand passes subcommand tokens to the completion
engine that are based on
commandline -op
, which includes thebuiltins.
Example: type "command git " and hit tab. Git completion does not work.
What happens is that the completion scripts assume that the first
token on the commandline ("command") is the git executable, and the next
token ("git") is the subcommand. Since "command" is ignored, the git completion is called
with garbage input.
This change uses the information provided by the AST to make completion treat the builtins like any other command. In above example the completions for "command" will be called first.
They will remove the "command" token and then call into "git" completions.
Previous approach
6e733d9
This changes
commandline -p
to only return the plain_statement,without any decorators to make examples like the above one work. If
anyone needs them to return decorators, then it may be preferable to
maintain compatibility instead. However, I think it makes sense to not
print decorators, consider for example:
commandline -p would print
and builtin A
, but in fish's grammar,and
applies to the entire expressionbuiltin A || B
.With this change, it only prints
A
.If needed I can make it so it does print the simple decorators
"exec", "command", "builtin" and "not".
Note that we keep completions like share/completions/builtin.fish
around, even though they are handled in C++, because a commandline
like "builtin " is parsed as plain statement
(while "builtin a" is recognised as decorated statement).
TODOs: