Open
Description
When using programs(less
, fzf
etc.), that emit to alternate buffers, inside ScriptBlock
, there is no display of the program buffer.
For Eg:
Set-PSReadLineKeyHandler -Chord Ctrl+o -ScriptBlock { less foo.txt }
Set-PSReadLineKeyHandler -Chord Ctrl+o -ScriptBlock { find . | fzf }
Show no output
Couple of questions
a) Why is that?
b) What should I do if I need to display them? (Start separate process and redirect stdout from that process?)
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
gogsbread commentedon Jan 20, 2020
Found my own answers. Documenting for reference
a) PsReadLine seems to handle pipe outputs differently using
[Microsoft.PowerShell.PSConsoleReadLine]
primitives. So a normal command likeSet-PSReadLineKeyHandler -Chord Ctrl+o -ScriptBlock { Write-Output "Foo" }
won't work.b) Starting a new process and waiting for that process to finish shows the alternate buffer from that process. From the example above
Set-PSReadLineKeyHandler -Chord Ctrl+o -ScriptBlock { Start-Process -FilePath /usr/bin/less -ArgumentList ./foo.txt -Wait }
will worklzybkr commentedon Jan 21, 2020
That's a reasonable workaround, but it shouldn't be necessary. Unrelated, but note that
less
does not use the alternate screen buffer.The issue is how PowerShell implements
ScriptBlock.Invoke
which redirects stdout to capture the output.less
honors this redirection and does not run interactively.I think this is fixable in PSReadLine. This line would need to be changed, but after some quick experiments, I'm not sure how exactly. Maybe @daxian-dbw has an idea.
daxian-dbw commentedon Jan 21, 2020
The only way I can think of is changing
scriptBlock.Invoke(k, arg);
to the following:By explicitly set the downstream cmdlet to be
Out-Default
, we force thestdout
to not be redirected when executingscriptBlock.ToString()
.However, it will be a breaking change if we go with this because the
scriptBlock
may be a closure created byGetNewClosure()
, andscriptBlock.ToString()
will lose the information about the closure.lzybkr commentedon Jan 21, 2020
Can you use
Invoke-Command
instead?daxian-dbw commentedon Jan 21, 2020
Yup, that would work for the closure:
It will still be a behavior change though, as all the output of the script block will be written out to the console. So for any existing script block handlers that accidentally leak to the output pipe, the user will see those output written out. If we change to this, then the guideline should be
don't write anything to the output pipe in the handler
. Otherwise, it will go through the formatting code and slow down the handler.Any other side effects you can think of, @lzybkr?
SeeminglyScience commentedon Jan 21, 2020
Or purposefully. I've been treating them like void methods, so typing anything is probably going to result in a large wall of
StringBuilder
spam for me. Not sure how typical that is though.daxian-dbw commentedon Jan 21, 2020
Alright, reopen this issue as it looks like something we are interested in improving.
lzybkr commentedon Jan 21, 2020
The behavior change is probably OK. Arguments in favor:
I was worried it might affect modules like
PSFzf
but I don't think it will as that module uses the .Net api to launchfzf
.[-]Question: Programs that use alternate buffers don't output inside scriptblock `Set-PSReadLineKeyHandler`[/-][+]Make the output of script block handler formatted and rendered to the console?[/+]daxian-dbw commentedon Jan 21, 2020
Note that
PSReadLine
doesn't know there is text rendered on the console, so when typing anything after the handler execution, the new characters will be rendered at the original cursor position and overwrite the output from the handler. This will be annoying.It's already the case today when commands like
Write-Host
is used in the handler, but overall it's not too bad given that it behaves like avoid
method today. Making this change will have it look like we encourage rendering the handler output to the console.msftrncs commentedon Jan 24, 2020
Wouldn't the correct behavior for the OP's purpose be to:
RevertLine()
)SelfInsert()
or similar.AcceptLine()
).This way keybinding handlers can remain
void
. The desired command could even be a[psconsolereadline]::method()
if needed, but should, if complexity requires, be implemented as a PowerShell function. This would resolve the issue of output in the middle of editing.I'll admit, I do not know if all the required services to implement this are available.
lzybkr commentedon Jan 24, 2020
Running via
AcceptLine
might be an option, but there are likely unintended consequences like unwanted commands in your history.Also - the command you launch would have to be the last (only?) command in your scriptblock - you couldn't do anything afterwards which could be a deal breaker for some useful extensions.
SeeminglyScience commentedon Jan 24, 2020
If it's determined to be the responsibility of the handler writer, they could just pipe to
Out-Default
themselves. The biggest issue with that currently is that PSRL doesn't notice the cursor position change. So the next key press moves the cursor position back to where PSRL thinks it should be.FWIW, the handlers being invoked with a null pipe is consistent with similar API's like event subscribers and breakpoint actions.
For
AcceptLine
to work, wouldn't the key handler have to return before any action would actually take place? Meaning you'd have to discard the current input completely? Or is that what you're referring to with the next sentence?lzybkr commentedon Jan 24, 2020
Yes, I guess I was hinting that you'd have to return, but a function like
AcceptAndGetNext
could be used to restore the current input.isti115 commentedon Dec 9, 2020
Hmm, PSFzf doesn't want to play nice for me under linux under PowerShell Core 7 and I think that it would be awesome if interactive scripts could be invoked using hotkeys, so I would appreciate if this issue could be solved in a way that doesn't require external tools.
Edit: Hmm, it seems like I've managed to solve it for now, but this doesn't seem to be the cleanest workaround:
rafaeloledo commentedon Dec 12, 2023
I adapted the @isti115 workaround, the behavior is still the same here.
PSReadLineKeyHandler
could have different default values in his context in further versions to prevent user manipulanting processes under the nail like this example.