Filesystem paths are strings for parameters. So for any string parameter that doesn't have ValidateSet
, tab completion defaults to using the filesystem provider. For compatibility, we can't ask everyone to decorate parameters that are filesystem paths to indicate they should use the filesystem provider for tab completion. Instead, we can introduce a new attribute to declare it's NOT a filesystem path so that tab complete doesn't start showing filesystem paths where it isn't appropriate.
Add-Content -Path ./foo.txt -Value # hit tab
Tab completion here should do nothing as the parameter is any arbitrary string
Tab completion enumerates files/folders in the current path
Name Value
---- -----
PSVersion 6.2.0-preview.1
PSEdition Core
GitCommitId 6.2.0-preview.1
OS Darwin 18.0.0 Darwin Kernel Version 18.0.0: Wed Aug 22 20:13:40 PDT 2018; root:xnu-4903.201.2~1/RELEASE_X86_64
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
Why use a whole new attribute? I think predefining some behaviours for ArgumentCompleter would be much more extensible.
Param(
[Parameter(Position = 0)]
[ArgumentCompleter(Provider = 'FileSystem')]
[string]
$Path,
[ArgumentCompleter(Provider = 'None')]
[string]
$RandomString
)
So, yes, default to filesystem if not specified, but I think an entirely new attribute is overkill. Let folks specify filesystem for clarity if that is what it is, and let them specify no completion if none is desired.
^^^ Totally agree with the above.
This to me makes more sense than a new attribute
So for any string parameter that doesn't have ValidateSet, tab completion defaults to using the filesystem provider.
It is fallback. How many we have or can have such fallbacks? My thoughts here is about something like ArgumentCompleter(SuppressFallback = $true)
For compatibility, we can't ask everyone to decorate parameters that are filesystem paths to indicate they should use the filesystem provider for tab completion.
Do we really need the fallback and why?
As minimum I think it would be best practice to do this (to decorate path parameters) for future. We could use ArgumentCompleter(filesystem)
for path parameters in the repo.
ArgumentCompleter
accepts a type, so I'd expect something like:
[ArgumentCompleter([PathCompleter])]
# or
[ArgumentCompleter([FileSystemPathCompleter])]
# or
[ArgumentCompleter([NullCompleter])]
Problem with that is that would throw an immediate error in earlier versions. Ideally, I think we should try to have a solution that simply doesn't function in earlier versions / windows PowerShell, without throwing errors.
A new attribute or named argument will be an error in older versions when you call the function.
Yes, but passing it a type that doesn't exist will be an error as well, so it's about the same (except for a more noisy syntax, in my opinion), unless you plan on backporting the proposed classes.
I would think that simply being able to specify a PSProvider would be much more streamlined in this case; given a string that matches a provider name, it can lookup against available PSProviders and apply completion for that instead of the standard filesystem only completion.
Otherwise, every single new and existing PSProvider would need its own argumentcompleter attribute class, which strikes me as awkward and unnecessary.
If you add a named argument, you allow something that is probably nonsense:
[ArgumentCompleter([CompleterType], Provider = 'OtherThing')]
You could use an unnamed argument so the constructor is overloaded, but I think a new attribute would be clearer than an unnamed argument to ArgumentCompleter
.
Providers should probably opt-in to completion anyway by implementing System.Management.Automation.IArgumentCompleter
because some providers are really slow, should use a cache, etc. Then you could write:
[ArgumentCompleter([Microsoft.PowerShell.Commands.FileSystemProvider])]
But if you really want a single type doing all path completion and supports specific providers, the ArgumentCompleterAttribute
could support passing arguments to the types constructor, e.g.:
[ArgumentCompleter([PathCompleter], "FileSystemProvider")]
I will also point out that some people would like a global option to disable the fallback completion e.g. see this StackOverflow question.
I think the trivial implementation of such a global setting would not be a good experience, but such an option might make sense once the core commands have an the necessary annotations to complete paths where it makes sense. I do think we'd still need to complete paths for native commands that have no registered argument completers, or maybe this global option has different levels, like Off
, NativeCommandsOnly
, On
.
Hmmm. All good points, indeed.
So, essentially our options seem to be:
[ArgumentCompleter]
-- as you say, this is kind of unclear to do, and would be interpreted in odd ways in old versions, I'm sureI think option 1 is neatest; I've never really be a particular fan of the overly-bracketed syntax that arises with [ArgumentCompleter([type])]
-- just too many layers, I think, really.
So maybe something along the lines of a [ProviderCompleter('FileSystem')]
sort of approach, inheriting from the existing argumentcompleter class?
Unless there's a backwards-compatible way to do it, which I... don't think there is?
If going the new attribute route, it should probably implement IArgumentCompleter
, see https://github.com/PowerShell/PowerShell/issues/7860
I do think we'd still need to complete paths for native commands
We could implement default ArgumentCompleter for native commands. It allows to create custom completers for native commands. (Could we use here your idea with proxy classes (psmore)?)
Providers should probably opt-in to completion anyway by implementing
I like this most. This goes well with previous suggestion.
I do not like the idea of creating new attributes so we already have a lot of ones. IArgumentCompleter allow address all scenarios in modern way.
Most helpful comment
ArgumentCompleter
accepts a type, so I'd expect something like: