-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Use parameter HelpMessage for tool tip completion #25108
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
base: master
Are you sure you want to change the base?
Conversation
Use the help message on the parameter in the completion tool tip to provide better completion help. This can be utilised by other tools to provide more context for a parameter outside of the current type and parameter name which is quite minimal.
/cc @MartinGC94 Please review. |
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.
Looks great!
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
Looks good to me. My only concern was the tooltip showing the exception "Failed to find the help message: {e.Message}" but it seems like you already plan to change this. |
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Outdated
Show resolved
Hide resolved
/// <returns></returns> | ||
private static List<CompletionResult> GetParameterCompletionResults( | ||
string parameterName, | ||
uint validParameterSetFlags, | ||
IEnumerable<MergedCompiledCommandParameter> parameters, | ||
bool withColon) | ||
bool withColon, | ||
Assembly commandAssembly = null) |
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.
The same.
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.
We don't but it saved me from specifying null for the argument where it is called. I can certainly make it without a default if you prefer that.
I do think the default is a nice way to see that the argument is nullable without having to turn on the nullability checks and annotating it.
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 see your point. This is not critical, it just makes me think that there are a number of call sites that use this 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.
In this case there still are, this is why I added the default in the first place because there are some calls where there is no assembly object to provide.
Thanks for the review @iSazonov, I've pushed a change that is a tiny bit different from your suggestion (still very similar). Please let me know if I've missed anything or if you want me to make the commandAssembly on |
if (helpMessage is not null && TryGetParameterHelpMessage(pattr, commandAssembly, out string attrHelpMessage)) | ||
{ | ||
helpMessage = $" - {attrHelpMessage}"; | ||
} |
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.
Last attribute win? In code above first win. I'd expect the same here.
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.
It's somewhat confusing but the "first" attribute is actually the closes one to the definition rather than it being top -> bottom.
So in the below example the first attribute is actually Bottom
, then Middle
, then finally Top
.
[Parameter(HelpMessage='Top')]
[Parameter(HelpMessage='Middle')]
[Parameter(HelpMessage='Bottom')]
[string]
$Param
This could change in the future but the code already goes bottom -> top and I don't think this PR should be the one to revisit that choice.
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 mean line 791. There is a break
but not here. Why is it different?
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.
The code from 783-794 only check for the help message and does not check for DontShow
(what it is doing today) so once we get a message we can cancel the loop entirely.
The code from 904-921 currently checks if DontShow
is present hence why it breaks early there in that code branch. With this PR it also now checks for the help message if present but it doesn't break because it still needs to check for DontShow
if present in subsequent attributes for the parameter.
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 ask about follow difference:
- In code from 783-794 we get help message from "Bottom" (first attribute in the loop)
- In code from 904-921 we get help message from "Top" (last attribute in the loop)
Yes?
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.
No differences they are both the same, both will loop through the attributes in the "compiled" order from PowerShell (bottom up). It will stop at the first attribute where there is a valid help message found.
The only reason why there is a difference in code is because one handles DontShow
while the other does not. This is a behaviour not touched by this PR at all.
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 could change in the future but the code already goes bottom -> top and I don't think this PR should be the one to revisit that choice.
Before this change, there was nothing in the result to distinguish one result from another for the same parameter. But now we have such property - Tooltip
. That's why I can't agree with your statement. The results should be generated correct now.
In [string][int]$var
first attribute win - [string]
. The common expectation is that first parameter attribute win too and we see help message from the attribute.
Also if parameter has two parameter attributes for different parameter sets we should get help message from correct parameter set if possible or all cases.
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'm just going to have to leave this as is. This is beyond what I find needed for such a PR. Will just have to wait until someone from the pwsh team gets to this.
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.
MSFT team has already clearly outlined the work that they will do in this milestone and they will not consider others as this exceeds their capabilities.
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
if ($SingleMatch) { | ||
$Script = 'Test-Function -ParamWithHelp' | ||
$res = (TabExpansion2 -inputScript $Script).CompletionMatches | ||
} | ||
else { | ||
$Script = 'Test-Function -' | ||
$res = (TabExpansion2 -inputScript $Script).CompletionMatches | Where-Object CompletionText -eq '-ParamWithHelp' | ||
} | ||
|
||
$res.Count | Should -Be 1 | ||
$res.CompletionText | Should -BeExactly '-ParamWithHelp' | ||
$res.ToolTip | Should -BeExactly $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.
It is better to check all the cases explicitly to avoid regression in any form (in tests below too):
if ($SingleMatch) { | |
$Script = 'Test-Function -ParamWithHelp' | |
$res = (TabExpansion2 -inputScript $Script).CompletionMatches | |
} | |
else { | |
$Script = 'Test-Function -' | |
$res = (TabExpansion2 -inputScript $Script).CompletionMatches | Where-Object CompletionText -eq '-ParamWithHelp' | |
} | |
$res.Count | Should -Be 1 | |
$res.CompletionText | Should -BeExactly '-ParamWithHelp' | |
$res.ToolTip | Should -BeExactly $expected | |
if ($SingleMatch) { | |
$Script = 'Test-Function -ParamWithHelp' | |
$res = (TabExpansion2 -inputScript $Script).CompletionMatches | |
$res.Count | Should -Be 1 | |
$res.CompletionText | Should -BeExactly '-ParamWithHelp' | |
$res.ToolTip | Should -BeExactly $expected | |
} | |
else { | |
$Script = 'Test-Function -' | |
$res = (TabExpansion2 -inputScript $Script).CompletionMatches | Where-Object CompletionText -eq '-ParamWithHelp' | |
$res.Count | Should -Be 2 | |
$res[0].CompletionText | Should -BeExactly '-ParamWithHelp' | |
$res[0].ToolTip | Should -BeExactly $expected | |
$res[1].CompletionText | Should -BeExactly '-ParamWithoutHelp' | |
$res[1].ToolTip | Should -BeExactly '[Object] ParamWithoutHelp' | |
} |
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 this case we are only testing the ToolTip message for each returned option but even if you wanted to have multiple tests there are a few problems with this approach:
- This will return all parameters including the common ones so adding more common parameters would mean you also need to update this test
- I've already added a specific test for a parameter without the help message here https://github.com/PowerShell/PowerShell/pull/25108/files#diff-393e1fa171a673ad5e5c3c1f3700ad03d32d46031ffcf72e4eaac1a7c7c46579R1056-R1077
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 may not apply to this change directly, but if it is possible to make an additional check, why not add it and exclude regression in case someone reworks this code?
My suggestion is to expand this test a bit and check that the text from the first parameter is not randomly displayed for the second one.
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.
Because if attributes for another parameter are being applied to another we have a major problem that would/should be picked up by other tests. By testing it here as well we complicate an already somewhat complicated test that isn’t designed to check for this particular problem.
PR Summary
Use the help message on the parameter in the completion tool tip to provide better completion help. This can be utilised by other tools to provide more context for a parameter outside of the current type and parameter name which is quite minimal.
PR Context
The current tool tip provided by
MenuComplete
for parameter is not too useful as it has just the parameter name and type. With this change it will also include theHelpMessage
(orHelpMessageBaseName
andHelpMessageResourceId
on compiled cmdlets).For example here is the output of
Write-Progress
todayNow this is the output with the changes in this PR.
I went with using
HelpMessage
for a few reasons:ParameterAttribute
at runtimeThe final point I think is pretty important as CBH or MAML help could have quite long descriptions for a parameter which can be messy to display in the console. By having the
HelpMessage
set we can reserve the more detailed help for things likeGet-Help
to show but use this attribute field for things that display the tool tip (tip being short here).PR Checklist
.h
,.cpp
,.cs
,.ps1
and.psm1
files have the correct copyright headerWIP:
or[ WIP ]
to the beginning of the title (theWIP
bot will keep its status check atPending
while the prefix is present) and remove the prefix when the PR is ready.- [ ] Issue filed:
(which runs in a different PS Host).