The idea here is to make it a bit easier to do hit detection for UI
elements; today we've been duplicating position math between the render
and the mouse movement handlers, with both pieces of code knowing the
location of the UI element.
UIItem allows the render phase to record the position, which allows
the mouse phase to be a more independent lookup against the registered
elements.
This makes it easier to add more UI elements in the future.
If a cell contained a ligature, the math used to track where the
next quad was going to be placed could lose consistency with
the cluster/shaping information and result in offset glyphs.
This was most noticeable to me in tab titles in the tab bar;
my shell dotfiles append `-- something` to the title when a
command is launched, and the `--` is a ligature in my font.
I think I've also seen this mess up positioning in the notcurses
demo as well.
The solution is to take the cluster initial cell index rather
than trying to reverse engineer it from incomplete info.
This commit annotates fonts with a boolean that indicates whether
we think it contains glyphs with emoji presentation, and then
passes the cluster.presentation field down to the shaper.
If the presentation doesn't match the current font in the fallback,
then it will be skipped until we exhaust its options.
`wezterm ls-fonts` also shows whether we think a font has emoji
presentation.
refs: #997
This replaces the slightly gnarly subpixel enabled blending in the
shader with Dual Source Blending, which is a technique where the
fragment shader can specify both the primary color (RGBA) as well
as an additional per-channel mask that can be used to alpha blend
with the destination.
This enables artifact-free alpha blending when used together
with a transparent window background.
refs: https://github.com/wez/wezterm/issues/932
Terminal now maintains a sequence number that increments
for each Action that is applied to it.
Changes to lines are tagged with the current sequence number.
This makes it a bit easier to reason about when an individual
line has changed relative to some point in "time"; the consumer
of the terminal can sample the current sequence number and then
can later determine which lines have changed since that point
in time.
refs: https://github.com/wez/wezterm/issues/867
Use the newer logical line method in pane rather than going
via the hyperlink function, so that we can better reason
about physical vs. logical line breaks, and get the results
very slightly faster too.
refs: #874
We were previously only remembering the most recently pressed
button, but that's a lossy thing to do.
This commit remembers the button presses so that we can correctly
report all press/release events.
refs: #973
I think this is the heart of the initial size issues:
during creation, if the dpi or size is different, we generate
a resize event, but because it is dispatched before we've
assigned self.window, we weren't able to resize the window
to fit.
This commit passes the Window object down to the resize
handler so that it can do that; the diff is conceptually
small but there is corresponding fanout around ensuring
that the Window is passed down through all the resize
related codepaths that need it.
refs: #1002
refs: #695
It seems like this is making things worse on X11/Wayland.
Let's try simply skipping it--that seems fine on X11/Wayland,
but needs to be verified on macOS and Windows.
refs: #1002
refs: #695
The intent is to avoid weirdness with Wayland where we need to wait for
a configure event before we try to set the window size programmatically.
refs: #1002
WindowState is a bitfield that can represent maximized, full screen
and hidden window states.
WindowState is passed along with resize events, improving on the
prior basic is_full_screen boolean by representing the other states.
Notably, WindowState::MAXIMIZED is used to represent a state where
the window's size is constrained by some window environment function;
it could be due to the window being maximized in either or both the
vertical or horizontal directions, or by the window being in a tiled
state on any edge.
When the window is MAXIMIZED, wezterm will behave as though
`adjust_window_size_when_changing_font_size = false` because it knows
that it cannot adjust the window size in that state.
This potentially helps with #695, depending on whether the window
manager propagates this state information to wezterm. Gnome/mutter
does a good job at this with both X11 and Wayland, but I couldn't get
sway to report these states and I don't know of any other tiling wm
that I can easily install and use on fedora, so there's a question
mark around that.
This commit changes the full surface fill to be fully transparent,
and adds a separate quad to fill with the configured window background
color.
The thesis is that this should avoid the apparent weird rgb/srgb
mismatch that seems to occur with the window background on Intel macs
(those have a different OpenGL implementation than M1 based macs which
don't appear to have this issue).
refs: https://github.com/wez/wezterm/issues/1000
refs: https://github.com/wez/wezterm/issues/653
I noticed that on macos, the initial terminal size didn't
match the 80x24 default; it was a few columns short.
I think I broke this with recent changes in window
event dispatching.
This commit passes the terminal size down to apply_dimensions
just after we've set up the GL context to preserve the
terminal size.
Possibly related to https://github.com/wez/wezterm/issues/1002
This should help to avoid artifacts in the case where glyphs
render outside their nominal terminal cell (happens when the
shaper tweaks positioning, and/or when ligatures are involved).
Previously we'd render the layers in z-index order for cell N
before the layers in z-index order for cell N+1.
If N had an image that overlayed the text (nominally z-index 0.5!)
and the glyph in N+1 (z-index 0) was slightly to the left of its
border, then it could layer incorrectly over the cell to the left.
The underlying types in termwiz support 10-bit color, but in our
conversion to the data we pass to the vertex, we were forcing it
into 8-bit and then converting to float.
Simplify this by skipping the intermediate 8-bit representation
and just go directly to float.
I'm not sure if this is needed now that we have a single draw call, but
based on the history and the nuance of different gl/driver/os quirks it
feels like a good idea to keep this option in the back pocket.
Since we can now mutate individual frames, we need to avoid
falsely caching across a change; switch from using (image_id, frame_idx)
to frame_hash.
refs: #986
Adds a use_image feature to termwiz that enables an optional
dep on the image crate. This in turn allows decoding of animation
formats (gif, apng) from file data, but more crucially, allows
modeling animation frames at the termwiz layer, which is a pre-req
for enabling kitty img protocol animation support.
refs: #986
Rather than leaving the frame un-rendered, this commit arranges
to make one last pass but with all image quad assignments skipped.
This should at least make a reasonable effort at displaying text
on the screen.
refs: https://github.com/wez/wezterm/issues/879
I noticed when running the notcurses demo that we're spending a
decent amount of time decoding png data whenever we need to
re-do the texture atlas.
Let's avoid that by allowing for ImageData at the termwiz layer
to represent both the image file format and decoded rgba8 data.
This commit is a bit muddy and also includes some stuff to try
to delete placements from the model. It's not perfect by any
means--more expensive than I want, and there's something funky
that causes a large number of images to build up during some
phases of the demo.
refs: #986
OpenGL will silently let us allocate a texture larger than the GPU can
bind to a sampler, reporting the error status out of band and leaving
the display in a perma-broken state.
This commit deliberately checks against the max texture size and raises
an error in that case.
The recovery story isn't perfect, but at least the texture remains
usable, so the user can clear the screen and still be able to see glyphs
afterwards.
refs: https://github.com/wez/wezterm/issues/879
Taking further advantage of dynamic quad allocation, we can now
remove the multiple render passes in favor of allocating the quads
and painting them from back to front.
In turn, this means that we can reduce the amount of data that we
store in the vertex, which simplifies the shaders a bit, at the
expense of making the render code in rust a bit more complex.
However, we can take advantage of stretching runs of cells with
background colors in to a single quad.
refs: #986
This was added in 365a68dfb8 to free the
orca from its cage. With the recent dynamic quad allocation changes, we
don't need a distinct 4th pass any more and can simply layer a separate
quad on top of the glyph quad.
refs: #986
This removes the pre-allocated (at resize) number of quads
and replaces it with a dynamic mechanism that tracks how many
quads are needed for a frame and then will re-allocate and
re-render when there weren't enough.
We start with 1024 quads and try to allocate in multiples
of 1024 quads.
refs: #986
This commit removes the `Quads` struct which maintained pre-defined quad
indices for each of the cells, the background image and scrollbar thumb.
In its place, we now "dynamically" hand out quads to meet the needs of
what is being rendered. There are some efficiency gains here with
things like the selection (which can now be a single stretched quad,
rather than `n` quads in width).
This isn't a fully dynamic allocation scheme, as we still allocate the
current worst case number of quads when resizing.
A following commit will adjust that so that we allocate a ballpark and
then employ a mechanism similar to OutOfTextureSpace to grow and retry a
render pass when we need more quads.
Futhermore, this dynamic approach may allow reducing the amount of stuff
we have in the Vertex and "simply" render some quads before others so
that we don't have to have so many draw() passes to build up the
complete scene.
refs: #986
This teaches termwiz to recognize and encode the APC
sequences used by the kitty image protocol.
This doesn't include support for animations, just the
transmit, placement and delete requests.
refs: #986
In the case where the cells vec is shorter than the line width,
we need to ensure that we render the inverse video background
color if that mode is in effect.
refs: #133
Also fixes an issue where only the first frame schedule would
take effect! Surprised this didn't bubble up as a bug with
animated gifs already.
refs: #133
This commit introduces a 4th draw pass for rendering sixel and
iterm images that are attached to cells.
Previously, a cell could container either text or an image from
the perspective of the renderer. If it had an image then the glyph
bitmap would be ignored in favor of the image.
However, that causes sixel behavior to diverge from other terminals
(https://github.com/wez/wezterm/issues/942) so we need to be render
both of these.
The simplest way to achieve this is to add a distinct set of texture
coordinates for the attached image and then add a draw pass to alpha
blend it over the glyph content.
The sixel/iterm image processing stage is also adjusted to preserve
the prior cell information and "simply" attach the image info to
the cell. Previously, the cell would be replaced with a blank cell
with the image attached.
The result of this is that the notcurses-demo intro section can
now render the orca "enveloped in the soft glow of glyphs" rather
than caged in a black box.
Note that there are some cases where the render turns blocky but
I suspect that that is due to some other misunderstanding between
wezterm and notcurses and that we'll root cause it as a follow up.
Looking at #900; the unconditional directory change on startup
is "bad" because it only happens on Windows.
This commit removes it and instead puts the logic into the pty
layer to match the unix behavior.
The behavior is:
* If the command specifies the cwd, use that.
* Otherwise, use the home directory
This commit causes a window-config-reloaded event to trigger
when the appearance (dark/light mode) is changed on macos.
It also arranges to propagate the window level config to newly
spawned panes and tabs, created both via the gui and via the
CLI/mux interface.
refs: https://github.com/wez/wezterm/issues/894
refs: https://github.com/wez/wezterm/issues/806
This allows window-level config overrides to apply
to panes contained within the window.
For instance, this allows setting a window-level
color scheme.
While looking at https://github.com/wez/wezterm/issues/945 I noticed
that mouse moves were being considered to be drag events even though
no mouse buttons were held down.
I added this originally thinking that it would make it easier to resolve
https://github.com/wez/wezterm/issues/695 and to integrate wgpu support,
but it's the cause of https://github.com/wez/wezterm/issues/922 so let's
take it out and more directly connect the window events to those in the
terminal.
This commit likely breaks mac and windows; pushing it so that I can
check it out and verify on those systems.
0.8 doesn't seem to build with rusttls, but I don't think
we need that any more: we've been using vendored openssl on windows
and mac for some time.
closes: #924
refs: https://github.com/jayjamesjay/http_req/issues/48
Previously, if the config file had errors, ls-fonts would silently
continue with the default config, which was confusing.
Make a point of checking and reporting config file errors.
You can run `cargo build --release --no-default-features` to build
without wayland support.
This is useful for systems that do not have wayland (eg: the `slint`
distro).
This section of the code wasn't looking up the custom glyphs
and would always use the font. We can make rendering a little
more efficient if we skip the font resolution for this case,
and the code is much simpler if we just use our own box drawing
glyphs, so that's what we're doing here.
refs: #584
The issue is that the pane was only removed from the tab when explicitly
closed, leaving it to be later detected and flushed.
However, in the meantime, when performing eg: cursor blink maintenance,
if the set of panes in the tab is empty then the window would close.
The resolution is to ask the mux (rather than the tab) to kill the pane,
so that the cascading closure of the tab causes the window's active
tab to reference the correct remaining tab.
refs: #890
This changes the fill_rect function over to use the zeno crate.
zeno allows describing a path and filling or stroking.
This commit doesn't strictly need that, but it sets things
up for more interesting custom glyphs in later commits.
refs: #584
refs: #588
Same vein as 8931afba5cee07ab12990f06c2ff34d6f8426b19; the auth
window could sometimes get stuck until an input event was sent
to it.
Wire up a mux event so that the window can close itself.
When the client connected to an empty remote mux, it would allocate an
empty window and then spawn a new tab into it.
Meanwhile, the authentication window would close and trigger a prune of
all empty windows, causing the in-flight spawn to fail because its
destination window was removed.
This commit defers window pruning while Activity is in progress;
the MuxWindowBuilder has an associated Activity count.
in the same vein as d657721163, the
increased idle loop means we need to be careful not to suppress
invalidation events.
In this case, overlays aren't from the window in the mux model,
so we'd ignore invalidations for those.
While looking at this I realized that we'd also do the same
for output being emitted in panes that were not the active pane,
so tidy that up.
in the same vein as d657721163
this commit introduces more assertive signalling from the remote
mux when a pane is closed so that the client can update.
As part of reducing the amount of regularly scheduled stuff wezterm
does in the background, this commit restructures how an empty mux
is detected; now when the mux prunes dead windows it will emit
an Empty event.
The Activity type will now schedule a prune when it is dropped,
which will clean up and trigger the Empty event.
refs: https://github.com/wez/wezterm/issues/770
Adds a `ShowDebugOverlay` key assignment that will create a tab
overlay that shows a limited number of recently logged events.
refs: https://github.com/wez/wezterm/issues/641
This got a bit broken by the fix for https://github.com/wez/wezterm/issues/714
since we can be handed a range of logical line fragments, we should
test each of them to find our matching result.
Also, improve the logic for constraining the length when looking
backwards.
This commit introduces the knowledge about whether a font is
scalable or was using bitmap strikes (eg: color emoji bitmaps).
Then that information is used to help figure out whether and
how to scale a glyph.
refs: https://github.com/wez/wezterm/issues/685
* Better function for undercurl
* Setting lower alpha
* underline alpha in line-frag
* make undercurl alpha background independent
* Improved Shader
* Old Rasterization
Co-authored-by: Roland Fredenhagen <git@modprog.de>
When the title, icon, OSC 7 and SetUserVars sequences are processed,
notify the embedding application.
The gui layer uses this to trigger a titlebar update.
refs: #647
Previously, we used `git describe --tags` to produce a version number
for non-released builds derived from the most recent tag + some info
such as the number of commits since that tag and then `g{HASH}`.
That always confuses people because the date portion at the front
looks old (it is typically the previous release) and the hash at
the end has that `g` in it.
This commit simplifies both the tag name used when making a release
and the computed version number take the date/time from the current
commit, and then append the hash. That way the version number always
corresponds to a commit.
This scheme doesn't help detect situations where the commit is
dirty, but I don't think the old one would have helped with that
either.
the binary search would falsely extend the end of the match
to the start of the subsequent match for the wrapped line case.
The resolution is to emit a coordinate for the newline that we
add to the haystack between the wrapped lines.
closes: https://github.com/wez/wezterm/issues/732
In the situation where we have a full screen terminal (eg: 500 cells
wide), but very little output (eg: only 10's of columns on the left are
NOT blank), we would previously spend a non-trivial amount of time
calculating fg/bg colors for the blanks that trailed the actual
clusters; the calculation for each row was:
O(trailing-blanks * full cell color compute cost)
which was around 30us per row. For large numbers of rows this could
add up to >10ms per frame.
This commit changes the logic to run in two phases:
* O(selection-width) with simple fg/bg color updates for the selection
range
* O(1) full cell color compute cost for the cursor if the cursor
is somehow in the trailing blank region and not already handled
by the earlier clustering logic.
With the sequence of recent commits, the frame time for the large
terminal case has been reduced from ~22ms to ~7ms, which is approx 3x
improvement.
refs: #740
It looks like the mux search results include a trailing newline
in some cases, which means that a match can wrap onto a second
line.
If that line is shorter than the label length, we could panic.
This commit makes quickselect safer to use in this situation,
but the real fix is with the mux search code.
It's not perfect; this only handles the case where you move down
into the terminal. I couldn't easily make the same thing happen
when moving the mouse up or left outside of the window. It's
probably fixable but this is better than it was.
closes: https://github.com/wez/wezterm/issues/591
* Make alphabet and patterns configurable
* add docs
* Enhance scrollback search to support regex captures so that
searching for eg: `fo(o)` will select the last `o` in `foo`.
refs: https://github.com/wez/wezterm/issues/732
This is the first pass implementation, drawing on the alphabet logic
and default patterns from tmux-thumbs (thanks @fcsonline!).
ctrl-shift-space pops up the quick select overlay.
Typing the highlighted prefix will select the matching text and
copy it as though the `Copy` key assignment was used.
TODOs are to make the alphabet and patterns configurable, as well
as write up some docs.
refs: #732
I've built this on linux, which doesn't respect the timeout.
I've made speculative changes that should build on mac and windows,
but that don't plumb the timeout functionality on those systems
as of yet.
refs: #619
back out the portion of the cap height scaling that applied when
we knew the cap height of the primary font but not a fallback font.
That logic allowed some overly wide powerline fonts to be sized
correctly (a bit smaller), but also meant that a number of emoji
and other symbol glyphs were now undersized.
refs: https://github.com/wez/wezterm/issues/727
It now outputs something that you could conceivably put into
your config file, although the intent is to show the canonical
way to reference the individual fonts that were found, rather
than to specify a fully baked list to paste into a config.
eg:
```
; ./target/debug/wezterm ls-fonts
Primary font:
wezterm.font_with_fallback({
-- /home/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
{family="Operator Mono SSm Lig", weight="DemiLight"},
-- /home/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontConfig
{family="Operator Mono SSm Lig", weight="DemiLight"},
-- /home/wez/.fonts/MaterialDesignIconsDesktop.ttf, FontDirs
"Material Design Icons Desktop",
-- /home/wez/.fonts/terminus-bold.otb, FontDirs
{family="Terminus", weight="Bold"},
-- /home/wez/.fonts/JetBrainsMono-Regular.ttf, FontDirs
"JetBrains Mono",
-- /home/wez/.fonts/NotoColorEmoji.ttf, FontDirs
"Noto Color Emoji",
-- /home/wez/.fonts/MaterialDesignIconsDesktop.ttf, FontConfig
"Material Design Icons Desktop",
-- /usr/share/fonts/terminus-fonts/ter-u32n.otb, FontConfig
"Terminus",
-- /home/wez/.fonts/JetBrainsMono-Regular.ttf, FontConfig
"JetBrains Mono",
-- /home/wez/.fonts/NotoColorEmoji.ttf, FontConfig
"Noto Color Emoji",
-- <built-in>, BuiltIn
"Last Resort High-Efficiency",
})
```
we now compute the ratio of the cap height (the height of a capital
letter) vs. the em-square (which relates to our chosen point size) to
understand what proportion of the font point-size that a given font
occupies when rendered.
When rendering glyphs from secondary fonts we can use the cap height
ratios of both to scale the secondary font such that its effective
cap height matches that of the primary font.
In plainer-english: if you mix say bold, italic and regular text
style in the same line, and you have different font families for
those fonts, then they will now appear to be the same height where
previously they may have varied more noticeably.
For emoji and symbol fonts there may not be a cap-height metric
encoded in the font. We can however, improve our scaling: prior
to this commit we'd use the ratio of the cell metrics of the two
fonts to scale the icon/emoji glyph, but this could cause the glyph
to be slightly oversized as seen in https://github.com/wez/wezterm/issues/624
If we know the cap-height of the primary font then we can additionaly
apply that factor to scale the emoji to better fit the cell.
While looking at this, I noticed that the aspect ratio calculation
for when to apply to the allow_square_glyphs_to_overflow_width option
had width and height flipped :-(
See also: https://tonsky.me/blog/font-size/
refs: https://github.com/wez/wezterm/issues/624
This addresses the render artifacts aspect of https://github.com/wez/wezterm/issues/671
For whatever reason, some font(s) cannot be loaded on that system
and that results in the paint routine erroring out.
This commit avoids the error by substituting a blank glyph
instead of the glyph that failed to load.
refs: https://github.com/wez/wezterm/issues/671
This commit allows the x11 window implementation to detect changes
in the DPI that occur after a window is created.
These can occur when changing desktop resolution or when changing
the accessibility option for "Large Text" in gnome.
In order to avoid continually polling for the value on every resize,
we look for the `_GTK_EDGE_CONSTRAINTS` atom in our property change
notifications. This seems to be sent at least as often as the
dpi/scaling changes.
It's also worth noting that some dpi changes don't generate resize
events, so we can't just read the dpi value on every resize, because
we'd miss some of those changes.
Part of this commit changes the font scaling logic: previously
we'd keep a notion of "dpi scale" to apply. That dates from an
earlier time in wezterm where we didn't think that we knew an
actual dpi value.
The way that worked was that we'd compare our current guestimate
of the DPI against what we though the baseline OS dpi should be to
produce a scaling factor.
On X11 that dpi value is global and we'd effectively always produce
a revised scaling factor of 1 after we'd set up the initial window.
This commit changes that logic to just pass down the actual DPI value
to the font code. That DPI value already accounts for HiDPI scaling
so this is hopefully a NOP change for the other systems.
refs: https://github.com/wez/wezterm/issues/667
This was broken by b441be3ac9
For whatever reason, the breakage was only visible with the Iosveka
font on Windows. I couldn't reproduce it on my other systems, even
though the code technically applies to any system.
The breakage was: the metrics resulted in a difference of about 0.4
pixels being used for the descender with that particular font, resulting
in weird vertical alignment problems.
The offset needs to be computed against the ceil of the cell height,
which removes the fractional offset.
refs: https://github.com/wez/wezterm/issues/661
refs: https://github.com/wez/wezterm/issues/582
The repro scenario for this case was:
* open GNU nano
* hit enter twice
* type hello
* move the text cursor to the top line
* double click on hello
* hit enter
Prior to this commit, the selection would remain on the now-blank line
that previously held `hello`.
refs: #644
This has been a commonly requested feature in the past week,
and it's a reasonable one. The mux server inherited the
close-when-done behavior from when it used to be an alternate
front-end in the same executable as the gui, but it doesn't
need to be that way any more.
We also need to accomodate that case in the client: if the
newly attached domain doesn't result in any panes being imported,
we need to spawn a new command there in order to keep the client
alive. The pre-existing check for whether the mux was empty had
false positives because the local mux may still reference the
pane from the connection UI, which would finish closing out shortly
after we had decided not to spawn anything, and then the client
would close.
refs: https://github.com/wez/wezterm/issues/631
refs: https://github.com/wez/wezterm/issues/507
When line_height is specified, rather than applying the offset
to just the top of the cell, apply it in equal parts to the top
and the bottom so that the cell is vertically centered.
closes: https://github.com/wez/wezterm/issues/582
This replicates `last-window` in tmux. To pull this off, I
deliberately store the last tab whenever I'm activating a new one or
spawning a new one. I had to do this explicitly rather than hooking
set_active, because we end up setting the active tab briefly for some
common operations like moving a tab.
Allow overriding ssh config options from the command line.
I don't want to replicate the many options that `ssh(1)` has;
this just exposes the `-oNAME=VALUE` syntax. The config names
are those from `man ssh_config`; `IdentityFile` rather than `-i`.
refs: #457
I wonder how long this has been broken... rather than spawning
into domain "local" it would try to spawn into "`local`" and fail
silently because the error message wasn't logged.
So let's log it, and let's fix it.
refs: https://github.com/wez/wezterm/issues/468
There are a few notable changes as a result:
* A number of `.ssh/config` options are now respected; host matching
and aliasing and identity file are the main things
* The authentication prompt is inline in the window, rather than
popping up a separate authentication window
Refs: https://github.com/wez/wezterm/issues/457
These now operate in terms of logical lines so they deal with
lines that have wrapped outside the viewport better than in
previous releases.
closes: https://github.com/wez/wezterm/issues/408
Rust 1.51 allows addressesing a long-standing TODO which was that we
shouldn't need to build a vendored copy of openssl on most sensible unix
systems.
We do require a vendored copy on macOS and Windows, but due to the way
that Cargo's feature resolver worked, it wasn't possible for this
requirement to be respected.
Rust 1.51 introduces `resolver="2"` which can deal with this feature
resolution!
https://doc.rust-lang.org/nightly/cargo/reference/features.html#feature-resolver-version-2
The upshot of this is that building wezterm on real unix systems that
are not macos will now link against the system libssl, resulting in both
a shorter compile time and less headaches arising from having a slightly
different openssl used by wezterm than the rest of the system.
cc: @jsgf
If shaping can't resolve some glyphs, queue the font locator
fallback resolution to another thread; meanwhile, a last resort
glyph is used.
That thread can trigger an invalidation once the fallback resolve
is complete, the window is invalidated and the last resort glyph
is replaced by the resolve glyph.
refs: https://github.com/wez/wezterm/issues/559
refs: https://github.com/wez/wezterm/issues/508