Skip to content

Conversation

@iSazonov
Copy link
Collaborator

@iSazonov iSazonov commented Sep 14, 2017

Add ArgumentCompletions attribute to '-Format' parameter of Get-Date to enable
IntelliSense (tab complete).

Fix

  1. Added ArgumentCompletions attribute to enable IntelliSense but allow not only named format values ("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal") but also custom format strings ("YYYY-MM-dd").
  2. Added a commit to replace tabs in test file.
  3. Added new ArgumentCompletionsAttribute type which allow tab completions (IntelliSense) for parameters without throw on "invalid" values in contrast to ValidateSet.
  4. Added tests for -Format parameter with named format values.
  5. Added tests for ArgumentCompletionsAttribute

Additional considerations

No tab completion test added for Get-Date because it seems we have no requirements to check tab completion for every parameter in all cmdlets.

If AllowAll==true 'ValidateElement' always pass all elements.
Useful if we need enable IntelliSense (TabComplete) but effectively
disable validation
when a parameter can accept not only the listed values but also
arbitrary.
Ex.: Get-Date -Format
Add ValidateSet attribute to '-Format' parameter of Get-Date to enable
IntelliSense (tab complete).
@vors
Copy link
Collaborator

vors commented Sep 14, 2017

Should we use another attribute name just for the IntelliSense scenario?
[ValidateSet(AllowAll)] looks cumbersome. We can inherit from ValidateSetAttribute and use some name that doesn't mention Validation. It's also not very clean, but at least for the end user it will be not as confusing imo.

@iSazonov
Copy link
Collaborator Author

ValidateSet is a sealed.

Copy link
Contributor

@lzybkr lzybkr left a comment

Choose a reason for hiding this comment

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

Thanks for thinking about the usability here - I agree we should do something here, just not like this.

/// Useful if we need enable IntelliSense (TabComplete) but effectively disable validation
/// when a parameter can accept not only the listed values but also arbitrary.
/// Ex.: Get-Date -Format
/// </summary>
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't feel right to me - you shouldn't use a Validation attribute if you aren't validating.

Copy link
Contributor

Choose a reason for hiding this comment

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

This should be reverted.

/// Unix format string
/// </summary>
[Parameter(ParameterSetName = "net")]
[ValidateSetAttribute("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal", AllowAll=true)]
Copy link
Contributor

Choose a reason for hiding this comment

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

I would suggest using an ArgumentCompleter attribute instead - it's a bit more cumbersome, but if this scenario makes sense (and I think it probably does), we can find some way to make it simpler.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Do you suggest enhance ArgumentCompleter to support [ArgumentCompleter("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal")] ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Just brainstorming here - but maybe a new attribute ArgumentCompletions that also implements IArgumentCompleter - this probably requires some additional code elsewhere, probably similar to the ValidateSet code for completion.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

A new attribute requires a lot of code. It seems easiest to add a new constructor public ArgumentCompleterAttribute(params string[] completeStrings)

Introduce new ArgumentCompleter constructor.
Invoke the constructor in NativeCommandArgumentCompletion()
/// </summary>
[Parameter(ParameterSetName = "net")]
[ValidateSetAttribute("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal", AllowAll=true)]
[ArgumentCompleter("FileDate", "FileDateUniversal", "FileDateTime", "FileDateTimeUniversal")]
Copy link
Contributor

Choose a reason for hiding this comment

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

This is much better, but I think still a little weird, I still think it's worth considering adding a new attribute ArgumentCompletions. It seems like you could take your class StringArrayArgumentCompleter, rename it, make it an attribute, and either duplicate a little bit of logic around ValidateSet or ArgumentCompleter in the tab completion code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Is your only thought that ArgumentCompleter is a strange name and you want to rename it?

Copy link
Contributor

Choose a reason for hiding this comment

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

I wouldn't rename ArgumentCompleter even if it is a strange name (which I suppose it is.)

It's a really minor thing, but to me, ArgumentCompleter implies some dynamic code to compute the completions, whereas ArgumentCompletions is static.

Copy link
Collaborator

@powercode powercode Sep 18, 2017

Choose a reason for hiding this comment

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

I have missed that for a long time - the ability to easily complete a set without limiting the parameter to the completions.

Is it a reasonable compromise that you have to go IArgumentCompleter if you want to provide rich CompletionResults, or should be enable this with ArgumentCompletions too?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done next iteration.

This attribute is used to specify an argument completions for a
parameter of a cmdlet or function without force throw unlike
ValidateSetAttribute.
Copy link
Contributor

@lzybkr lzybkr left a comment

Choose a reason for hiding this comment

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

Just a little cleanup and I think it looks good.

{
if (wordToCompletePattern.IsMatch(str))
{
yield return new CompletionResult(str, str, CompletionResultType.Text, str);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be CompletionResultType.ParameterValue? I think that's the only place the attribute will have any effect.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree.
Fixed.

var argumentCompletionsAttribute = parameter.CompiledAttributes.OfType<ArgumentCompletionsAttribute>().FirstOrDefault();
if (argumentCompletionsAttribute != null)
{
try
Copy link
Contributor

Choose a reason for hiding this comment

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

You are calling internal code which doesn't throw, so the try/catch is unnecessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

Metadata.ValidateNotNullFailure);
}

if (AllowAll == true)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be reverted.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

/// Useful if we need enable IntelliSense (TabComplete) but effectively disable validation
/// when a parameter can accept not only the listed values but also arbitrary.
/// Ex.: Get-Date -Format
/// </summary>
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be reverted.

{
result.IgnoreCase = s_attrArgToBoolConverter.Target(s_attrArgToBoolConverter, argValue);
}
else if (argumentName.Equals("AllowAll", StringComparison.OrdinalIgnoreCase))
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be reverted.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed.

Copy link
Contributor

@lzybkr lzybkr left a comment

Choose a reason for hiding this comment

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

Code changes are approved - but we should get a couple of tests for the new ArgumentCompletions attribute.

@daxian-dbw
Copy link
Member

daxian-dbw commented Sep 19, 2017

@iSazonov Can you please update the PR description? Looks like the design has changed.
And also, please consider addressing @lzybkr's non-blocking comment about adding tests for ArgumentCompletions.

@iSazonov iSazonov force-pushed the get-date-intelli branch 2 times, most recently from 411123c to f86c15a Compare September 20, 2017 15:53
@daxian-dbw
Copy link
Member

daxian-dbw commented Sep 20, 2017

@iSazonov The tests look good, thanks!
Hmm, there are failures in AppVeyor test run, can you please take a look?

@iSazonov
Copy link
Collaborator Author

iSazonov commented Sep 21, 2017

Could you please help: C# test failed on "ArgumentCompleter" abbreviation - full name ArgumentCompleterAttribute works. I cannot find how make "ArgumentCompleter" alias.

}

AfterAll {
#Remove-Module -ModuleInfo $testModule
Copy link
Member

Choose a reason for hiding this comment

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

Did you forget to uncomment this?

Copy link
Collaborator Author

@iSazonov iSazonov Sep 21, 2017

Choose a reason for hiding this comment

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

Yes 😄 Today tests is passed. I wonder - I don't change a code.

@daxian-dbw daxian-dbw merged commit 93dc591 into PowerShell:master Sep 21, 2017
@iSazonov iSazonov added the Documentation Needed in this repo Documentation is needed in this repo label Sep 22, 2017
@iSazonov
Copy link
Collaborator Author

@lzybkr Thanks for great idea!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants