PSExpandLine_sbExpandHotstring.ps1

[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseDeclaredVarsMoreThanAssignments','')]

# Set the key handler for hotstring expansion
$sbExpand =
{
    Param ($Key,$Arg)

    # Get the contents of the buffer
    $ast         = $null
    $tokens      = $null
    $parseErrors = $null
    $cursor1     = $null
    $buffer      = $null
    $cursor2     = $null
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([Ref]$ast,[Ref]$tokens,[Ref]$parseErrors,[Ref]$cursor1)
    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([Ref]$buffer,[Ref]$cursor2)

    # Find the token immediately before the cursor
    $textLeftOfCursor  = $buffer.Substring(0,$cursor2)
    $spaceLeftOfCursor = $textLeftOfCursor[-1] -eq ' '
    $tokenLeftOfCursor = $null
    ForEach ($token in $tokens)
    {
        $tokenLeftOfCursor = $token

        # Remove token text from the buffer text until there's nothing left
        If ($textLeftOfCursor.StartsWith($token.Text))
        {
            $textLeftOfCursor = $textLeftOfCursor.Substring($token.Text.Length).Trim()
        }
        If (!$textLeftOfCursor)
        {
            Break
        }
    }

    # Get the hotstring definition
    $hotstringDefinition = $null
    If (!$tokenLeftOfCursor.TokenFlags -or $tokenLeftOfCursor.TokenFlags -band 524288) # 524288 = CommandName
    {
        $hotstringDefinition = $hotstrings[$($tokenLeftOfCursor.Text)]
    }

    # Replace hotstring with full command name
    If ($hotstringDefinition -and !$spaceLeftOfCursor)
    {
        [Microsoft.PowerShell.PSConsoleReadLine]::Delete($cursor2-$tokenLeftOfCursor.Text.Length,$tokenLeftOfCursor.Text.Length)
        $trailingWhitespace = ' '
        If ($cursor2 -lt $buffer.Length -and $buffer.Substring($cursor2,1) -eq ' ') { $trailingWhitespace = '' } # don't add a space if there's one already there
        If ($hotstringDefinition[0] -eq '{' -and $hotstringDefinition[-1] -eq '}') # script block
        {
            $sbHotstring = [ScriptBlock]::Create($hotstringDefinition.Substring(1,$hotstringDefinition.Length-2).Trim())
            $hotstringDefinition = Invoke-Command -ScriptBlock $sbHotstring -ErrorAction Ignore | Out-String -NoNewline
        }
        $hotstringDefinition = $hotstringDefinition.Replace("`r`n","`n").Replace("`r","`n") # handle line breaks
        If ($hotstringDefinition -like '*<PSXLCursor>*')
        {
            $splitDefinition = $hotstringDefinition -split '<PSXLCursor>'
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert($splitDefinition[0])
            [Microsoft.PowerShell.PSConsoleReadLine]::SetMark()
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert($splitDefinition[1])
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert($trailingWhitespace)
            [Microsoft.PowerShell.PSConsoleReadLine]::ExchangePointAndMark()

        }
        Else
        {
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert($hotstringDefinition)
            [Microsoft.PowerShell.PSConsoleReadLine]::Insert($trailingWhitespace)
        }
    }
    Else
    {
        [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ')
    }
}