wez / wezterm

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

tmux status line update makes beam cursor twitch & change animation step #2363

Closed scy closed 2 years ago

scy commented 2 years 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 20220805-075344-ef532fc7

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

I have a clock in my tmux status line that updates once per second. This apparently causes WezTerm’s cursor to either reset its blinking cycle, or do something else to produce a weird phasing issue which looks like the cursor is blinking in varying speeds.

What bugs me more than that, however, is that I have configured my (Neo)Vim to use an I-beam cursor in insert mode, and every once in a while it will flip back to being a block cursor for a frame or two, apparently also related to the update of the clock.

Here’s a one-minute GIF demonstrating both issues. I’ve gone into insert mode and typed a bunch of space characters so that the cursor and the seconds on the clock are near each other, to make it easier to see.

wezterm-beam-cursor-flicker

Not pictured: When I’m not in insert mode (and thus the cursor is a block), obviously it doesn’t change shape, but the animation step weirdness still occurs.

To Reproduce

My dotfiles at the time of writing are at https://codeberg.org/scy/dotfiles/src/commit/ec6d585d0319a1e26c34208080570dd289a9d475. The relevant tmux and Vim config:

set -g status-interval 1
set -g status-right "#h %Y-%m-%d %H:%M:%S"
if &term =~ "xterm" || &term =~ "screen" || &term =~ "tmux"
        let &t_SI = "\<Esc>[5 q" " start insert: blinking bar
        let &t_SR = "\<Esc>[3 q" " start replace: blinking underscore
        let &t_EI = "\<Esc>[1 q" " end insert/replace: blinking block
endif

Configuration

-- I don't see anything of relevance in here, but nevertheless, here's my config.

local wezterm = require 'wezterm'

return {
        -- Profiles
        default_prog = { 'wsl', '-d', 'Ubuntu', '--cd', '~' },  -- TODO put behind an OS check

        -- Window Size
        initial_cols = 180,
        initial_rows = 45,

        -- Font
        font = wezterm.font 'Iosevka Term',
        font_size = 10.5,
        harfbuzz_features = { 'calt=0', 'clig=0', 'liga=0' },  -- disable ligatures

        -- Colors & Translucency
        color_scheme = 'Sihaya',
        -- the following currently works on my Windows machine, I'll add others when required
        color_scheme_dirs = { 'C:\\Users\\scy\\dotfiles\\.config\\wezterm\\colors' },
        bold_brightens_ansi_colors = false,  -- don't keep me from having bold text
        window_background_opacity = 0.95,

        -- Tab Bar
        hide_tab_bar_if_only_one_tab = true,
        use_fancy_tab_bar = true,

        -- Visual Bell Only
        audible_bell = 'Disabled',
        visual_bell = {
                fade_in_duration_ms = 20,
                fade_out_duration_ms = 200,
                fade_in_function = 'Linear',
                fade_out_function = 'EaseOut',
        },

        -- Features
        enable_kitty_keyboard = true,  -- modernize keyboard input
}

Expected Behavior

The cursor should not change shape or move to another step in its blinking animation when it gets moved somewhere, I’d say.

I’ve seen in https://github.com/wez/wezterm/issues/83#issuecomment-569460626 that the current behavior was apparently on purpose (let the animation depend on when the cursor moved, not when a key was pressed), but maybe we should reconsider that.

Logs

Debug Overlay wezterm version: 20220805-075344-ef532fc7 OpenGL version: Intel(R) HD Graphics 630 4.5.0 - Build 27.20.100.8682 Enter lua statements or expressions and hit Enter. Press ESC or CTRL-D to exit 21:38:05.026 WARN wezterm_term::terminalstate > unhandled DecPrivateMode ResetDecPrivateMode(Unspecified(1005))

(I don't think the warning is related.)

Anything else?

No response

wez commented 2 years ago

I think the heart of this is that tmux is moving the cursor from where you expect it to be and changing its attributes non-atomically, so there is a race condition where the effects of tmux's additional rendering can be seen when a frame is rendered.

An additional complication: on Windows the ConPTY layer can also choose to repaint the entire screen in somewhat surprising situations, and exacerbate this sort of thing.

wezterm supports synchronized rendering which tmux could potentially use to minimize this kind of visual artifact.

I'm open to considering a PR that adds an option to control whether the cursor blink resets on movement or keyboard input, but I'm not sure that it will 100% solve this sort of thing.

Another option to consider: wezterm natively supports a good number of the functions of tmux, and you could replicate your tmux status bar using format-tab-title and window:set_right_status, and do so with the same monospace aesthetic by setting use_fancy_tab_bar = false.

scy commented 2 years ago

Thanks for getting back to me so fast.

An additional complication: on Windows the ConPTY layer can also choose to repaint the entire screen in somewhat surprising situations, and exacerbate this sort of thing.

I’ll be setting up a Linux machine with WezTerm in the coming days and will check whether the issue appears there as well.

wezterm supports synchronized rendering which tmux could potentially use to minimize this kind of visual artifact.

That’s good to know, thanks. I’ve searched through the tmux issues and couldn’t find one where they’re talking about synchronized rendering or 2026 or BSU, so I assume they don’t support it yet. However, this is a WSL1 machine running Ubuntu 18.04 and thus a relatively old version of tmux (2.6), maybe something has changed under the hood in more recent versions. I’ll try that out.

I'm open to considering a PR that adds an option to control whether the cursor blink resets on movement or keyboard input, but I'm not sure that it will 100% solve this sort of thing.

Well, you certainly know more about this than I do, but I still would consider it worth an experiment. However, my Rust skills are not (yet) good enough to write this myself.

Another option to consider: wezterm natively supports a good number of the functions of tmux, and you could replicate your tmux status bar using format-tab-title and window:set_right_status, and do so with the same monospace aesthetic by setting use_fancy_tab_bar = false.

Hm. Yeah, I know, and please don’t get me wrong, but I’m not ready for that yet. I’m using some Linux machines in text-only mode where tmux is the only multiplexer available to me, and I don’t want to get used to two different tools right now. ;)

There are two workarounds I’ve implemented to help with the issue:

cursor_blink_rate = 500,
cursor_blink_ease_in = 'Constant',
cursor_blink_ease_out = 'Constant',

The default blink rate of 800 was more prone to “phase mismatch”. Disabling the fade is not strictly required, but somehow it feels less irritating to me when a non-fading blink resets than a fading one. 🤷‍♂️

set -g status-interval 10

This just makes the problem appear 10 times less often … I’m not really happy with the clock updating less frequently though.

I’ve also investigated why this was never a problem in Windows Terminal: A quick

while sleep 0.1; do echo -n 'x'; done

reveals that Terminal indeed resets the blink animation on keypress, not on movement. (In Terminal, the cursor continues to blink in the normal rhythm while printing x characters. In WezTerm, printing an x causes the animation to restart, leading to basically a continuously lit up cursor.)

scy commented 2 years ago

I’ve done some more debugging. Turns out that on Windows Terminal, the animation resets appear, too, but I couldn’t notice the cursor changing to block shape for one or two frames. Maybe that’s why I didn’t notice it before.

Additionally, I’ve looked around in Terminal’s issues and came across one with similar symptoms. It has been suggested there (e.g. https://github.com/microsoft/terminal/issues/12313#issuecomment-1026955111) that tmux is handling the cursor in a sub-optimal way, but also that more recent versions of tmux don’t show the issue anymore.

I’ve upgraded tmux to 3.3a by building from source and the issue is completely gone, even without the workarounds from my previous comment. Yay!

I’ll leave this issue open in case you’re still interested in introducing a config option for whether movement or keypresses should reset the animation, but feel free to close it, my issue is solved.

Thanks again for the fast and elaborate response.

wez commented 2 years ago

Thanks also for your detailed investigation! Glad to hear you resolved this!

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.