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
Fix tab completion for filename contains literal wildcard character #7407
Conversation
*System.Management.Automation/engine/CommandCompletion/CompletionCompleters: Use WildcardPattern::Escape to escape completion text of filename. *System.Management.Automation/engine/regex: WildcardPattern::Escape should also escape "`" since WildcardPattern::Unescape would unescape it, and the matcher parse it as escape character. *System.Management.Automation/namespaces/LocationGlobber: Do not pass regex escaped string to WildcardPattern::Get. This fails tab completion when doing "./path/to/`[f"<TAB>.
@kwkam Please remove "[Feature]" from title in your PRs. We need this prefix only in commit header to force run feature tests. |
This PR has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed if no further activity occurs within 10 days. |
@@ -739,6 +739,9 @@ dir -Recurse ` | |||
@{ inputStr = "Get-Process >'.\My ``[Path``]\'"; expected = "'.${separator}My ``[Path``]${separator}test.ps1'" } | |||
@{ inputStr = "Get-Process >${tempDir}\My"; expected = "'${tempDir}${separator}My ``[Path``]'" } | |||
@{ inputStr = "Get-Process > '${tempDir}\My ``[Path``]\'"; expected = "'${tempDir}${separator}My ``[Path``]${separator}test.ps1'" } | |||
@{ inputStr = "cd 'My ``["; expected = "'.${separator}My ``[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.
- We should replace the alias with cmdlet and above too.
- I'd expect that users will type the path without escape - it doesn't work.
- I'd expect that it will work for literal path too - it doesn't work. It could be out of the PR but I'd prefer to remove the fix from the PR and get a full fix in another PR for all scenarios. We should do full review how we process all special chars in Path and in LiteralPath. I do not see the point in partial fixes because they can break something without having a full set of tests.
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.
- Updated test.
- I disagree. User should type escape for
-Path
(which support globbing), just like we do in bash (eg.touch \[test\]
). But if you typed escape and auto completion still did not work, that is because by default, powershell treats "unquoted string without space" like "double-quoted string", that "double-quoted string" will consume escape character. For file name[test]
, eitherGet-Content -Path ```[
orGet-Content -Path '`[
will work. - Would you please let me know what did not work for
-LiteraPath
?
I triedGet-Item -LiteralPath [
(TAB) for a file named[test]
and it did auto complete.
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.
- Consider interactive UX. User do
dir
and then type directory or file name as one see on screen - without escapes. In the scenario both the user and PowerShell know right name. And more, we can have both names - with escape char too. - Get-Item '.\My `[
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 problem is,
-Path
support wildcard. When a path can be an expression, the special characters should always be escaped otherwise it will become too complicated. For example, in a directory there areA.txt
,B.txt
and[AB].txt
, what shouldGet-Item -Path [AB].txt
return? - I tested both
-Path
and-LiteralPath
and both will complete the file name. eg.
New-Item -Name 'My [test]'
Get-Item '.\My `[
will be completed toGet-Item '.\My `[test`]'
, and
Get-Item -LiteralPath '.\My [
will be completed toGet-Item -LiteralPath '.\My [test]'
Did you use the build here? https://ci.appveyor.com/project/PowerShell/powershell/build/v6.1.0-rc.10960/job/3i76g2ar1wqlvw7x/artifacts
test/powershell/Language/Parser/LanguageAndParser.TestFollowup.Tests.ps1
Outdated
Show resolved
Hide resolved
// | ||
if (IsWildcardChar(ch) && !charsNotToEscape.Contains(ch)) | ||
if ((IsWildcardChar(ch) || ch == escapeChar) && | ||
!charsNotToEscape.Contains(ch)) |
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.
Why we always should escape the escape char? What scenario don't work without fix?
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.
- When we accidentally created a file named
`[test`]2
due to the incorrect handling of wildcard character, we cannot remove it using the -Path parameter with the tab completed name. - When I escaped string A and get B, and try to unescape B, I would expected that A will be returned, but it is not when A contains escape character.
- The wildcard pattern parser always treat escape character as escape character.
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.
My understanding is that we should test if a file/directory/path exists before trying escape. If exist then return the path. Then continue with escaping wildcard chars. Then continue with expansion wildcards if -Path.
Also what if there is some special symbols in the path? Seems we should process them in cycle.
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.
Okay, I know what is wrong here. This part is to fix the WildcardPattern::Escape
function itself, which is not necessary related to the file system.
When WildcardPattern::Get
parse a pattern string, it always treats the escape character as escape character of an escape character. That means, ``
will be parsed to `
.
And so is the WildcardPattern::Unescape
method, [WildcardPattern]::Unescape('``')
will return `
instead of ``
.
But, [WildcardPattern]::Escape('`')
does not escape the escape character, which conflicts with the others.
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.
@kwkam I see your point.
We have the public API
public static string Escape(string pattern)
So the change is a breaking change and it is not desirable to change this behavior until it is established that this is a significant bug.
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.
@iSazonov Yes, we should be careful with changes in public API, but I doubt if this is not a significant bug. For example, there is a list of text:
`[HIGH] patch 1`
`[MED] update 1`
`[LOW] patch 1`
`[MED] patch 2`
`[HIGH] hotfix 3`
`[LOW] patch 2`
`[LOW] hotfix 3`
Now, I want to search for `[LOW] patch 1`
and `[LOW] patch 2`
, and I am using WildcardPattern:
$prefix = '`[LOW] patch '
$pattern = '[1-2]'
$suffix = '`'
$sarg = [WildcardPattern]::Escape($prefix) + $pattern + [WildcardPattern]::Escape($suffix)
$opts = [Management.Automation.WildcardOptions]::Compiled
$matcher = [WildcardPattern]::Get($sarg, $opts)
$ListOfText | ? {$matcher.IsMatch($_)}
No result will be return because of the inconsistency between the Escape method and the WildcardPattern parser. (And this is also the cause of the issue in auto-completed filename which contains escape character)
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 for good example!
We need PowerShell Committee conclusion.
/cc @SteveL-MSFT
@kwkam Sorry for delay - it is very sensetive aria and we should very careful. |
@iSazonov Yes, that's why this PR was placed behind the cmdlet ones. Please let me know if something is not correct/not working. |
cc @BrucePay to follow-up |
This PR has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed if no further activity occurs within 10 days. |
@SteveL-MSFT We have too many frozen PRs. How we can resolve the problem? |
@BrucePay will follow-up on this specific PR |
This PR has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed if no further activity occurs within 10 days. |
Co-Authored-By: Ilya <darpa@yandex.ru>
@@ -4383,6 +4383,12 @@ internal static IEnumerable<CompletionResult> CompleteFilename(CompletionContext | |||
if (CompletionRequiresQuotes(completionText, !useLiteralPath)) | |||
{ | |||
var quoteInUse = quote == string.Empty ? "'" : quote; | |||
|
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.
should all changes be behind the experimental feature?
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 was a condition of the committee
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.
Except filename completion will now also escape *
and ?
in non-literal path, the behaviour should be identical unless the experimental feature (the breaking part) is enabled.
I tested a variation of this PR, while testing the PR I am preparing to fix all argument completion patterns along with variable and member completions, #10226. Previously, I could not use Get-Content to read the content of a file named I did not modify the WildCardPattern.Escape() method, but instead added Now Get-Content reads the content of that file. Even if changes to WildCardPattern.Escape() are considered too breaking, at least manually escape the backticks, in each call. Unfortunately this doesn't fix the issue with redirection, which accepts a wildcard path, but then sends it to out-file as a literal. |
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
@kwkam Please resolve merge conflicts and address comments. |
src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs
Show resolved
Hide resolved
This pull request has been automatically marked as Review Needed because it has been there has not been any activity for 7 days. |
@@ -0,0 +1,68 @@ | |||
# Copyright (c) Microsoft Corporation. All rights reserved. |
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.
# Copyright (c) Microsoft Corporation. All rights reserved. | |
# Copyright (c) Microsoft Corporation. |
@daxian-dbw Can you review this? |
This pull request has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 15 days. It will be closed if no further activity occurs within 10 days of this comment. |
@iSazonov could this pr be reopened? |
@floh96 It makes no sense to reopen. The work could be continue if anybody grabbed the work and MSFT team agreed to review. Now you could open new issue to discuss and vote. |
PR Summary
*System.Management.Automation/engine/CommandCompletion/CompletionCompleters:
Use WildcardPattern::Escape to escape completion text of filename.
*System.Management.Automation/engine/regex:
WildcardPattern::Escape should also escape
"`"
sinceWildcardPattern::Unescape would unescape it,
and the matcher parse it as escape character.
*System.Management.Automation/namespaces/LocationGlobber:
Do not pass regex escaped string to WildcardPattern::Get. This fails
tab completion when doing
"./path/to/`[f"<TAB>
.PR Checklist
.h
,.cpp
,.cs
,.ps1
and.psm1
files have the correct copyright headerWIP:
to the beginning of the title and remove the prefix when the PR is ready.[feature]
if the change is significant or affects feature tests