-
-
Notifications
You must be signed in to change notification settings - Fork 61
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
Autocompletion #98
Autocompletion #98
Conversation
Take your time ;) |
This is looking awesome! Did have one piece of feedback though:
Please don't. As a user, the only time I expect my profiles to be touched is either if A) I'm personally updating them or B) I'm using a package manager which has a trigger to enable completion. I would never want a tool to abitrarily touch my profiles. Providing the ability for tool makers to opt-in to having a command which will allow their end users to trigger an install or export a registration script would be much more preferable. |
I had wondered what kind of reaction this would get. My thought was to let the application developer decide as follows: new CliApplicationBuilder().AllowSuggestMode(enabled: true, autoinstall: true) if enabled = false, don't install under any circumstances cli.exe [suggest] --install
## alternatively, supply reference documentation if enabled = true, autoinstall = true, install upon first run The default values would be enabled = false, autoinstall = false. |
Imho, allowing auto install at all I think is a foot gun and maintenance concern. I may honestly be a bit biased however. |
I'm also leaning towards letting the user decide whether they want to install autocompletion or not. We can add a hint inside the help text what would give instructions on how to do it (probably just running |
For libraries, I tend to err on giving developers ultimate control over their applications, however upon second thought, I think there is wisdom here. While I've tried my best to consider the edge cases for now, and while I reckon we can probably get there eventually, I don't for a second think we wouldn't be fixing bugs. Ok. Let's make it a user choice, at least until we've validated functionality with real users. Even then, I suspect that we will have done more than enough with any sort of install.
Yup. I'm cool with that.
I like this
Yup. We just want to watch out for the edge case where someone wants to manually write their own hooks. We wouldn't want the action that does suggestions to also modify profiles. |
bd3aa95
to
5b0eedb
Compare
… not handled consistently.
…x subsystem for Windows behave weirdly when application is in a windows mount (eg /mnt/c...).
…with [suggest] --install command line.
f1e321c
to
7f0fe4d
Compare
…s when searching for an exact options match.
Updated PR as follows
Known issue: Bash autocompletion does not suggest child commands
I suspect the issue is in the bash autocomplete hook, but I don't know what the issue is exactly. More investigation needed. |
Thanks @mauricel. I will take a closer look over the coming weeks. Can you please write down a short but detailed reasoning behind the changes you made? I want to better understand how it works, possible edge cases, nuances you encountered and considered. Unfortunately it's hard to do by just reading the code (as it usually is, not your fault). If you want, you can leave review comments on your code to highlight certain parts or start a discussion if you need some input. Thanks! |
Thank you for considering this pull request. I've included the requested design information. You're right about the edge cases. I hope this helps., and I would appreciate any feedback/guidance you might have. Sorry about the large merge! Thanks! |
Random aside: Probably too big for this PR (which is already big (and awesome)), but it'd be nice to eventually be able to plug into autocompletion to allow dynamic suggestions. (e.g. |
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.
Thanks! Finally got around to read through this. Left some comments/questions, which should be enough for first pass. Let's slowly flesh it out :)
private string _cmdCommandCs = @" | ||
[Command(""cmd"")] | ||
public class Command : ICommand | ||
{ | ||
public ValueTask ExecuteAsync(IConsole console) => default; | ||
} | ||
"; | ||
|
||
private string _cmd2CommandCs = @" | ||
[Command(""cmd02"")] | ||
public class Command02 : ICommand | ||
{ | ||
public ValueTask ExecuteAsync(IConsole console) => default; | ||
} | ||
"; | ||
|
||
private string _parentCommandCs = @" | ||
[Command(""parent"")] | ||
public class ParentCommand : ICommand | ||
{ | ||
public ValueTask ExecuteAsync(IConsole console) => default; | ||
} | ||
"; | ||
|
||
private string _childCommandCs = @" | ||
[Command(""parent list"")] | ||
public class ParentCommand : ICommand | ||
{ | ||
public ValueTask ExecuteAsync(IConsole console) => default; | ||
} | ||
"; |
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.
Let's keep the commands local to the tests. This was the intention behind compiling them like this, otherwise we'd just be able to use regular classes instead :)
Code duplication is fine, logical isolation is more important. I don't want the tests to have shared context.
To compile multiple commands at once, you can use DynamicCommandBuilder.CompileMany(...)
.
} | ||
|
||
[Fact] | ||
public async Task Suggest_directive_is_disabled_by_default() |
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.
Is "off by default" a behavior we want? I mean, the user will still have to enable suggest mode in their terminal regardless, right?
[InlineData("supply all commands if nothing supplied", | ||
"clifx.exe", 0, new[] { "cmd", "cmd02", "parent", "parent list" })] | ||
[InlineData("supply all commands that 'start with' argument", | ||
"clifx.exe c", 0, new[] { "cmd", "cmd02" })] | ||
[InlineData("supply command options if match found, regardles of other partial matches (no options defined)", | ||
"clifx.exe cmd", 0, new string[] { })] | ||
[InlineData("supply nothing if no commands 'starts with' argument", | ||
"clifx.exe m", 0, new string[] { })] | ||
[InlineData("supply completions of partial child commands", | ||
"clifx.exe parent l", 0, new[] { "list" })] | ||
[InlineData("supply all commands that 'start with' argument, allowing for cursor position", | ||
"clifx.exe cmd", -2, new[] { "cmd", "cmd02" })] | ||
public async Task Suggest_directive_suggests_commands_by_environment_variables(string usecase, string variableContents, int cursorOffset, string[] expected) |
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.
Let's split this into separate tests instead of using InlineData
. This is very unreadable in the current state in my opinion.
|
||
// Act | ||
var exitCode = await application.RunAsync( | ||
new[] { "[suggest]", "--envvar", "CLIFX-{GUID}", "--cursor", (variableContents.Length + cursorOffset).ToString() }, |
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.
Do we need a dynamic environment variable or can it always be the same? It's set per-process so there shouldn't be conflicts, right?
|
||
Once enabled, your shell must be configured to use suggest mode as follows: | ||
|
||
1. Add your application to the PATH |
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.
This sounds like a dealbreaker. Can we somehow work around this? As a user, I wouldn't want to add a CLI to PATH just to enable autocompletion...
CliFx.Demo.exe [suggest] CliFx.Demo book add title_of_book | ||
# completion suggestions provided, one per line, in standard output | ||
``` | ||
* The command line, and the cursor position can also be supplied by environment variable for more accurate results. |
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 remember you said that the issue was that PowerShell had "breaking weirdness". Can you give some examples of when/how it happens (to explain why we use environment variable as a workaround)?
* Windows Powershell, detected by the presence of "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" | ||
* Ubuntu Powershell, detected by the presence of "/usr/bin/pwsh" | ||
* Ubuntu Bash, detected by the presence of "/usr/bin/bash" |
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.
If I have Ubuntu and both Powershell and Bash installed, what happens if I run cli [suggest] --install
? Will it install on both or just Powershell?
Also, what if I'm using an entirely different terminal? I guess the command will execute successfully, but then autocomplete won't work, which may confuse the user.
|
||
Observations: | ||
1. Text passed to the `[suggest]` directive is split inconsistently when passed via the powershell hook. | ||
2. Cursor positioning seems difficult to predict in relation to the rest of the supplied terms. Note that CliFx is supplied with command line arguments after processing for whitespace. I couldn't find a platform indepdenant way of extracting the raw command line string. |
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 know on .NET/Powershell Environment.CommandLine
returns the raw string without processing.
|
||
# Known Issues | ||
|
||
### Bash auto-completion does not suggest child commands in empty directories |
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.
In empty directories?
<?xml version="1.0" encoding="utf-8"?> | ||
<configuration> | ||
<packageSources> | ||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" /> | ||
</packageSources> | ||
</configuration> |
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.
Can you merge origin/master
into your branch? We added NuGet.config
recently there.
Gonna close it for now due to inactivity, but feel free to reopen if you ever feel like working on it again (and it's fine if you don't too) 🙂 |
Hi,
I've been working at this a while, so I thought I should at least get what I have so far for feedback.
This pull request:
This pull request does not:
Sorry for the wait; encountered some false bugs that slowed down development, and life got busy also.
Closes #13