Skip to content
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

Closed
wants to merge 31 commits into from
Closed

Autocompletion #98

wants to merge 31 commits into from

Conversation

mauricel
Copy link

@mauricel mauricel commented Mar 31, 2021

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:

  • Implements [suggest] directive for commands .
  • Implements Bash and Powershell installation upon first run for current user.
  • Adds necessary tests

This pull request does not:

  • Implement [suggest] auto-completion for options/parameters. Still to do.

Sorry for the wait; encountered some false bugs that slowed down development, and life got busy also.

Closes #13

@Tyrrrz Tyrrrz changed the title #13 suggest mode Autocompletion Apr 1, 2021
@Tyrrrz Tyrrrz added the enhancement New feature or request label Apr 1, 2021
@Tyrrrz
Copy link
Owner

Tyrrrz commented Apr 1, 2021

Take your time ;)

@RichiCoder1
Copy link

RichiCoder1 commented Apr 10, 2021

This is looking awesome! Did have one piece of feedback though:

Implements Bash and Powershell installation upon first run for current user.

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.

@mauricel
Copy link
Author

This is looking awesome! Did have one piece of feedback though:

Implements Bash and Powershell installation upon first run for current user.

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
if enabled = true, autoinstall = false, install is manually triggered by user as follows:

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.

@RichiCoder1
Copy link

Imho, allowing auto install at all I think is a foot gun and maintenance concern. I may honestly be a bit biased however.

@Tyrrrz
Copy link
Owner

Tyrrrz commented Apr 12, 2021

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 cli.exe [suggest] or something). Then that command would install autosuggestions for the current shell.

@mauricel
Copy link
Author

Imho, allowing auto install at all I think is a foot gun and maintenance concern.

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.

I'm also leaning towards letting the user decide whether they want to install autocompletion or not.

Yup. I'm cool with that.

We can add a hint inside the help text what would give instructions on how to do it

I like this

(probably just running cli.exe [suggest] or something).

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.

@mauricel
Copy link
Author

Updated PR as follows

  • implemented parameter and option suggestions
  • added documentation for [suggest] mode in Readme.md
  • Added Nuget.config to work around recent CI failures
  • Number of bug fixes

Known issue: Bash autocompletion does not suggest child commands

Given:  a Bash shell, working in an empty directory
When: user types CliFx.Demo <tab><tab>
Then: Suggestions are: [book] instead of [book, book add, book list, book remove]
Note: cannot reproduce issue if 'book list' is renamed to 'boom' 

I suspect the issue is in the bash autocomplete hook, but I don't know what the issue is exactly. More investigation needed.

@Tyrrrz
Copy link
Owner

Tyrrrz commented Apr 15, 2021

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!

@mauricel
Copy link
Author

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!

@RichiCoder1
Copy link

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. git checkout f<tab> displaying branch suggestions)

Copy link
Owner

@Tyrrrz Tyrrrz left a 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 :)

Comment on lines +21 to +51
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;
}
";
Copy link
Owner

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()
Copy link
Owner

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?

Comment on lines +103 to +115
[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)
Copy link
Owner

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() },
Copy link
Owner

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
Copy link
Owner

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.
Copy link
Owner

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)?

Comment on lines +151 to +153
* 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"
Copy link
Owner

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.
Copy link
Owner

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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In empty directories?

Comment on lines +1 to +6
<?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>
Copy link
Owner

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.

@Tyrrrz Tyrrrz added invalid This doesn't seem right and removed enhancement New feature or request labels Jun 21, 2021
@Tyrrrz
Copy link
Owner

Tyrrrz commented Jun 21, 2021

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) 🙂

@Tyrrrz Tyrrrz closed this Jun 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid This doesn't seem right
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Autocompletion
3 participants