Skip to content
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

Text Wrapping with ConPTY #405

Closed
davidhewitt opened this issue Apr 2, 2019 · 27 comments · Fixed by #4415
Closed

Text Wrapping with ConPTY #405

davidhewitt opened this issue Apr 2, 2019 · 27 comments · Fixed by #4415
Assignees
Labels
Area-Interaction Interacting with the vintage console window (as opposed to driving via API or hooks) Area-Interop Communication between processes Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Priority-1 A description (P1) Product-Conpty For console issues specifically related to conpty Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. Work-Item It's being tracked by an actual work item internally. (to be removed soon)
Milestone

Comments

@davidhewitt
Copy link

It seems to me that output is line-wrapped by conhost before being sent through the ConPTY stdout pipe. This makes sense, though it has the unfortunate downside that in Alacritty we can't do the line-wrapping ourselves.

This wouldn't matter that much, but when selecting and copying text in Alacritty which has been line-wrapped by conhost, Alacritty isn't aware that the text was originally a single line and inserts a newline into the content placed on the clipboard.

Is it possible to disable the line wrapping by conhost?

(Perhaps this would be something that would naturally be in the "passthrough" mode I've seen mentioned elsewhere in this issue tracker?)

@zadjii-msft
Copy link
Member

I'm sure there's another issue tracking this lying around somewhere...

There was actually a prototype of doing this for a few insider's builds but that caused some other regressions in behavior late in RS5. (For internal reference, see task 16485846 and bug 18123777).

This is definitely something we need to figure out how to get right.

@zadjii-msft zadjii-msft added Product-Conpty For console issues specifically related to conpty Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Work-Item It's being tracked by an actual work item internally. (to be removed soon) labels Apr 3, 2019
@zadjii-msft zadjii-msft self-assigned this Apr 3, 2019
@zadjii-msft zadjii-msft added this to the Backlog milestone Apr 3, 2019
@davidhewitt
Copy link
Author

Thanks for the notes!

I did have a search for an existing issue before opening though didn't spot one. Please do close this issue if a duplicate turns up!

@jzabroski
Copy link

Interesting. This feature request dovetails nicely with my recent remarks on MSBuild supporting colors but intermediary programs like PowerShell blocking colors: dotnet/msbuild#4299

I am still wrapping my head around all of this, so apologies to those who don't see the same connection I see, which is that API consumers don't control output, API providers do. I think this is a fundamental problem.

@ghost ghost added the Needs-Tag-Fix Doesn't match tag requirements label May 17, 2019
@miniksa miniksa added Area-Interaction Interacting with the vintage console window (as opposed to driving via API or hooks) Area-Interop Communication between processes and removed Mass-Chaos labels May 17, 2019
@ghost ghost removed the Needs-Tag-Fix Doesn't match tag requirements label May 18, 2019
@Tyriar
Copy link
Member

Tyriar commented May 31, 2019

This is one of the major issues VS Code has with ConPTY as we have to guess which lines wrap (based on a naive heuristic) to try to avoid issues like microsoft/vscode#43664

@ExE-Boss
Copy link

ExE-Boss commented May 31, 2019

@Tyriar Well, that heuristic doesn’t work well at all with a PowerLine prompt that has right‑aligned blocks.

Also, are you sure you didn’t mean to say WinPTY? Because that is what the comment in the linked code mentions.

@Tyriar
Copy link
Member

Tyriar commented May 31, 2019

@ExE-Boss its primary uses are link detection and error detection so that doesn't matter too much. Problems arise for example when errors have unfortunately placed spaces at the end of a wrapped line, leading to flaky detection.

@Tyriar
Copy link
Member

Tyriar commented May 31, 2019

winpty acts in the same way as conpty, the workaround is for both.

@wolf99
Copy link
Contributor

wolf99 commented Oct 1, 2019

Per microsoft/vscode#81328, this is breaking problem matchers in VS Code in the case where the user has not already opened the terminal.

@jzabroski
Copy link

API Consumers need to control output formatting, not API Producers.

@zadjii-msft
Copy link
Member

Okay, we're not disagreeing that this should be fixed. However, no one on the team has had the time to get to it quite yet. If a particularly passionate community member is interested in contributing, we'd be happy to review a PR.

@Biswa96
Copy link

Biswa96 commented Oct 1, 2019

Which source file or project or function handle the text wrapping in normal CMD + ConHost combo?

@zadjii-msft
Copy link
Member

@Biswa96 this is probably less about the wrapping within conhost itself, but more about how ConPTY renders wrapped text. I'd probably take a look at XtermEngine::PaintBufferLine, which is where conpty draws a particular run of text. Currently, whenever we reach the end of a line, we're always going to emit a \n to move the cursor to the next line. We probably shouldn't, because that's causing hard line breaks.

In my original prototype, I believe I added a flag wasWrapped, which the Renderer passes to the various IRenderEngines, including the VtEngines. What we'd need to do is make sure that when a run of text is painted that was wrapped, we don't move the cursor (with _MoveCursor) immediately following that. Instead, we should just assume the subsequent text we need to render was on the next line.

@ghost ghost closed this as completed in #4415 Feb 27, 2020
@ghost ghost added Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. and removed In-PR This issue has a related PR labels Feb 27, 2020
ghost pushed a commit that referenced this issue Feb 27, 2020
## Summary of the Pull Request

Changes how conpty emits text to preserve line-wrap state, and additionally adds rudimentary support to the Windows Terminal for wrapped lines.

## References

* Does _not_ fix (!) #3088, but that might be lower down in conhost. This makes wt behave like conhost, so at least there's that
* Still needs a proper deferred EOL wrap implementation in #780, which is left as a todo
* #4200 is the mega bucket with all this work
* MSFT:16485846 was the first attempt at this task, which caused the regression MSFT:18123777 so we backed it out.
* #4403 - I made sure this worked with that PR before I even sent #4403

## PR Checklist
* [x] Closes #405
* [x] Closes #3367 
* [x] I work here
* [x] Tests added/passed
* [n/a] Requires documentation to be updated

## Detailed Description of the Pull Request / Additional comments

I started with the following implementation:
When conpty is about to write the last column, note that we wrapped this line here. If the next character the vt renderer is told to paint get is supposed to be at the start of the following line, then we know that the previous line had wrapped, so we _won't_ emit the usual `\r\n` here, and we'll just continue emitting text.

However, this isn't _exactly_ right - if someone fills the row _exactly_ with text, the information that's available to the vt renderer isn't enough to know for sure if this line broke or not. It is possible for the client to write a full line of text, with a `\n` at the end, to manually break the line. So, I had to also add the `lineWrapped` param to the `IRenderEngine` interface, which is about half the files in this changelist.

## Validation Steps Performed
* Ran tests
* Checked how the Windows Terminal behaves with these changes
* Made sure that conhost/inception and gnome-terminal both act as you'd expect with wrapped lines from conpty
@Tyriar
Copy link
Member

Tyriar commented Feb 27, 2020

@zadjii-msft in what Windows version should this be expected? I think I'll need to disable the special compatibility mode in VS Code that guesses wrapped lines based on the build number.

@DHowett-MSFT
Copy link
Contributor

@Tyriar the version what comes after 19041.

@davidhewitt
Copy link
Author

Thanks very much! Thrilled to see this. I guess until stable release I'll also be able to enjoy it on insiders ;)

DHowett-MSFT pushed a commit that referenced this issue Mar 13, 2020
This PR adds support for "Resize with Reflow" to the Terminal. In
conhost, `ResizeWithReflow` is the function that's responsible for
reflowing wrapped lines of text as the buffer gets resized. Now that
#4415 has merged, we can also implement this in the Terminal. Now, when
the Terminal is resized, it will reflow the lines of it's buffer in the
same way that conhost does. This means, the terminal will no longer chop
off the ends of lines as the buffer is too small to represent them. 

As a happy side effect of this PR, it also fixed #3490. This was a bug
that plagued me during the investigation into this functionality. The
original #3490 PR, #4354, tried to fix this bug with some heavy conpty
changes. Turns out, that only made things worse, and far more
complicated. When I really got to thinking about it, I realized "conhost
can handle this right, why can't the Terminal?". Turns out, by adding
resize with reflow, I was also able to fix this at the same time.
Conhost does a little bit of math after reflowing to attempt to keep the
viewport in the same relative place after a reflow. By re-using that
logic in the Terminal, I was able to fix #3490.

I also included that big ole test from #3490, because everyone likes
adding 60 test cases in a PR.

## References
* #4200 - this scenario
* #405/#4415 - conpty emits wrapped lines, which was needed for this PR
* #4403 - delayed EOL wrapping via conpty, which was also needed for
  this
* #4354 - we don't speak of this PR anymore

## PR Checklist
* [x] Closes #1465
* [x] Closes #3490
* [x] Closes #4771
* [x] Tests added/passed

## EDIT: Changes to this PR on 5 March 2020

I learned more since my original version of this PR. I wrote that in
January, and despite my notes that say it was totally working, it
_really_ wasn't.

Part of the hard problem, as mentioned in #3490, is that the Terminal
might request a resize to (W, H-1), and while conpty is preparing that
frame, or before the terminal has received that frame, the Terminal
resizes to (W, H-2). Now, there aren't enough lines in the terminal
buffer to catch all the lines that conpty is about to emit. When that
happens, lines get duplicated in the buffer. From a UX perspective, this
certainly looks a lot worse than a couple lost lines. It looks like
utter chaos.

So I've introduced a new mode to conpty to try and counteract this
behavior. This behavior I'm calling "quirky resize". The **TL;DR** of
quirky resize mode is that conpty won't emit the entire buffer on a
resize, and will trust that the terminal is prepared to reflow it's
buffer on it's own.

This will enable the quirky resize behavior for applications that are
prepared for it. The "quirky resize" is "don't `InvalidateAll` when the
terminal resizes". This is added as a quirk as to not regress other
terminal applications that aren't prepared for this behavior
(gnome-terminal, conhost in particular). For those kinds of terminals,
when the buffer is resized, it's just going to lose lines. That's what
currently happens for them.  

When the quirk is enabled, conpty won't repaint the entire buffer. This
gets around the "duplicated lines" issue that requesting multiple
resizes in a row can cause. However, for these terminals that are
unprepared, the conpty cursor might end up in the wrong position after a
quirky resize.

The case in point is maximizing the terminal. For maximizing
(height->50) from a buffer that's 30 lines tall, with the cursor on
y=30, this is what happens: 

  * With the quirk disabled, conpty reprints the entire buffer. This is
    60 lines that get printed. This ends up blowing away about 20 lines
    of scrollback history, as the terminal app would have tried to keep
    the text pinned to the bottom of the window. The term. app moved the
    viewport up 20 lines, and then the 50 lines of conpty output (30
    lines of text, and 20 blank lines at the bottom) overwrote the lines
    from the scrollback. This is bad, but not immediately obvious, and
    is **what currently happens**. 


  * With the quirk enabled, conpty doesn't emit any lines, but the
    actual content of the window is still only in the top 30 lines.
    However, the terminal app has still moved 20 lines down from the
    scrollback back into the viewport. So the terminal's cursor is at
    y=50 now, but conpty's is at 30. This means that the terminal and
    conpty are out of sync, and there's not a good way of re-syncing
    these. It's very possible (trivial in `powershell`) that the new
    output will jump up to y=30 override the existing output in the
    terminal buffer. 

The Windows Terminal is already prepared for this quirky behavior, so it
doesn't keep the output at the bottom of the window. It shifts it's
viewport down to match what conpty things the buffer looks like.

What happens when we have passthrough mode and WT is like "I would like
quirky resize"? I guess things will just work fine, cause there won't be
a buffer behind the passthrough app that the terminal cares about. Sure,
in the passthrough case the Terminal could _not_ quirky resize, but the
quirky resize won't be wrong.
@aytey
Copy link

aytey commented Apr 21, 2021

@davidhewitt in case you're interested, I implemented the xterm.js (== VS Code) "naïve heuristic" in Alacritty here:

This change resolves the issue with copying (e.g.,) ~/.ssh/id_rsa.pub but also preserves the newlines when copying files that do have genuine \n (e.g., cat ~/.zshrc).

@wesley800
Copy link

wesley800 commented Nov 25, 2022

@DHowett-MSFT Hi, I wonder if the fix (#4415) applies to conhost.exe on Windows newer than 19041? I've tested it on 19044 with ConPty APIs, and got \r\ns between segments of wrapped lines (output by sending echo LONG...LINE\r to powershell). I've placed my test code snippet at https://github.com/wesley800/rust-conpty-test .

I've briefly checked the code of #4415 and it seems that all changes relates to the WindowsTerminal part, rather than the conhost part. But I'm not familar with the whole architecture of the source tree. So if it does changed the behaviour of conhost, what sould I do if I want to decide whether a line is wrapped, or just happens to holds a line with same width to the window and a following hard break?

Actually this is from alacritty/alacritty#2093 . I also tested with latest alacritty on 19044 and found it still gives breaked lines when copying content from the window, such as ssh public keys.

Update: this seems to be already fix on Win11. Output files are attached to https://github.com/wesley800/rust-conpty-test/tree/master/output .

Update2: A pre-compiled binary is added to the repo for those not familiar with rust toolchain.

@aytey
Copy link

aytey commented Nov 27, 2022

@wesley800:

Update: this seems to be already fix on Win11. Output files are attached to https://github.com/wesley800/rust-conpty-test/tree/master/output .

How did you perform this test? Just using a latest Alacritty build on stock Windows 11? What version of Windows 11?

@wesley800
Copy link

wesley800 commented Nov 27, 2022

How did you perform this test? Just using a latest Alacritty build on stock Windows 11? What version of Windows 11?

I don't know, probably the latest one. I don't have access to that machine in fact. I've confirmed that both latest Alacritty and rust-conpty-test shows no CR or LF at line wrapping points.

@wesley800
Copy link

@zadjii-msft In case no one is still watching this issue...

@zadjii-msft
Copy link
Member

Sorry, still catching up on mail after the holidays.

I'd assume just based on the dates that #4415 would be in at least 19042 - it's at around this point in time that tracking code changes across win10 versions vs win11 versions starts getting a little more confusing... I can try and drill in and find where the commit to the OS repo is, but this should definitely be in 19044 and Windows 11, that I'm sure of.

That code change is mostly a Conhost / ConPTY change - the bulk of the real change is in the VT renderer, which is what conpty uses to write the buffer to a connected terminal application[1]

We do have a number of ongoing issues with line wrapping across the repo. #6901 (comment) has a collection of issues we've been seeing. It's hard to tease those apart to individual root causes, unfortunately. My headcannon is that there's some renderer state that's not getting set/reset correctly, resulting in the incorrectness of it all, but it's been hard to get exact repros.

Maybe there's something to do with the volume of text written in a single frame? hard to say.

[1] this is a vast oversimplification for the sake of brevity.

@wesley800
Copy link

Thank you for your time and detailed replies to my each question and hope I didn't break your vacation much.

Actually I ran the test on Win10 LTSC 2022 which is 19044 by winver but don't know if the SKU matters.

Also I might be wrong in the expectation of #4415, which seems to be mainly focused on rendering (as you've stated). From my perspective, changes are mostly among adding lineWrapped flag into the state storage of ConPty, but nowhere relating to dismiss the "fake" line breaks at line wrapping points when ConPty writes to it's output pipe. I assume that's because I have not complete insight of the whole repo though.

@zadjii-msft
Copy link
Member

zadjii-msft commented Dec 7, 2022

hope I didn't break your vacation much

Nah it's fine, I'm just still slow coming back off paternity and only working like, half time. It's generally the holidays, so things are just slow here 😅 sorry for any delays!


You might have something here. We should probably take a look through the history here. Why is performedSoftWrap never used? #5181 might be relevant here.

I'll need to double tap on this.


That also being said - it looks like on windows 11 the test works fine? Perhaps the fixes I'm thinking of didn't actually land till 22000. This might just be another point in favor of having a proper ConPTY nuget package, that folks can use to consume the updated ConPTY version (regardless of OS version).

@std-move
Copy link

std-move commented Jul 14, 2023

@zadjii-msft Any chance this could get fixed in Win10 19044/19045? The regular editions are supported at least till 2025-10-14, with IoT Enterprise LTSC (for which volume licencing is newly available) supported until 2032-01-13.

It seems like a bug that should be fixed as part of a cumulative update.

@DHowett
Copy link
Member

DHowett commented Jul 14, 2023

It seems like a bug that should be fixed as part of a cumulative update.

I agree with you! Unfortunately, the Windows organization doesn't necessarily agree. Changes like this -- especially ones that are in vanishingly rare cases that come with a high likelihood of destabilizing a working product -- are very difficult to get into a servicing update without a strong "business justiciation."

The way we're tackling getting ConPTY bug fixes out to people on a quicker cadence than Windows releases is over in #15065: a NuGet package for folks to depend upon. 😄

@Walms
Copy link

Walms commented Jun 20, 2024

It seems like a bug that should be fixed as part of a cumulative update.

I agree with you! Unfortunately, the Windows organization doesn't necessarily agree. Changes like this -- especially ones that are in vanishingly rare cases that come with a high likelihood of destabilizing a working product -- are very difficult to get into a servicing update without a strong "business justiciation."

The way we're tackling getting ConPTY bug fixes out to people on a quicker cadence than Windows releases is over in #15065: a NuGet package for folks to depend upon. 😄

I'm hitting problems using the Alacritty terminal. alacritty/alacritty#4993

Is there anyway I can get the latest version to make that bug go away?

@j4james
Copy link
Collaborator

j4james commented Jun 20, 2024

Is there anyway I can get the latest version to make that bug go away?

There's an invisible entry in the Alacritty FAQ that explains what you need to do.

And if you search the Alacritty repo for conpty.dll openconsole.exe you'll find several comments from users explaining how they've got it to work. Here is one recent example: alacritty/alacritty#6704 (comment)

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Interaction Interacting with the vintage console window (as opposed to driving via API or hooks) Area-Interop Communication between processes Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Priority-1 A description (P1) Product-Conpty For console issues specifically related to conpty Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. Work-Item It's being tracked by an actual work item internally. (to be removed soon)
Projects
None yet
Development

Successfully merging a pull request may close this issue.