PowerShell / PSReadLine

A bash inspired readline implementation for PowerShell
BSD 2-Clause "Simplified" License
3.69k stars 293 forks source link

Support "Paste Bracketing" #1471

Open TylerLeonhardt opened 4 years ago

TylerLeonhardt commented 4 years ago

Description of the new feature/enhancement

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

The idea is simple:

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

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~)

lzybkr commented 4 years ago

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

iSazonov commented 4 years ago

Should it be in PowerShell consolehost too?

Tyriar commented 4 years ago

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.

daxian-dbw commented 4 years ago

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

TylerLeonhardt commented 3 years ago

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

skyline75489 commented 3 years ago

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.

lzybkr commented 3 years ago

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.

SteveL-MSFT commented 2 years ago

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.

daxian-dbw commented 2 years ago

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.

o-sdn-o commented 8 months ago

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:

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.