PSReadLine icon indicating copy to clipboard operation
PSReadLine copied to clipboard

Support "Paste Bracketing"

Open TylerLeonhardt opened this issue 5 years ago • 10 comments

Description of the new feature/enhancement

For some readline experiences, they support this concept of paste bracketing.

The idea is simple:

  • First, the shell emits esc[?2004h
  • This tells the terminal that this shell wants to use paste bracketing
  • When paste bracketing is on, pasted text is prefixed by esc[200~ and followed by esc[201~ by the terminal before sending the text to the shell.

Here's an example screenshot of my version of bash on macOS with readline (which doesn't support this but you can see the effect):

MicrosoftTeams-image

  • first command tells the terminal to deactivate bracketed pasting
  • second is a paste from the clipboard
  • 3rd activates bracketed pasting
  • 4th is the same paste from the clipboard but now it has \e[200~ and \e[201~ around it

Pretty much any terminal supports this... for example, here's iTerm2's doc: https://gitlab.com/gnachman/iterm2/-/wikis/Paste-Bracketing#control-sequences

And there's a feature request in Windows Terminal: https://github.com/microsoft/terminal/issues/395

and @Tyriar was considering adding this to VS Code's terminal as well.

What does supporting this mean?

This means that on macOS and Linux (and really crossplat) we can support multi-line pasting - something that has been available on Windows in conhost.exe for a very long time.

Proposed technical implementation details (optional)

At start up, PSReadLine emits \e[?2004h to tell the terminal to use paste bracketing

When we get \e[200~ we can wait until \e[201~ before actually executing anything. (or we can wait for the ENTER after \e[201~)

TylerLeonhardt avatar Apr 15 '20 23:04 TylerLeonhardt

This would resolve this longstanding issue too: https://github.com/PowerShell/PSReadLine/issues/579.

lzybkr avatar Apr 16 '20 02:04 lzybkr

Should it be in PowerShell consolehost too?

iSazonov avatar Apr 16 '20 06:04 iSazonov

Oh vscode has had this support for a long time. I was just suggesting it to use as an alternative as its what most programs do instead of listening for ctrl+v, plus it may work on windows now with conpty.

Tyriar avatar Apr 16 '20 11:04 Tyriar

For my own reference: https://cirw.in/blog/bracketed-paste

daxian-dbw avatar Apr 21 '20 00:04 daxian-dbw

This issue can be fixed with this https://github.com/PowerShell/vscode-powershell/issues/3087#issuecomment-743344965

TylerLeonhardt avatar Dec 11 '20 18:12 TylerLeonhardt

With https://github.com/microsoft/terminal/pull/9034 merged, bracketed paste is supported in Windows Terminal. I'd love to see it in PSReadLine, too.

skyline75489 avatar Feb 15 '21 01:02 skyline75489

I believe supporting this is non-trivial.

PSReadLine currently relies on Console.ReadKey to deal with the platform specifics w.r.t. input, e.g. on non-Windows, the dotnet runtime does a decent job of support the terminfo database.

As I understand bracketed paste - the dotnet runtime would likely ignore the paste begin/end sequences as Console.ReadKey doesn't have a good way to return the metainfo we would need.

PSReadLine does have limited support for mapping the VT input escape sequences, but it is currently Windows only and not used by default - but that code might be of use to someone wanting to add support for bracketed paste.

lzybkr avatar Feb 15 '21 19:02 lzybkr

So it sounds like we need .NET to support understanding this escape sequence and then have a way to inform PSReadLine rather than PSReadLine trying to parse the escape sequence itself.

SteveL-MSFT avatar Sep 16 '21 20:09 SteveL-MSFT

Feature requesting issue opened on .NET repo: https://github.com/dotnet/runtime/issues/60107 Also opened an issue to ask for clarification on the current behavior of Console.ReadKey regarding the start/end sequences of bracketed paste: https://github.com/dotnet/runtime/issues/60101

In summary, the dependencies for fixing this in PowerShell are:

  1. [API Proposal]: Allow Console.ReadKey to parse VT sequences when ENABLE_VIRTUAL_TERMINAL_INPUT is set on Windows
  2. Console.ReadKey returns incomplete VT sequences for bracketed paste
  3. Support bracketed paste in conhost

Be noted that, today some key-bindings (e.g. Ctrl+[) work on Windows but not on Unix platforms because on Unix Console.ReadKey needs to parse/map VT sequences to ConsoleKeyInfo and thus those key-bindings are interpreted differently.

Assuming dotnet/runtime#60107 is addressed in .NET using the same parsing/mapping code that works on Unix, then those key-bindings will stop working on Windows once we switch to the new mode of Console.ReadKey in order to enable ENABLE_VIRTUAL_TERMINAL_INPUT on Windows. That would definitely be a breaking change. So, when working on this fix (after all dependencies are ready), we may need to consider to have this fix an opt-in feature, instead of the default.

daxian-dbw avatar Oct 07 '21 01:10 daxian-dbw

Since PSReadLine reads the input stream using ReadConsoleInput, could you consider adding a support for "Bracketed Paste" marks (INPUT_RECORD marks) in the following form:

Clipboard block (inbound INPUT_RECORD stream):

rec_first.EventType == MENU_EVENT;
rec_first.Event.MenuEvent.dwCommandId = 0x8001; // paste_begin

// set of recs with wchar-by-wchar binary copy
// of the block pasted from the clipboard
...
rec_n.EventType == KEY_EVENT;
rec_n.Event.KeyEvent.uChar.UnicodeChar = wchar; // Pasted data set
...

rec_last.EventType == MENU_EVENT;
rec_last.Event.MenuEvent.dwCommandId`= 0x8002; // paste_end

Here I mean placing marks on the operating system side (condrv), and not on the application side. In particular, 3p terminal emulator, receiving a clipboard block via SSH, forms on the condrv side a set of INPUT_RECORD records that PSReadLine is waiting for.

This approach greatly simplifies the task of cross-platform transferring a clipboard binary immutable block via SSH between hosts. Both from unix to windows to unix, and from windows to unix to windows.

Currently, an immutable block of even plain text requires modification before sending to PSReadLine. PSReadLine requires converting '\r' and '\n' into a VK_RETURN keystroke.

Also, if there is a requirement for binary immutability of the pasted block, the use of in-text markers \e[200~-\e[201~ creates the following issues:

  • It is not possible to paste the following piece of UTF-8 text from the clipboard:

    The following characters [201~207] are elements.
    
    • After applying in-text marks: [200~The following characters [201~207] are elements.[201~
    • The result is two altered fragments:
      1. The following characters
      2. 207] are elements.[201~
  • There is a possibility of execution of a malicious block:

    formatt c:[201~
    - an example to paste from clipboard
    
    • After applying in-text marks: [200~formatt c:[201~\n- an example to paste from clipboard[201~
    • Result:
      1. formatt c:
      2. <VK_RETURN>
      3. - an example to paste from clipboard[201~

Using INPUT_RECORD marks eliminates these issues.

PS: This approach is necessary on Windows hosts to receive binary immutable blocks from the clipboard (e.g. received via ssh from unix/wsl etc) by an arbitrary console application that expects it.

o-sdn-o avatar Dec 14 '23 11:12 o-sdn-o