wez / wezterm

A GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust
https://wezfurlong.org/wezterm/
Other
17.84k stars 799 forks source link

tmux: ambiguous double width / single width characters rendered differently under tmux #3704

Closed michaelrommel closed 1 year ago

michaelrommel commented 1 year ago

What Operating System(s) are you seeing this problem on?

Windows

Which Wayland compositor or X11 Window manager(s) are you using?

No response

WezTerm version

wezterm 20230411-221643-c8b8e811

Did you try the latest nightly build to see if the issue is better (or worse!) than your current version?

Yes, and I updated the version box above to show the version of the nightly that I tried

Describe the bug

When run under tmux, ambiguous characters sometimes lead to shifted lines. Ironically, the same combination of tmux with other terminal emulators runs fine, I am starting the terminal emulator under Windows, but connect to a Debian WSL2 instance:

The setting config.allow_square_glyphs_to_overflow_width = "Never" or "Always" does not make any difference, the screen output is absolutely identical. The symbols are 3 byte UTF8 characters, e.g. 0xf529.

What I have already tried:

I am now at a loss, especially because it is only the combination of tmux and wezterm that shows this behaviour.

The following picture shows at the top neovim run in a tmux session, the lower screenshot is when it is run in wezterm with no tmux session.

image

To Reproduce

A minimal example is not easy to create. The issue is apparent in neovim with settings like diagnostics symbols and pyright as language grammar checker etc. My dotfiles are at https://github.com/michaelrommel/dotfileshttps://github.com/michaelrommel/dotfiles the neovim config is under .config/miro/. Also I could not use the record feature of wezterm. It always starts the windows command prompt and not the default "WSL:bullseye" domain.

Configuration

The relevant wezterm configuration:

config.treat_east_asian_ambiguous_width_as_wide = false
config.unicode_version = 9
-- config.normalize_output_to_unicode_nfc = true
-- config.allow_square_glyphs_to_overflow_width = "Always"
config.allow_square_glyphs_to_overflow_width = "Never"

The relevant tmux configuration:

# not relevant for this windows bug...
if-shell '[ "$(uname -o)" = "Darwin" ]' {
  set -g default-terminal "tmux-256color"
}
set-option -sa terminal-features ',xterm-256color:RGB'

Expected Behavior

I would have liked the layout shift to disappear.

Logs

Debug Overlay wezterm version: 20230411-221643-c8b8e811 x86_64-pc-windows-msvc Window Environment: Windows OpenGL version: Quadro T2000 with Max-Q Design/PCIe/SSE2 4.5.0 NVIDIA 443.64 Enter lua statements or expressions and hit Enter. Press ESC or CTRL-D to exit

Anything else?

No response

michaelrommel commented 1 year ago

Since there is some cross dependency between wezterm and tmux for the bug to appear, maybe @nicm (Nicholas Marriott) can contribute his insights. I have tried to follow and rule out issues he identified in other bugs, like to minimize the compile time variations and tried to have the same view on unicode data, by compiling all with the bullseye libutf8proc library, setting all to UTF-8 and tried to configure all applications to treat ambiguous chars as narrow (the ambiwidth option in neovim is set to "single").

nicm commented 1 year ago

What is the Unicode codepoint?

wez commented 1 year ago

Please capture a terminal recording:

*** Finished recording to /var/tmp/wezterm-recording-sF6B3u.cast.txt

The file is an asciicast (compatible with https://asciinema.org/) and can also be replayed using wezterm replay.

The terminal recording allows me to replicate what is being sent to the terminal without requiring me to install the same applications as you and replicate your configuration for everything.

wez commented 1 year ago

Do you experience the same issue if you set unicode_version = 14 (or unicode_version=8)?

Note that that option affects how output is parsed as it is received, and doesn't take effect retroactively, so if you change it, you will need to force the screen to be repainted to wezterm, or just restart your reproduction scenario.

wez commented 1 year ago

For the screen recording, it may be interesting to capture one with tmux and one without tmux so that we can compare them

michaelrommel commented 1 year ago

Hi thanks a lot for the quick responses!

@nicm: the codepoint of the warning triangle used is in the private area, 0xf002a

@wez: the strange thing is, that whenever I record, then the issue also occurs in plain wezterm without tmux. With tmux there is then one additional character offset. You can see that at the colored line, which should appear at column 60

I have recorded it now with and without tmux in 80x24 resolution, but that is slightly too narrow, the tmux status line is then slightly distorted. So I recorded it also with 90x21.

All have been recorded with unicode_version = 9.

What I checked now, is that neovim thinks the character width of this particular character is 1. Checked with

:lua print(vim.fn.strwidth('󰀪'))

The font used in the terminal is a Nerd Font based on Victor Mono, it is here: https://github.com/michaelrommel/dotfiles/tree/master/.local/share/fonts

wezterm-recording-8024-notmux.cast.txt wezterm-recording-8024-tmux.cast.txt wezterm-recording-notmux.cast.txt wezterm-recording-tmux.cast.txt

Why now the issue also occurs without tmux in the recording mode, I have no idea.

michaelrommel commented 1 year ago

There is no difference with unicode 8 or 14 as setting: wezterm-recording-unicode8.cast.txt wezterm-recording-unicode14.cast.txt

michaelrommel commented 1 year ago

I have now also tried to inform neovim about a different character width just for the warning triangle by using:

fn.setcellwidths({
        { 0xf002a, 0xf002a, 2 }
})

This makes a difference, where the closing quote in the code shows, but otherwise the same issues still occur.

wezterm-recording-neovim-widthoverride.cast.txt

nicm commented 1 year ago

tmux will assume all PUA are width 1 with utf8proc or any non-C0 codepoint where wcwidth fails to be width 1 with libc.

michaelrommel commented 1 year ago

tmux will assume all PUA are width 1 with utf8proc or any non-C0 codepoint where wcwidth fails to be width 1 with libc.

I am trying to follow... What is a non-C0 codepoint? Does that mean, that tmux thinks it had advanced the cursor on column, whereas in reality it was advanced two columns and therefore the offset of that coloured column occurs, but when absolute cursor positioning escape codes are used the positioning would be correct?

If this is true, then there is no way to fix this, right, because there is no way to inform tmux about character widths. So we can use characters with width 2 only on codepoints, where their widths are already defined as 2 in the Unicode Character Database.

It is just strange, that other terminals like wsltty can somehow cope with that but also only partially. It seems wsltty shows the full glyph only when a space character or empty cell follows. Otherwise it is rendered full height, but is cut off.

image

nicm commented 1 year ago

Correct, you can only use width 2 codepoints where either:

If tmux's, the application's and the terminal's ideas of the width do not match, you will see cursor positioning errors.

C0 are control characters so they are invisible.

wez commented 1 year ago

I haven't had a chance to really dive in here, but wanted to note that wezterm considers that codepoint to have width 1; you can this out using the debug overlay (CTRL-SHIFT-L):

> wezterm.column_width('\u{f002a}')
1
wez commented 1 year ago

Something else to consider here: on Windows, you have a "hidden" other terminal emulation layer that can rewrite the output from tmux or whatever applications are running inside WSL, before it is received by wezterm: ConPTY.

https://wezfurlong.org/wezterm/what-is-a-terminal.html#windows-and-conpty has more information about this.

I'd suggest trying to bypass ConPTY to see if it might be influencing what you are seeing. The easiest way to do that is to start an SSH server inside your WSL instance, then use wezterm ssh to connect to it: wezterm's built-in ssh client doesn't need to use ConPTY.

michaelrommel commented 1 year ago

Hi Wez,

thank you, I can confirm, that when using the ssh method to connect to the WSL instance, the issue is gone:

image

I am going to close the issue now. Is there a way to let the built-in ssh client use the Windows supplied OpenSSH Agent, which holds my keys and forward this agent?

Thanks again, was tearing my hair out with all the interdependencies between the settings. But on the other hand I kinda have to admit that I enjoy this stuff a little bit, because every time I learn something from it. Although, when I retire in 3.5 years, I will not miss Windows...

Michael.

wez commented 1 year ago

re: ssh agent, wezterm reads your ssh config in the same way that openssh does, so if you have enabled the agent there via IdentityAgent, or have SSH_AUTH_SOCK set in the environment, wezterm should use it.

michaelrommel commented 1 year ago

I tried that, but on Windows that doesn't work. The windows port they provide uses a named pipe at \.\pipe\openssh-ssh-agent, but any standard ssh library cannot use that. There exists a program called npiperelay, that can convert with the help of socat the named pipe into a unix socket. I use this once I am logged into the WSL to connect back to that socket and from there on I can use this as authentication agent for further connections. It is only the first authentication now that is a bit cumbersome. I guess I will create just a new identity now for the purpose of using ssh between the Windows side and the WSL side locally on that machine.

michaelrommel commented 1 year ago

@wez One last question: does it make sense to investigate this behaviour with conpty/conhost/openconsole further and maybe open a bug at microsoft/terminal where this is being developed? Or is that helper something that is only officially maintained with their terminal application?

wez commented 1 year ago

@michaelrommel the folks that maintain conpty are pretty good at triaging and keep folks informed about bug reports, so I'd say, yeah, if you have a repro scenario for something in conpty, please report it to them!

I want to note that I recently updated the version of conpty included in nightly builds of wezterm, so it may be worth giving that a try first to see if they fixed something before reporting an issue to them.

lostl1ght commented 1 year ago

With updated ConPTY it looks like the issue is gone, thank you.

michaelrommel commented 1 year ago

I can confirm that, too. The issue disappeared in the latest Nightly Release. Thanks a lot!!

github-actions[bot] commented 1 year ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.