Search code examples
powershellpsreadline

Insert text in current commandline in PowerShell


My goal is to write a function which behaves similarily to what happens when invoking PsReadline's Ctrl-R functionality: insert text on the current command line, but don't accept the line, so that when the function returns the cursor is still on the same line. I tried the following

function Invoke-Foo() {
  [Microsoft.PowerShell.PSConsoleReadLine]::Insert('foo')
}

But when calling this, the result is:

PS> Invoke-Foo foo
PS> <cursor position>

What I want instead if that after inserting the text, the cursor stays on that line so

PS> Invoke-Foo foo<cursor position>

I looked into other PSConsoleReadLine functions (as I assume they are the way to go since PsReadline handles the console?) like AddLine/CancelLine/... but none of the combinations do the trick. What does work is calling the function as a PsReadline key handler using Set-PSReadlineKeyHandler -Key 'Ctrl+P' -ScriptBlock {Invoke-Foo} then hitting Ctrl-P does exactly what I want. So the question is probably: how to hook into PsReadline to mimic a function being called as it's key handler?

update Solution is fairly simple, thanks to Jason for the tip: just bind Enter, and don't accept the line if Invoke-Foo is being called

function DealWithEnterKey() {
  $line = $null
  $cursor = $null
  [Microsoft.PowerShell.PSConsoleReadline]::GetBufferState([ref]$line, [ref]$cursor)

  if($line -match 'Invoke-Foo') {
    Invoke-Foo
  } else {
    [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
  }
}

Set-PSReadlineKeyHandler -Key 'Enter' -ScriptBlock {DealWithEnterKey}

Solution

  • You'll need to either use a custom key handler or simulate keyboard input I think.

    I suggest rebinding Enter. If the command line matches your command, run your command and replace the command line. If not, just call the normal handler for Enter.