Skip to content

variable tab completion does not escape curly quotes, potentially others #10006

Closed

Description

@msftrncs

Similar to #9881, while attempting to tab complete a variable reference, at least curly quotes (I've also determined en-dash/em-dash too) do not cause an escape to the ${ } notation.

Steps to reproduce

${test`u{2018}var} = 'Hello World'

$t # press tab for completion until `test‘var` appears

Expected behavior

${test‘var}

Actual behavior

$test‘var

I believe this is part of the issue:

private static readonly char[] s_charactersRequiringQuotes = new char[] {
'-', '`', '&', '@', '\'', '"', '#', '{', '}', '(', ')', '$', ',', ';', '|', '<', '>', ' ', '.', '\\', '/', '\t', '^',

I think this is inadequate to catch the conditions that require when the ${ } notation is needed, but the above constant appears to be used for more than just that. The list of characters that require the ${ } notation is much larger and more complicated. If regex could be used, the following might be more accurate for when to require the ${ } : ^(?:[^$^\w?:]|[$^?].)|.(?:::|[^\w?:]) This would return a MATCH when ${ } is required. Examples:

$ false
$$ true
^ false
^^ true
? false
?? true
_? false
:: false
a:: true
test‘var true

Environment data

This particular example was captured with 6.2.0 on Win 10 Pro 18922 (Insiders)

Edit: improved performance of the regex example.

Activity

  1. added
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on Jun 26, 2019
  2. msftrncs commented on Jun 26, 2019

    @msftrncs
    ContributorAuthor

    Also, slightly related,

    ${test`{`}} = 'Hello World'
    
    $t # press tab for completion until `{test{}}` appears

    Expected

    ${test`{`}}

    Actual

    ${test{}}

    This will cause an error stating that you must use `{ instead of { in variable names.

  3. vexx32 commented on Jun 26, 2019

    @vexx32
    Collaborator

    This is actually further complicated, because the variables $$, $^, $! etc are all special. They should require braces, but the tokenizer explicitly allows them as special variables.

  4. msftrncs commented on Jun 26, 2019

    @msftrncs
    ContributorAuthor

    Never heard of $!. The regex above was set to handle the fact that the tokenizer accepts those special conditions.

  5. msftrncs commented on Jun 26, 2019

    @msftrncs
    ContributorAuthor

    I think I might have missed $? … EDIT: I corrected the above regex for the special condition of $?

  6. msftrncs commented on Jun 26, 2019

    @msftrncs
    ContributorAuthor

    Also adding that $?? fails to be completed correctly as ${??}, as I noticed ? was not in the constant list of characters in the code referenced.

    Edit: $:?? is also acceptable.

  7. msftrncs commented on Jun 26, 2019

    @msftrncs
    ContributorAuthor

    Sample PowerShell filter code for testing:

    filter variablenotate {
        if ($_ -match '^(?:[^$^\w?:]|[$^?].)|.(?:::|[^\w?:])') {
            "{$($_ -replace '[{}`]', '`$0')}"
        } else {
            $_
        }
    }

    Note that a more complete filter might escape all control characters, such that <TAB> (^I) would become `t and so on.

    Edit: missed ` in the list of characters that need escaped in the -replace operation.

    Edit: improved performance of the -match regex

  8. msftrncs commented on Jul 1, 2019

    @msftrncs
    ContributorAuthor

    Also adding that variables with backticks in their name will properly wrap with ${ } when completed but fail to escape the backtick in that notation.

  9. msftrncs commented on Jul 20, 2019

    @msftrncs
    ContributorAuthor

    I've also found that there are some issues around variables that contain : (I know there are some opinions there), but demonstrating a more complete escaper:

    filter variableNotate {
        param(
            [string]$ScopeOrProviderPrefix = '' # specify either scope or provider prefix
        )
        # return a result object similar to the System.Management.Automation.CompletionResult class
        [pscustomobject]@{ 
            ListItemText   = $_
            CompletionText = "$($(
                if ($ScopeOrProviderPrefix -eq '') {
                    # no scope/drive prefix, detect reasons to force a blank prefix
                    if ($_.Contains([char]':') -or $_ -match '^\?[\w?:]+$') {
                        # force `:` prefix for names containing `:` or beginning with `?` but not needing `{}`
                        ":$_"
                    } else {
                        #no prefixing needed
                        $_
                    }
                } else {
                    # assemble the prefixed completion
                    "${ScopeOrProviderPrefix}:$_"
                }
            ).foreach{
                # detect if final completion requires `{}`
                if ($_ -match '^(?:[^$^\w?:]|[$^?].)|.(?:::|[^\w?:])') {
                    # `{}` required, escape where needed
                    "{$($_ -replace '[{}`]', '`$0')}"
                } else {
                    # no wrapping or escaping needed
                    $_
                }
            })"
        }
    }
    

    This filter now produces an output similar to the CompletionResult class.

    Example usages: (uses aliases)

    (dir env:*).name | variableNotate 'env'
    
    (dir variable:*).name | variableNotate

    Both above should demonstrate the correct escaped completion to use with the $ sigil.

    (Partial Output from env:*)

    ListItemText                    CompletionText
    ------------                    --------------
    OS                              env:OS
    CommonProgramFiles(x86)         {env:CommonProgramFiles(x86)}
    HOMEPATH                        env:HOMEPATH
    ProgramFiles(x86)               {env:ProgramFiles(x86)}
    ProgramData                     env:ProgramData
    TMP                             env:TMP
    

    (Partial Output from variable:*)

    ListItemText                CompletionText
    ------------                --------------
    $                           $
    ^                           ^
    ?                           ?
    *hello                      {*hello}
    hello                       hello
    @hello                      {@hello}
    a                           a
    `                           {``}
    ::                          {:::}
    :                           ::
    ??                          :??
    

    While writing this up, I also found that the *Hello variable doesn't complete correctly, * is also missing from the list of characters that require escape, but you can see this filter suggests the correct completion.

    Edit: Revised filter a few times to optimize the regex, and better capture condition of variables starting with '?', Reference the ?? variable in the sample output.

  10. msftrncs commented on Jul 21, 2019

    @msftrncs
    ContributorAuthor

    I have an intention to post a PR regarding at least parts of this issue, implementing the escapers already found in the CodeGeneration class, and we'll see how far I can go from there.

  11. added a commit that references this issue on Jul 22, 2019
    0af1d06
  12. msftrncs commented on Jul 22, 2019

    @msftrncs
    ContributorAuthor
  13. added
    Issue-BugIssue has been identified as a bug in the product
    and removed
    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a
    on Oct 2, 2019
  14. added a commit that references this issue on Dec 2, 2019
    ae99f9b
  15. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  16. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  17. microsoft-github-policy-service commented on Nov 16, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  18. microsoft-github-policy-service commented on Nov 23, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    In-PRIndicates that a PR is out for the issueIssue-BugIssue has been identified as a bug in the productResolution-No ActivityIssue has had no activity for 6 months or moreWG-Interactive-IntelliSensetab completion

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions