-
Notifications
You must be signed in to change notification settings - Fork 815
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pasting is broken on Windows #1661
Comments
Upon further debugging it appears like a null byte is inserted before every capital letter... |
Given what you've provided above, it's not immediately obvious to me what I'm looking at here and how I may go about recreating the situation so I can further dive into it. To start with, would you mind providing the output of Next, do you think you could provide some instructions on how to go about recreating what you're seeing, and then explaining what you'e seeing? Presumably the above is intended to show what's in your clipboard? To start with, what do you believe you put in there, and how was it placed there, and where from? Does it matter that it looks like a file path? Do you see the same effect if the file doesn't look like a file path? Things such as that. Also, it's not clear to me what relationship the input field and its content has to the JSON below it, which I take to be evidence of the problem given your subsequent comment. A minimal standalone program and some instructions to reproduce would be super helpful. |
I'm using the latest commit that has been merged and to reproduce using the following snippet you may copy text from anywhere and notice that the bug occurs for capital letters and some other characters like colon: from textual.app import App
from textual.widgets import Footer, Header, Input, TextLog
class Configure(App):
def compose(self):
yield Header()
yield Input()
yield TextLog()
yield Footer()
def on_input_changed(self, event):
text_log = self.query_one(TextLog)
text_log.clear()
text_log.write(repr(event.input.value))
if __name__ == "__main__":
Configure().run() |
Thanks. I'll test here when next at my desk. As requested, to check like-for-like (or not), can we see your textual diagnose output too please? |
That's a screenshot of the Textual demo. I'm asking for the output of running the $ textual
Usage: textual [OPTIONS] COMMAND [ARGS]...
Options:
--version Show the version and exit.
--help Show this message and exit.
Commands:
borders Explore the border styles available in Textual.
colors Explore the design system.
console Run the Textual Devtools console.
diagnose Print information about the Textual environment
easing Explore the animation easing functions available in Textual.
keys Show key events.
run Run a Textual app. It writes handy information to Textual DiagnosticsVersions
Python
Operating System
Terminal
Rich Console options
|
The demo is what the following command gives me:
|
Yes, |
I expected that to run the same entry point (as other projects do) since I have many on my PATH... but here is the output: Textual DiagnosticsVersions
Python
Operating System
Terminal
Rich Console options
|
Thank you; that'll be helpful to refer back to. |
Note to self: Windows 10 rather than Windows 11. (making a note as it wouldn't be the first time I've seen mention of Windows Terminal apparently misbehaving on Windows 10 but working fine on Windows 11). |
Eliminating from textual.app import App, ComposeResult
from textual.widgets import Header, Footer, TextLog
from textual.events import Paste
class PasteEventLog( TextLog ):
def on_paste( self, event: Paste ) -> None:
self.write( repr( event.text ) )
event.stop()
class PasteExplorer( App[ None ] ):
def compose( self ) -> ComposeResult:
yield Header()
yield PasteEventLog()
yield Footer()
def on_mount( self ) -> None:
self.query_one( PasteEventLog ).focus()
if __name__ == "__main__":
PasteExplorer().run() and testing with the following three different lines as three different paste events:
the result (Windows 11, Windows Terminal) is this: This is also under Parallels on macOS. Pasting the exact same things into the same app running under macOS is fine. |
That's a weird one. Trust Windows Terminal to do some things differently. To whomever works on this, I'd try to find the spec or PR in the Windows Terminal project that explains the weird behaviour. Non-zero change its a bug in WIndows... |
Also worth noting that this finally explains the code for stripping out |
Making a tweaked version of Textual that has some debug prints sprinkled in "xterm parser" to try and see what's going on low level. With this in place: diff --git a/src/textual/_xterm_parser.py b/src/textual/_xterm_parser.py
index 1bbec555..dc39b9cb 100644
--- a/src/textual/_xterm_parser.py
+++ b/src/textual/_xterm_parser.py
@@ -125,6 +125,7 @@ class XTermParser(Parser[events.Event]):
use_prior_escape = False
if bracketed_paste:
+ print(f"PASTE - APPEND BUFFER - {character!r}")
paste_buffer.append(character)
self.debug_log(f"character={character!r}")
@@ -190,11 +191,13 @@ class XTermParser(Parser[events.Event]):
sequence
)
if bracketed_paste_start_match is not None:
+ print(f"PASTE - BRACKETED START - {sequence!r}")
bracketed_paste = True
break
bracketed_paste_end_match = _re_bracketed_paste_end.match(sequence)
if bracketed_paste_end_match is not None:
+ print(f"PASTE - BRACKETED END - {sequence!r}")
bracketed_paste = False
break on macOS I see the following sequence of events if I paste in
This is what I'd expect given my reading of the code. The same code, running the same test, on Windows, however:
To make clear, those |
Ignoring paste for a moment: on Windows, if I press a key that requires Shift, two key events happen. Let's take pressing { for a moment. When I press that I see this:
The Ctrl+@ apparently corresponding to the press of Shift. On the other hand, if I press [:
This is not the same on macOS. There I just see this:
and this:
So, my hypothesis at the moment is this: Windows Terminal is feeding the pasted characters into the application as if they were keystrokes (or the app is accepting them as keystrokes), and every character that would require the Shift key to be held down as a modifier gets proceeded by a Ctrl+@. I don't know enough about the lowest-levels of Textual and the ways in which input is processed, but this is the correlation I'm seeing: any character that would require Shift to be pressed (perhaps any modifier key actually?) ends up having a connected |
This is really feeling like a bug. Bracketed paste mode support is super new in Windows Terminal. How about we write an independant script to capture a bracketed paste, and write out the repr. So we can raise an issue in https://github.com/microsoft/terminal/ |
It's very much looking that way. Meanwhile, as a workaround, how do you feel about having the paste buffer accumulation code in the xterm parser simply skip over For example, if I place If I do the same into the test app I posted above on macOS the result of pasting
In other words, if we strip NULs the worst case scenario we get is it'll match what you get anyway on macOS. The conclusion being, if we do davep@c80d933 it seems like this makes Windows work just like macOS (at least as a QoL workaround for Windows users for now). Then we can look into what's going on with Windows Terminal at our leisure. |
That seems like a reasonable workaround until we find the root cause. Would it not be more efficient to strip the NULLs on the bracketed end? That way it becomes a single |
Aye, that seems like the more sensible way to get the same effect. I'll create a PR to that effect. |
See Textualize#1661 for lots of context. Long story short, in Windows Terminal it looks like any character that would requite the press of a modifier key causes a NUL to appear in the pasted text for that character. This feels like it could be a bug in Windows Terminal and we will investigate and report at some point. Meanwhile though this provides a workaround that has the paste experience work the same as I'm seeing on macOS (and I would imagine in most terminals on GNU/Linux too).
Don't forget to star the repository! Follow @textualizeio for Textual updates. |
The text was updated successfully, but these errors were encountered: