Skip to content

Unable to select text in pagination mode #18799

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

Open
compnerd opened this issue Apr 14, 2025 · 13 comments
Open

Unable to select text in pagination mode #18799

compnerd opened this issue Apr 14, 2025 · 13 comments
Labels
Issue-Bug It either shouldn't be doing this or needs an investigation. Needs-Attention The core contributors need to come back around and look at this ASAP. Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting

Comments

@compnerd
Copy link

Windows Terminal version

1.22.10731.0

Windows build number

10.0.26100.0

Other Software

No response

Steps to reproduce

Using git log (which uses less as a pager as per default), I am unable to simply double click on the commit hash to select the text. Attempting to do so will result in re-rendering the entire terminal continuously for a while. I've noticed that ESC0D will sometimes appear in the bottom left corner, making me believe that this is a bug in the ANSI sequence parser. It seems that there would be something odd going on with the CSI interpreter, possibly mishandling the initial byte?

This seems to have triggered somewhat recently, though I cannot pin down whether it was a WT update or Patch Tuesday update.

The canary build seems to reproduce this as well.

Note that it helps to have a particularly large terminal (e.g. full screen).

Expected Behavior

No response

Actual Behavior

The terminal becomes non-responsive, redrawing the terminal.

@compnerd compnerd added Issue-Bug It either shouldn't be doing this or needs an investigation. Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting labels Apr 14, 2025
@compnerd
Copy link
Author

I suspect a related exhibition of the issue is that if you type a partial command on the terminal, and then attempt to highlight text, instead of highlighting the text, the cursor is moved to the beginning of the line.

@DHowett
Copy link
Member

DHowett commented Apr 16, 2025

Hey @compnerd, nice to see you around these parts 🙂

Just a couple quick differential diagnostic questions...

  • If you use Shift+click, are you able to select text again?
  • Would you be able to grab a debug tap trace/?

I'm guessing that less enables a mouse mode (or requests a mouse mode) (or uses the Win32 console mode to request mouse mode and then enables VT input...) and doesn't know what to do with what it's getting back.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Apr 16, 2025
@compnerd
Copy link
Author

Hey @compnerd, nice to see you around these parts 🙂

Hey @DHowett, great to see that you're still involved in Terminal! 😄

Just a couple quick differential diagnostic questions...

  • If you use Shift+click, are you able to select text again?

I think that I didn't clearly explain the issue, sorry. It will let me select text again, just only after it has completed repainting the terminal a large number of times. You can identify this process as being complete because the terminal is fully rendered and scrolled up a line (which matches the CSI of 0D). But, just to verify, Shift+click doesn't select any text during the re-draw phase.

One thing that is interesting is that once this has occurred, it will function properly subsequently. So there is something more interesting going on, possibly with state initialisation?

  • Would you be able to grab a debug tap trace/?

Well, the instructions seem complete enough, let me try to do that.

I'm guessing that less enables a mouse mode (or requests a mouse mode) (or uses the Win32 console mode to request mouse mode and then enables VT input...) and doesn't know what to do with what it's getting back.

Hmm, I didn't think of that. You think that this could be related to DECELR? That would allow it to read the scroll "button" (wheel) to allow pagination.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs-Attention The core contributors need to come back around and look at this ASAP. and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Apr 16, 2025
@compnerd
Copy link
Author

  • Would you be able to grab a debug tap trace/?

Well, the instructions seem complete enough, let me try to do that.

Well, that doesn't seem to work very well - it seems to truncate the buffer before I can get the interesting stuff due to the re-rendering.

@compnerd
Copy link
Author

compnerd commented Apr 16, 2025

tap.txt

Okay, I used a different repository which doesn't have as big of a history, it actually is interesting as this is the second exhibition of the issue: it has already exited the pager (less). However, the text selection seems to still trigger the issue. I'm attaching the tap as an attachment here.

@compnerd
Copy link
Author

It seems that yet another exhibition of this issue is if you scroll up, trying to highlight any text will scroll and then highlight, preventing copying any text on any row above the current viewport.

@compnerd
Copy link
Author

Any suggestions on what to do here to dig into this further @DHowett? It is really making Terminal nearly impossible to use for development work.

@lhecker
Copy link
Member

lhecker commented May 12, 2025

If you have multiple PCs, does this issue also occur on your other machines? We sometimes get reports from people having a laggy experience, where it then turns out they have a corporate anti-virus installed. They can sometimes interfere with us processing the output in a timely manner.

Because the problem is that we have 1 mutex that protects the terminal state. That mutex gets acquired by the:

  • output / VT parser
  • text renderer
  • UI thread when selecting text

If any of the 3 take an unusually long time to process something, this would explain why you find it difficult to select text. Regarding each respective point:

  • That version of Windows Terminal can process VT somewhere in the order of 50-100MB/s depending on your CPU. The maximum chunk size for reading text is somewhere around 128KiB. Thus, the worst-case scenario is that the terminal freezes for ~3ms per read.
  • The text renderer is highly optimized for performance and should run at around 100 FPS on a low end mobile GPU. Only a part of that duration is spent holding the lock. I estimate it to be less than half the time, so let's say 5ms.
  • The UI thread only holds the lock to update the selection data, which takes somewhere around 10ns.

So, theoretically each location that holds the mutex should hold it for reasonably short periods of time. This means, even if you have tons of VT output, and slow text rendering going on simultaneously, you should still be able to select text fluidly. Something else must be going on (could also be another bug in Windows Terminal).

If it's simple for you to do so, could you please capture a screen recording of the issue? Just so we're all on the same page.

@compnerd
Copy link
Author

If you have multiple PCs, does this issue also occur on your other machines? We sometimes get reports from people having a laggy experience, where it then turns out they have a corporate anti-virus installed. They can sometimes interfere with us processing the output in a timely manner.

The only antivirus that I have installed is Windows Defender.

Because the problem is that we have 1 mutex that protects the terminal state. That mutex gets acquired by the:

  • output / VT parser
  • text renderer
  • UI thread when selecting text

If any of the 3 take an unusually long time to process something, this would explain why you find it difficult to select text. Regarding each respective point:

  • That version of Windows Terminal can process VT somewhere in the order of 50-100MB/s depending on your CPU. The maximum chunk size for reading text is somewhere around 128KiB. Thus, the worst-case scenario is that the terminal freezes for ~3ms per read.
  • The text renderer is highly optimized for performance and should run at around 100 FPS on a low end mobile GPU. Only a part of that duration is spent holding the lock. I estimate it to be less than half the time, so let's say 5ms.
  • The UI thread only holds the lock to update the selection data, which takes somewhere around 10ns.

So, theoretically each location that holds the mutex should hold it for reasonably short periods of time. This means, even if you have tons of VT output, and slow text rendering going on simultaneously, you should still be able to select text fluidly. Something else must be going on (could also be another bug in Windows Terminal).

If it's simple for you to do so, could you please capture a screen recording of the issue? Just so we're all on the same page.

I don't think that this is a rendering issue per se ... if you look at the log, there is a large number of CSI scroll events, so I suspect that it is unnecessarily adjusting the cursor position and view port for the text. This gives the impression of freezing as the cursor rehoming in a tight loop prevents the other operations from actually getting processed. Note that at the very end, the selected bounds are on the last frame while the text itself has scrolled out of the view port resulting in some arbitrary content being highlighted. I'll try to see if I can create a recording if you think that is more useful.

@DHowett
Copy link
Member

DHowett commented May 13, 2025

So, the ESC0D is a bit of a red herring. That's output from less after it receives SS3 D (where SS3 is ESC O.)

That is the correct and complete encoding for cursor left in Application Keys mode (DECCKM set).

In your tap trace, I see that less is requesting DECCKM with termcap ks (set $env:LESS_TERMCAP_DEBUG=1 to see it), so that checks out. This is just a symptom though.

As you've identified, something is generating an inordinate amount of input into your terminal session of the following two key events:

  • ␛[37;75;0;1;0;1_

    • Vk: VK_LEFT
    • Sc: 75
    • Uc: 0
    • Kd: down
    • Cs: 0
  • ␛[37;75;0;1;0;1_

    • Vk: VK_LEFT
    • Sc: 75
    • Uc: 0
    • Kd: up
    • Cs: 0

By my count, 8346 of them... which is consistent with your observed behavior.

There are three instances in which Terminal will emit ␛[37;75;0;1;0;1_ (in this specific format) into the input buffer:

  • You pressed the left arrow key.
  • Some software pressed the left arrow key on your behalf.
  • You've enabled the experimental "reposition cursor with click" feature.

Considering that there are ~8,300 combined left arrow presses and releases (4,173 presses), and that your tap contains a cursor position sequence indicating Y=47 X=35, I can only assume that your buffer is... let's conservatively guess 88x47.

That experimental feature works only on input lines and by literally trying to move the cursor left or right the same logical number of cells as appear to be occupied on the screen.

So, clicking somewhere in the top left of the screen will try to move the cursor left ~4,173 times.


I would say that we should disable the cursor repositioning feature when the alternate screen buffer is in use (as it is in less) but that would break tmux.

It's an experimental feature, though, so we can play with the heuristics a bit.

@DHowett
Copy link
Member

DHowett commented May 13, 2025

For now, though, try disabling it :)

@DHowett DHowett added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Attention The core contributors need to come back around and look at this ASAP. labels May 13, 2025
@compnerd
Copy link
Author

I tried to glance through the tap trace but wasn't able to really split up the sequences even with the python script.

So, the ESC0D is a bit of a red herring. That's output from less after it receives SS3 D (where SS3 is ESC O.)

That is the correct and complete encoding for cursor left in Application Keys mode (DECCKM set).

Agreed that the output of ESC0D is from less, but I'm not entirely sure if it is entirely a red herring. It is just a symptom, not the cause of course.

In your tap trace, I see that less is requesting DECCKM with termcap ks (set $env:LESS_TERMCAP_DEBUG=1 to see it), so that checks out. This is just a symptom though.

As you've identified, something is generating an inordinate amount of input into your terminal session of the following two key events:

  • ␛[37;75;0;1;0;1_

    • Vk: VK_LEFT
    • Sc: 75
    • Uc: 0
    • Kd: down
    • Cs: 0
  • ␛[37;75;0;1;0;1_

    • Vk: VK_LEFT
    • Sc: 75
    • Uc: 0
    • Kd: up
    • Cs: 0

By my count, 8346 of them... which is consistent with your observed behavior.

Yeah, this doesn't seem to be a processing speed thing but rather overloading the processing.

There are three instances in which Terminal will emit ␛[37;75;0;1;0;1_ (in this specific format) into the input buffer:

  • You pressed the left arrow key.
  • Some software pressed the left arrow key on your behalf.
  • You've enabled the experimental "reposition cursor with click" feature.

Ugh, I had completely forgotten about the experimental feature🤦

Considering that there are ~8,300 combined left arrow presses and releases (4,173 presses), and that your tap contains a cursor position sequence indicating Y=47 X=35, I can only assume that your buffer is... let's conservatively guess 88x47.

That experimental feature works only on input lines and by literally trying to move the cursor left or right the same logical number of cells as appear to be occupied on the screen.

Oh, interesting! Why the preference for the simplistic approach (move cursor backwards) rather than something like the CUP CSI? At this point, that is pretty widely supported (including by Terminal). I suppose that the problem would be with more complex text layout and trying to map the position to a cell?

So, clicking somewhere in the top left of the screen will try to move the cursor left ~4,173 times.

I would say that we should disable the cursor repositioning feature when the alternate screen buffer is in use (as it is in less) but that would break tmux.

It's an experimental feature, though, so we can play with the heuristics a bit.

Verified that the experimental "reposition cursor with click" is indeed responsible. Interestingly enough, I think that I've seen some similar issues without the alternate buffer mode, though that may be an unclean exit from less not fully resetting the terminal parser state.

Thanks for identifying the issue though @DHowett!

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs-Attention The core contributors need to come back around and look at this ASAP. and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels May 13, 2025
@DHowett
Copy link
Member

DHowett commented May 13, 2025

CUP CSI

So, the problem isn't one of getting the cursor position right inside terminal, it's communicating it to the shell. Moving the cursor ourselves is easy: we don't even need to write output for it. Moving it under the nose of the active line editor will, however, break that line editor terribly.

We have to let the shell in on the trick and get it to move the cursor so it can keep its document model in sync. Most such line editors are only expecting a handful of input sequences, and CUP is definitely not one of them. 🙂

This feature is a stopgap built to serve when shells don't have mouse support, so it has to make some assumptions. If we could write CUP and get shells to handle it, we could probably just get them to handle mouse input directly too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Bug It either shouldn't be doing this or needs an investigation. Needs-Attention The core contributors need to come back around and look at this ASAP. Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting
Projects
None yet
Development

No branches or pull requests

3 participants