Rightmost column of text is invisible on moar #22461

Closed
opened 2026-01-31 08:14:01 +00:00 by claunia · 19 comments
Owner

Originally created by @lapo-luchini on GitHub (Oct 27, 2024).

Windows Terminal version

1.21.2911.0

Windows build number

10.0.26120.0

Other Software

moar 1.27.2 installed via go install github.com/walles/moar@latest (issue 250 there)

Steps to reproduce

This happens both on WSL:

go install github.com/walles/moar@latest
seq -s '-' 10 99 | moar -wrap

and also on cmd:

go install github.com/walles/moar@latest
echo 10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-91-92-93-94-95-96-97-98-99 | moar -wrap

Expected Behavior

Line breaking at the end of the terminal width, continuing on next line:

┌────────────────────────┐ screen width
10-11-12-13-14-15-16-17-18
-19-20-21-22-23-24-25-26-2
7-28-29-30…

Actual Behavior

Last column is blank and is not shown:
e.g.

┌────────────────────────┐ screen width
10-11-12-13-14-15-16-17-1
-19-20-21-22-23-24-25-26-
7-28-29-30…
Originally created by @lapo-luchini on GitHub (Oct 27, 2024). ### Windows Terminal version 1.21.2911.0 ### Windows build number 10.0.26120.0 ### Other Software `moar` 1.27.2 installed via `go install github.com/walles/moar@latest` ([issue 250](https://github.com/walles/moar/issues/250) there) ### Steps to reproduce This happens both on WSL: ``` go install github.com/walles/moar@latest seq -s '-' 10 99 | moar -wrap ``` and also on cmd: ``` go install github.com/walles/moar@latest echo 10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-87-88-89-90-91-92-93-94-95-96-97-98-99 | moar -wrap ``` ### Expected Behavior Line breaking at the end of the terminal width, continuing on next line: ``` ┌────────────────────────┐ screen width 10-11-12-13-14-15-16-17-18 -19-20-21-22-23-24-25-26-2 7-28-29-30… ``` ### Actual Behavior Last column is blank and is not shown: e.g. ``` ┌────────────────────────┐ screen width 10-11-12-13-14-15-16-17-1 -19-20-21-22-23-24-25-26- 7-28-29-30… ```
claunia added the Resolution-By-DesignNeeds-TriageIssue-Bug labels 2026-01-31 08:14:01 +00:00
Author
Owner

@walles commented on GitHub (Oct 30, 2024):

FWIW, moar shows the last column of text fine on all tested non-ConPTY terminals.

Test results for moar showing the last column

  • Windows Terminal (on Windows)
  • VSCode terminal on Windows. On macOS, the VSCode terminal works fine.
  • VSCode terminal on macOS. On Windows, the VSCode terminal does not show the last column.
  • iTerm2 on macOS
  • macOS Terminal
  • Hyper on macOS
  • KiTTY on macOS
  • WezTerm on macOS
  • MobaXTerm on Windows: https://github.com/walles/moar/issues/250#issuecomment-2425914388
@walles commented on GitHub (Oct 30, 2024): FWIW, `moar` shows the last column of text fine on all tested non-ConPTY terminals. # Test results for `moar` showing the last column - ❌ Windows Terminal (on Windows) - ❌ VSCode terminal on Windows. On macOS, the VSCode terminal works fine. - ✅ VSCode terminal on macOS. On Windows, the VSCode terminal does not show the last column. - ✅ iTerm2 on macOS - ✅ macOS Terminal - ✅ Hyper on macOS - ✅ KiTTY on macOS - ✅ WezTerm on macOS - ✅ MobaXTerm on Windows: https://github.com/walles/moar/issues/250#issuecomment-2425914388
Author
Owner

@DHowett commented on GitHub (Oct 30, 2024):

This will be very helpful for a differential diagnosis:

Does moar work properly in WSL under Windows Terminal and VSCode?

If so: there's a chance that it has--or is using a library which has--Windows platform-specific code.

If it does, I suspect that it is--or that library is--using GetConsoleScreenBufferInfo(Ex) and treating srWindow as exclusive when it should be inclusive.

@DHowett commented on GitHub (Oct 30, 2024): This will be very helpful for a differential diagnosis: Does moar work properly _in WSL_ under Windows Terminal and VSCode? If so: there's a chance that it has--or is using a library which has--Windows platform-specific code. If it _does,_ I suspect that it is--or that library is--using `GetConsoleScreenBufferInfo(Ex)` and treating `srWindow` as exclusive when it should be inclusive.
Author
Owner

@zadjii-msft commented on GitHub (Oct 30, 2024):

Also,

  • Does it work in conhost.exe (not the Terminal)
  • Does it work on Terminal Preview (1.22+, where there was a bit of a rewite of ConPTY)
@zadjii-msft commented on GitHub (Oct 30, 2024): Also, * Does it work in `conhost.exe` (_not_ the Terminal) * Does it work on Terminal Preview (1.22+, where there was a bit of a rewite of ConPTY)
Author
Owner

@walles commented on GitHub (Oct 30, 2024):

If so: there's a chance that it has--or is using a library which has--Windows platform-specific code.

moar is using Go's term.GetSize() function, ending up in here: https://cs.opensource.google/go/x/term/+/refs/tags/v0.25.0:term_windows.go;l=48-54

func getSize(fd int) (width, height int, err error) {
	var info windows.ConsoleScreenBufferInfo
	if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
		return 0, 0, err
	}
	return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil
}

If it does, I suspect that it is--or that library is--using GetConsoleScreenBufferInfo(Ex) and treating srWindow as exclusive when it should be inclusive.

Let's say the window is 100 chars wide.

If moar thought the windows was 99 chars wide, moar would wrap too early.

But what's happening is that the last char on the line goes missing.

So I believe moar is getting the right information, it just fails to write chars to the last column (with ConPTY).

@DHowett ^

@walles commented on GitHub (Oct 30, 2024): > If so: there's a chance that it has--or is using a library which has--Windows platform-specific code. `moar` is using Go's `term.GetSize()` function, ending up in here: https://cs.opensource.google/go/x/term/+/refs/tags/v0.25.0:term_windows.go;l=48-54 ``` func getSize(fd int) (width, height int, err error) { var info windows.ConsoleScreenBufferInfo if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil { return 0, 0, err } return int(info.Window.Right - info.Window.Left + 1), int(info.Window.Bottom - info.Window.Top + 1), nil } ``` > If it _does,_ I suspect that it is--or that library is--using `GetConsoleScreenBufferInfo(Ex)` and treating `srWindow` as exclusive when it should be inclusive. Let's say the window is 100 chars wide. If `moar` thought the windows was 99 chars wide, `moar` would wrap too early. But what's happening is that the last char on the line goes missing. So I believe `moar` is getting the right information, it just fails to write chars to the last column (with ConPTY). @DHowett ^
Author
Owner

@DHowett commented on GitHub (Oct 30, 2024):

Ugh, I missed your comment about WSL earlier. I'm sorry.

@DHowett commented on GitHub (Oct 30, 2024): Ugh, I missed your comment about WSL earlier. I'm sorry.
Author
Owner

@DHowett commented on GitHub (Oct 30, 2024):

@zadjii-msft It reproduces in preview and canary, as well as conhost.

Image

Image

In both cases I used a block selection to highlight the rightmost edge.

@DHowett commented on GitHub (Oct 30, 2024): @zadjii-msft It reproduces in preview and canary, _as well as conhost_. ![Image](https://github.com/user-attachments/assets/b0765098-acbd-4c00-be89-65be0414dcd0) ![Image](https://github.com/user-attachments/assets/b8963ea5-1354-4ea4-af52-ae1554129da7) In both cases I used a block selection to highlight the rightmost edge.
Author
Owner

@DHowett commented on GitHub (Oct 30, 2024):

Got it!

This is what moar is printing to the console:

␛[1;1H␛[m␛[38;2;104;104;104m  1 ␛[38;2;208;208;208m10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48␛[m␛[K  ␛[m    ␛[38;2;208;208;208m-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-8␛[m␛[K  ␛[m    ␛[38;2;208;208;208m7-88-89-90-91-92-93-94-95-96-97-98-99␛[m␛[K  ␛[m␛[7m---␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[K  ␛[m␛[7m1 line  100%  Press 'ESC' / 'q' to exit, '/' to search, '?' for help                                                    ␛[m␛[K

Zooming in on the end of the first line (which is 46-47-48 in my case), I see this:

46-47-48␛[m␛[K  ␛[m
       |   |   \- space
       |   \- clear to end of line
       \- fill the rightmost column

By design, emitting a \e[K (EL 0 Erase to Right) when the cursor is in the deferred last column position clears the last column. 🙂

Now to figure out why moar is emitting \e[K in the deferred wrap position!

EDIT to add NOTE: this does not require ConPTY, and does not appear to be a ConPTY issue. This appears to be an application issue (at the moment.)

@DHowett commented on GitHub (Oct 30, 2024): _Got it!_ This is what `moar` is printing to the console: ``` ␛[1;1H␛[m␛[38;2;104;104;104m 1 ␛[38;2;208;208;208m10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40-41-42-43-44-45-46-47-48␛[m␛[K ␛[m ␛[38;2;208;208;208m-49-50-51-52-53-54-55-56-57-58-59-60-61-62-63-64-65-66-67-68-69-70-71-72-73-74-75-76-77-78-79-80-81-82-83-84-85-86-8␛[m␛[K ␛[m ␛[38;2;208;208;208m7-88-89-90-91-92-93-94-95-96-97-98-99␛[m␛[K ␛[m␛[7m---␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[K ␛[m␛[7m1 line 100% Press 'ESC' / 'q' to exit, '/' to search, '?' for help ␛[m␛[K ``` Zooming in on the end of the first line (which is `46-47-48` in my case), I see this: ``` 46-47-48␛[m␛[K ␛[m | | \- space | \- clear to end of line \- fill the rightmost column ``` By design, emitting a `\e[K` (`EL 0` `Erase to Right`) when the cursor is in the deferred last column position clears the last column. 🙂 Now to figure out why `moar` is emitting `\e[K` in the deferred wrap position! EDIT to add NOTE: this does not require ConPTY, and does not appear to be a ConPTY issue. This appears to be an application issue (at the moment.)
Author
Owner

@walles commented on GitHub (Oct 30, 2024):

By design, emitting a \e[K (EL 0 Erase to Right) when the cursor is in the deferred last column position clears the last column. 🙂

I will change this behavior in moar.

Out of curiosity, why this design? When all other terminals seem to handle this differently?

@walles commented on GitHub (Oct 30, 2024): > By design, emitting a `\e[K` (`EL 0` `Erase to Right`) when the cursor is in the deferred last column position clears the last column. 🙂 I will change this behavior in `moar`. Out of curiosity, why this design? When all other terminals seem to handle this differently?
Author
Owner

@walles commented on GitHub (Oct 30, 2024):

Now to figure out why moar is emitting \e[K in the deferred wrap position!

Instead of clearing the screen at the start of a redraw, moar clears to EOL after it's done with rendering all chars on that line.

The hope (not measured) is that this might avoid some flickering during redraws.

@walles commented on GitHub (Oct 30, 2024): > Now to figure out why `moar` is emitting `\e[K` in the deferred wrap position! Instead of clearing the screen at the start of a redraw, `moar` clears to EOL after it's done with rendering all chars on that line. The hope (not measured) is that this might avoid some flickering during redraws.
Author
Owner

@DHowett commented on GitHub (Oct 30, 2024):

Out of curiosity, why this design?

That's a good question, but I should note that xterm does the same thing:

Image

The former libvte (gnome-terminal et al) maintainer filed a bug on us requesting that we deviate from STD 070, and James--who I look to as the paragon of all terminal emulation knowledge--had this to say: https://github.com/microsoft/terminal/issues/3177#issuecomment-542158335

He followed up with #14936, which pertains only to the delayed wrap state and not the last column.

@DHowett commented on GitHub (Oct 30, 2024): > Out of curiosity, why this design? That's a good question, but I should note that xterm does the same thing: ![Image](https://github.com/user-attachments/assets/f9dcac0f-31a4-489e-abed-da53b5f8450f) The former libvte (gnome-terminal et al) maintainer filed a bug on us requesting that we deviate from STD 070, and James--who I look to as the paragon of all terminal emulation knowledge--had this to say: https://github.com/microsoft/terminal/issues/3177#issuecomment-542158335 He followed up with #14936, which pertains only to the delayed wrap state and not the last column.
Author
Owner

@DHowett commented on GitHub (Oct 30, 2024):

TL;DR: this is supported by standard behavior in either direction.

@j4james likely knows much more than I do about it. 🙂

@DHowett commented on GitHub (Oct 30, 2024): TL;DR: this is supported by standard behavior in either direction. @j4james likely knows much more than I do about it. 🙂
Author
Owner

@j4james commented on GitHub (Oct 30, 2024):

We've tried to follow the spec as closely as possible (documented in STD 070, pages D-13 and D-14). I think the only intentional deviation is with the tab control, where the behavior was changed in later DEC terminals (in that case we're matching the most recent DEC implementation, rather than the older spec definition).

I believe this is exactly the same behavior as XTerm, and last I checked, MLTerm and the Linux console were also following the spec quite closely. We're definitely not the only terminal that handles EL this way. So if you're seeing something different in XTerm, it's probably worth investigating whether there is some other factor involved.

@j4james commented on GitHub (Oct 30, 2024): We've tried to follow the spec as closely as possible (documented in STD 070, pages D-13 and D-14). I think the only intentional deviation is with the tab control, where the behavior was changed in later DEC terminals (in that case we're matching the most recent DEC implementation, rather than the older spec definition). I believe this is exactly the same behavior as XTerm, and last I checked, MLTerm and the Linux console were also following the spec quite closely. We're definitely not the only terminal that handles `EL` this way. So if you're seeing something different in XTerm, it's probably worth investigating whether there is some other factor involved.
Author
Owner

@DHowett commented on GitHub (Oct 30, 2024):

Thanks!

And with that, I'll close this one as By Design.

@DHowett commented on GitHub (Oct 30, 2024): Thanks! And with that, I'll close this one as By Design.
Author
Owner

@DHowett commented on GitHub (Oct 30, 2024):

(Also, I think I need to install moar on all of my machines so thank you for that)

@DHowett commented on GitHub (Oct 30, 2024): (Also, I think I need to install `moar` on all of my machines so thank you for that)
Author
Owner

@o-sdn-o commented on GitHub (Oct 30, 2024):

It seems to me that with such a design, a console application that outputs via a serial port and has no way to track the size of the terminal will inevitably periodically lose the last character. Moreover, with a terminal size of 1xN, the last character will always be lost.

@o-sdn-o commented on GitHub (Oct 30, 2024): It seems to me that with such a design, a console application that outputs via a serial port and has no way to track the size of the terminal will inevitably periodically lose the last character. Moreover, with a terminal size of 1xN, the last character will always be lost.
Author
Owner

@DHowett commented on GitHub (Oct 31, 2024):

@o-sdn-o Literal serial terminals act like this, so.

@DHowett commented on GitHub (Oct 31, 2024): @o-sdn-o Literal serial terminals act like this, so.
Author
Owner

@walles commented on GitHub (Oct 31, 2024):

if you're seeing something different in XTerm

I haven't tried XTerm, but I did produce this list (before I just changed moar's behavior):

Test results for moar showing the last column

  • Windows Terminal (on Windows)
  • VSCode terminal on Windows. On macOS, the VSCode terminal works fine.
  • VSCode terminal on macOS. On Windows, the VSCode terminal does not show the last column.
  • iTerm2 on macOS
  • macOS Terminal
  • Hyper on macOS
  • KiTTY on macOS
  • WezTerm on macOS
  • MobaXTerm on Windows: https://github.com/walles/moar/issues/250#issuecomment-2425914388

I do appreciate the thorough response!

@walles commented on GitHub (Oct 31, 2024): > if you're seeing something different in XTerm I haven't tried XTerm, but I did produce this list (before I just changed `moar`'s behavior): # Test results for `moar` showing the last column - ❌ Windows Terminal (on Windows) - ❌ VSCode terminal on Windows. On macOS, the VSCode terminal works fine. - ✅ VSCode terminal on macOS. On Windows, the VSCode terminal does not show the last column. - ✅ iTerm2 on macOS - ✅ macOS Terminal - ✅ Hyper on macOS - ✅ KiTTY on macOS - ✅ WezTerm on macOS - ✅ MobaXTerm on Windows: https://github.com/walles/moar/issues/250#issuecomment-2425914388 I do appreciate the thorough response!
Author
Owner

@o-sdn-o commented on GitHub (Oct 31, 2024):

With this design, supporting the \e[K command is completely pointless. Applications that can track the terminal size can easily erase the rest of the line using spaces, and this will be even more efficient. Other applications cannot rely on this vt-command at all because of the risk of losing the last character.

@o-sdn-o commented on GitHub (Oct 31, 2024): With this design, supporting the `\e[K` command is completely pointless. Applications that can track the terminal size can easily erase the rest of the line using spaces, and [this will be even more efficient](https://github.com/microsoft/terminal/discussions/18072#discussioncomment-10986314). Other applications cannot rely on this vt-command at all because of the risk of losing the last character.
Author
Owner

@j4james commented on GitHub (Oct 31, 2024):

@o-sdn-o It's worked this way for more than 40 years - I think it's a little late to decide you don't like the design. But if you want to invent a new protocol, maybe propose something on terminal-wg.

@j4james commented on GitHub (Oct 31, 2024): @o-sdn-o It's worked this way for more than 40 years - I think it's a little late to decide you don't like the design. But if you want to invent a new protocol, maybe propose something on terminal-wg.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#22461