There are various complaints about the right click to paste behavior - all of which are non-issues with Ctrl+v paste.
This includes:
\n
comes in reverse (#496)The fix for this should also address #290 by checking if the input is "complete" after a newline, though it should check if the last statement could be continued even if it is complete, e.g. if
w/o an else
or try
without a finally
.
So I mentioned capturing mouse events and I came up with this PoC https://github.com/Tadas/PSReadLine/tree/MouseHook
Basically this installs a global Windows event hook to capture right clicks. It looks for ones going to our console window, makes sure that the click was in the client area and if we're in quick edit mode calls PSConsoleReadLine.Paste()
directly while suppressing the event.
With some more hackery I think it would be possible to intercept Paste action from the context menu.
Interesting approach.
I'm not interested in taking a dependency on System.Windows.Forms
- I used it for clipboard support but removed the dependency to work as a netstandard2
assembly. I haven't switched the build over though because it gets unnecessarily messy with unnecessary assemblies in the build output directory.
I'm also a bit concerned about ensuring UnhookWindowsHookEx
is always called, e.g. I have some code that should be running when PowerShell exits but it doesn't seem to happen, see #262.
One other thing - ideally we can fix this on every platform, not just Windows. The heuristic approach should work cross-platform, but I'm open to more reliable approaches like yours if there is a solution for the various non-Windows platforms as well.
FYI
This issue still persist on PowerShell Core 6 RC.
:)
@MaximoTrinidad - PSReadLine has always worked this way and it is a little different than without PSReadLine. It wasn't much of a problem because Ctrl+v is preferred - it is way faster and characters like Tab don't get expanded incorrectly.
Now this problem is more annoying on PowerShell Core because the port that the PowerShell team did not support the clipboard. My port does, so when PSReadLine 2.0 is widely available, I'll continue to recommend folks use Ctrl+v instead of right click.
That said, it would be nice to see this fixed at some point.
Hum! Interesting.
They force me to close my incident about the issue with the If-Else block not working after pasting it into PowerShell Core as it breaks at the "else".
I just tried using Ctrl-V and it do nothing. In the other hand, doing the right-click on the mouse works.
My issue wasn't really the pasting of the code. The If-Else should work with both structure:
PowerShell v6.0.0-rc
Copyright (c) Microsoft Corporation. All rights reserved.
https://aka.ms/pscore6-docs
Type 'help' to get help.
PS C:\Program Files\PowerShell\6.0.0-rc> # the following code block will break:
PS C:\Program Files\PowerShell\6.0.0-rc> $m = "max"; if($m -eq "elaine")
>> {
>> "Its elaine!!"
>> }
PS C:\Program Files\PowerShell\6.0.0-rc> else
else : The term 'else' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ else
+ ~~~~
+ CategoryInfo : ObjectNotFound: (else:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
PS C:\Program Files\PowerShell\6.0.0-rc> {
>> "Its not elaine"
>> }
"Its not elaine"
PS C:\Program Files\PowerShell\6.0.0-rc> # the following code block will execute:
PS C:\Program Files\PowerShell\6.0.0-rc> $m = "max"; if ($m -eq "elaine")
>> {
>> "Its elaine!!"
>> }else{
>> "Its not elaine"
>> }
Its not elaine
PS C:\Program Files\PowerShell\6.0.0-rc>
I know if I remove the module then is works as expected.
:)
As I said, Ctrl+v works in Windows PowerShell, but you need PSReadLine 2.0 (no official builds available yet) for PowerShell Core.
And I fully understand the problem, you don't need to keep repeating yourself.
Without PSReadLine, if there is multi-line input, you must enter a single blank line before the input is accepted.
With PSReadLine, if the input is "complete", as in, it parses without an IncompleteParseException, then the input will be accepted without that extra blank line.
So PSReadLine is just different and that's not changing. If you aren't pasting, you use Shift+Enter when you know you're not done - this way you can enter your else
without PSReadLine accepting the input.
When you paste, you can't use Shift+Enter, so the input might get accepted before you wanted.
This issue is to attempt to emulate Ctrl+v when you right click paste so that the experience is better, but I do not plan on requiring a blank line to accept multi-line input.
My Apologies!
It's been a tough day! At least, it's manageable, and not show stopper as the script will execute regardless of the way I code the If-Else block.
I appreciate all the information,
:)
I don't understand why you mentioned cross platform'ness - isn't this right-click paste issue strictly a Windows thing?
Anyway, I've removed System.Windows.Forms
by implementing the message loop. It needs to be improved further because right now it keeps calling PeekMessage as fast as it can which is unnecessary.
Seems like always calling UnhookWindowsHookEx
might be not that important as long as the hooking process exits. At least I've never had any issues during debugging.
Maybe not with a right click, but Linux and Mac terminals definitely support paste. For example, the default graphical terminal in CentOS has Edit|Paste in the main menu and Paste in a right click popup menu.
My concern about UnhookWindowsHookEx
is purely based on the documentation - they usually have a good reason to call it out. Maybe try running PowerShell a few thousand times to see if system performance degrades.
As you pointed out, the busy loop is too busy. I use a 300ms wait to check for idle events in the main input loop - 300ms is supposedly long enough to not hurt battery life.
Just to summarize the status quo on (some) _Unix-like platforms_ (macOS 10.13 with either Terminal.app or iTerm2.app, Ubuntu 16 with its default terminal):
The Ctrl+V workaround applies to Windows only (similarly, binding a custom chord to the Paste
function doesn't work on Unix).
As with right-clicking on Windows, using the terminal-program specific keyboard shortcut for pasting (Cmd+V on macOS, Ctrl+Shift+Von Ubuntu), seems to paste by simulating interactive typing.
i am pasting a block of code from windows 5.1 powershel ise into powershell 6 via conhost.exe and when i paste with a right click, some of my dashes are missing, whereas if i paste with ctrl+v the dashes are there
I don't see an obvious way to fix this. On Windows, I can see that when pasting via Ctrl+V (which is handled by Windows Terminal and not PSRL), the end of line is \r\n
where the \n
is Ctrl+Enter. The \r
(Enter) is handled by PSRL as AcceptLine and executes. On macOS, the line ending is just \r
(without any modifier). So the best workaround is to bind PSReadLine Paste handler to some chord and use that which pastes correctly.
It is interesting that without PSReadLine, the basic ReadLine in pwsh handles this correctly...
@SteveL-MSFT: As for macOS: haven't looked in detail, but multi-line pasting with the default keyboard shortcut (Cmd-V) seems to work just fine in PSRL 2.0.0 beta.4, with both CRLF- and platform-native LF-only text.
On macOS, the line ending is just
\r
In case you're referring to the platform-native newline sequence on macOS: When macOS became OS X in 2001 and thereby became Unix-like, LF (\n
) became the newline sequence. Only the long-obsolete Mac OS 9 and earlier used CR-only (\r
) newlines.
@SteveL-MSFT - I hinted at the solution above and probably describe it in detail in a linked issue.
If we can infer that a user "pasted" via right click, then we can process keys differently. By tracking the time between key presses, I think it's probably reasonable to infer the user isn't actually typing.
I'm guessing that if the delay between keys is less than 25ms or so, it's not a human typing, especially if we average over enough keys.
@mklement0 I'm running Catalina, the \r
is just what I see in the debugger within PSRL.
@lzybkr detecting that the input isn't human may be good enough.
Thanks for clarifying and sorry fo the distraction, @SteveL-MSFT (I didn't know that Unix terminals apparently translate \n
in multi-line text to \r
, which traditionally acts as the accept-line key, on pasting).
So while the multi-line issues specifically appear not to affect macOS and Linux, PSRL's processing of the input as being typed by the user can cause problems in combination with custom key handlers that modify / complete input (as shown in #735), so the fix proposed by @lzybkr should help on these platforms too.
So while the multi-line issues specifically appear not to affect macOS and Linux, PSRL's processing of the input as being typed by the user can cause problems in combination with custom key handlers that modify / complete input (as show in #735), so the fix proposed by @lzybkr should help on these platforms too.
I didn't find the behavior to be any different in Ubuntu's terminal when pasting. Pasting a multiline IF ELSEIF ELSE statement still got executed between the statement blocks if PSReadLine was imported.
@msftrncs: Yes, there are no multi-line issues _per se_ on macOS and Linux, but if you have a custom keyboard handler that inserts a matching )
for a (
you type, for instance, then a multi-line string with a line that ends in (
will have a )
inserted right after, and pasting breaks - again, see #735.
To amend my previous comment re Unix-like platforms: If else
in a multi-line if
statement is placed on its own line, the problem surfaces too (similar to the VSCode-related problem originally reported in #1127):
# Pasting this fails on Unix-like platforms.
if ($true) { 'yes' }
else { 'no' }
On xterm, PowerShell could enable bracketed paste mode and then recognize the control sequences that xterm adds before and after pasted text. That could be more reliable than a timer-based heuristic, especially over slow links.
The Windows console does not seem to support it though, according to Console Virtual Terminal Sequences and https://github.com/microsoft/terminal/issues/395.
Yeah, bracketed paste is 100% the right way to fix this. It鈥檚 on my personal to-do list to add support for that to conhost and WT :)
Most helpful comment
Yeah, bracketed paste is 100% the right way to fix this. It鈥檚 on my personal to-do list to add support for that to conhost and WT :)