Currently implemented on X11 only, this function returns information
about the geometry of the screen(s).
This is taken from the same source of information we use for the
`--position` CLI argument to `wezterm start`.
```
> wezterm.window.screens()
{
"by_name": {
"DisplayPort-1": {
"height": 2160,
"name": "DisplayPort-1",
"width": 3840,
"x": 0,
"y": 0,
},
},
"main": {
"height": 2160,
"name": "DisplayPort-1",
"width": 3840,
"x": 0,
"y": 0,
},
"origin_x": 0,
"origin_y": 0,
"virtual_height": 2160,
"virtual_width": 3840,
}
```
This commit adjusts the config loading code so that we can return
information about the paths the should be watched for a subsequent
reload even in the more common error cases.
refs: #1174
This is a bit of an unsatisfactory commit... the bulk of it is
augmenting our calls into XCB to ensure that we check the status of each
request; the idea was that doing so would highlight the source of the
bad drawable error that is being surfaced in #2198, but after doing
that, it still doesn't highlight the offending call.
My conclusion is that either something in MESA/EGL or the IME is
generating calls that we cannot see into and that one of those is
referencing the window id that we just destroyed.
The resolution then is a bit gross: instead of destroying the window
when we need to close it, we first unmap it to remove it from the
screen, then after 2 seconds we destroy it.
refs: https://github.com/wez/wezterm/issues/2198
We need the mux window builder to notify in order for the ConnectionUI
to show up, but we wouldn't trigger the notify (which happens on drop)
until we'd awaited the connection ui completing password auth.
Force it to drop earlier to unblock.
refs: https://github.com/wez/wezterm/issues/2194
Previously, the mux layer had no internal understanding of titles other
than the Pane::get_title method to return state from a pane.
Users have asked for ways to explicitly set titles on windows and tabs,
so this commit is a step towards that.
The mux window and tab objects now store a title string.
The terminal layer now emits Alert::WindowTitleChanged when the window
title is changed via eg: OSC 0 or OSC 2.
The mux layer will respond to Alert::WindowTitleChanged by resolving the
window that corresponds to the source pane and amending its title.
The MuxWindow and MuxTab objects now provide accessor methods for the
title.
TabInformation (as used by format-tab-title and format-window-title) now
exposes the underlying window_id as well as tab_title and window_title.
The tab title can be changed via the lua MuxTab type, but there is not
currently an escape sequence associated with this.
The defaults for format-tab-title and format-window-title don't
currently consider these new title strings.
refs: https://github.com/wez/wezterm/issues/1598
Previously, trying to do something like `foo = "bar"` in the debug
overlay wouldn't succeed, because we were always trying to wrap
the line inside `return {line}`, which allowed for only expressions
to be used.
Now we also allow a fully formed statement to be used, which means
that that kind of assignment can be performed in the repl, making
it a bit more convenient to try stuff out.
refs: https://github.com/wez/wezterm/issues/1238
Using the newly exposed-to-lua mux apis, you may now run some lua code
at GUI startup and/or mux startup, just prior to any default windows
being created.
If you happen to spawn any panes as a result of this, wezterm will
skip creating the default program.
```lua
local wezterm = require 'wezterm'
local mux = wezterm.mux
-- This produces a window split horizontally into three equal parts
wezterm.on("gui-startup", function()
wezterm.log_info("doing gui startup")
local tab, pane, window = mux.spawn_window{}
mux.split_pane(pane, {size=0.3})
mux.split_pane(pane, {size=0.5})
end)
wezterm.on("mux-startup", function()
wezterm.log_info("doing mux startup")
local tab, pane, window = mux.spawn_window{}
mux.split_pane(pane, {size=0.5, direction="Top"})
end)
return {
unix_domains = {
{name="unix"}
},
}
```
refs: #674
refs: #1949
The intent is to expose Mux related functions to lua, so `wezterm.mux`
will be that module table.
In order to test this out in the debug overlay, I realized that the
overlay was running functions in a different thread and didn't have
access to the mux, so this commit also tweaks the debug overlay repl to
execute the input in the main thread.
The result is that it is now possible to do
`wezterm.mux.active_workspace()` in the debug overlay to print the
active workspace name.
More functions will follow.
refs: https://github.com/wez/wezterm/issues/225
Main thing to note here is that the open crate has deprecated
open::that_in_background, but made open::that non-blocking.
I think this is OK, but I'm a little cagey about what will
happen with this on Windows. We may need to spawn our own
thread for this if things go awry.
I did an ad-hoc test where I set the new tab button background to
an Animated value and saw that it eased in and out.
However, this commit doesn't make anything use this yet.
This is prep for future work where I'll be moving more of the main
monospace rendering into the box model code and factoring out
this aspect of animation.
Useful if you want to add smaller items to your background layers
every so often; you can specify the distance between them and make
it independent of the item height.
The color can have alpha and blend with other layers.
This is helpful if your image has fully transparent portions
and you want to explicitly place a color in there.
The `File` variant for background layers may now be an object
that specifes a speed factor. That factor is applied to the
animation frame durations in the loaded image, allowing the
playback rate to be adjusted.
Adjusts the background rendering logic so that we now allocate
a render layer for each defined background layer. This allows
their individual opacity value to multiple and blend together.
As part of this, I noticed that the big jpegs I was using could
take 400ms or more to load, so I added a basic cache to avoid
loading the same image multiple times around a config reload.
This adds some types that will enable richer background images.
* Can specify multiple layers
* Each layer can select from image files or gradient definitions
* Layers have additional properties to specify positioning, scaling,
tiling and whether they scroll with the viewport.
None of the additional properties are hooked up yet.
This commit allows for the SplitPane internal action to use the
pane id of an existing pane as the source of the pane to be added
in the new split target, rather than spawning a new command.
This can be used to move a pane from one tab to another, and is
analagous to tmux's `join-pane` command.
refs: https://github.com/wez/wezterm/discussions/2043
refs: https://github.com/wez/wezterm/issues/1253
Make the layer allocation more dynamic, which makes it
possible for the box model stuff to allocate a layer based
on the zindex for an element.
Adjust the box model code to cascade the base zindex via
the layer context so that the render stage can select
the correct layer.
This fixes up rendering tabs over the top of the right status
area.
Wraps up the changes from the following diff and allows for the modal
layer (and box model) to use alpha for poly quads.
Change the default background color for pane select to be slightly
transparent.
Each layer has the same 3-pass draw that we use for the main terminal
display.
These layers allow for potentially compositing between the layers.
That is untested at the moment as the upper layers use the box model
stuff which hard-codes its work to the vb index 1 which doesn't
use regular alpha blending.
This is still a bit of a WIP, but this commit:
* Introduces a new "Modal" concept to the GUI layer. The intent is
that modal intercepts key and mouse events while active, and renders
over the top of the rest of the normal display.
I think there might be a couple of cases where key events skirt
through this, but this is good enough as a first step.
Also, the render is forced into layer 1 which has some funny side
effects: if the modal choses to render transparent, it will poke
a hole in the window because all the rendering happens together:
there aren't distinct layer compositing passes.
* Add a new PaneSelect action that is implemented as a modal.
It uses quickselect style alphabet -> pane label generation and
renders the labels over ~the middle of each pane using an
enlarged version of the window frame font. Typing the label
will activate that pane. Escape will cancel the modal.
More styling and docs will follow in a later commit.
refs: #1975
This, along with the plumbing included here, allows specifying
the destination of the split (now you can specify top/left, whereas
previously it was limited to right/bottom), as well as the size
of the split, and also whether the split targets the node at the
top level of the tab rather than the active pane--that is referred
to as full-width in tmux terminology.
https://github.com/wez/wezterm/issues/578
Invalid option names, or values that evaluate as nil (such as the `foo`
above: that's treated as a global variable reference, but `foo` isn't a
defined global and evaluates as `nil`) will now cause the program
startup to error out with an actionable error message.
Previously, the invalid config name would generate a warning, and the
invalid value would silently have no effect as it has the same effect as
omitting the named value and leaving it as its default value.
I think these cases should both immediately error out and stop
further processing, so that's what we're doing.
This commit also adds support for adding:
```
#[dynamic(deprecated = "use newer option instead")]
pub some_config_value: bool,
```
but not options currently use this.
To do this, we split `Pattern` into the underlying pattern for the mux
layer (which is part of the codec), and another for the config layer,
so that we can specify this new mode.
At the gui layer, we translate the selection variant into the actual
selection text and map it to the mux Pattern enum.
When taking the selection text, we restrict it to just the first line.
refs: https://github.com/wez/wezterm/issues/1912
Turn on multi-line mode by default, and improve the localpane
search function to collapse runs of trailing whitespace into
just a newline.
That allows:
```
./target/debug/wezterm -n --config 'quick_select_patterns={"foo$"}'
```
to match the first line from this, but not the second:
```
printf "foo\nfoobar\n"
```
and this to match both:
```
./target/debug/wezterm -n --config 'quick_select_patterns={"^foo"}'
```
refs: https://github.com/wez/wezterm/issues/2008
Avoid using serde for mapping between Lua and Rust for the `Config`
struct.
This improves the build speed of the config crate by 2x; it goes down
from 30 seconds to 9 seconds on my 5950x.
fixes:
* beginning the selection with the top right or bottom left corner
* beginning the selection with the bottom right corner and only select a single line
The issue here was that we'd try to match this:
```
key_event RawKeyEvent { key: Char('t'), modifiers: ALT | LEFT_ALT, phys_code: Some(T), raw_code: 17, repeat_count: 1, key_is_down: true, handled: Handled(false) }
```
which has mods=`ALT|LEFT_ALT` against `ALT` and would fail.
We need to strip out the positional ALTs from the modifiers
in order to successfully match.
refs: https://github.com/wez/wezterm/issues/1958
This commit re-arranges the code so that an overlay can have a local
stack of key table activations; this allows copy_mode and search_mode
key tables to layer on top of the user's window level key tables.
Previously, we'd just stick the search_mode entry on top of the global
state, which worked, but had the undesirable side effect of hijacking
the Enter key when switching to another tab in the window.
refs: https://github.com/wez/wezterm/issues/993
The copy overlay now has a notion of running in search mode vs. copy
mode; it can be launched in either mode.
Search mode has a separate key table called `search_mode`.
Activating copy mode while search mode is active will now update
the mode of the existing overlay, rather than cancelling and creating
a new instance, and vice versa.
Activating copy mode while search mode is active will replace the
current key table activation (which is assumed to be `copy_mode`)
with `search_mode`, and vice versa.
The viewport is no longer scrolled to the bottom when activating search
mode.
refs: https://github.com/wez/wezterm/issues/993
refs: https://github.com/wez/wezterm/issues/1592
This change causes key table activations to effectively layer
over prior key table activations.
This is necessary for the copy mode key assignment changes to
work.
refs: https://github.com/wez/wezterm/issues/993
Moves the key handling in the copy overlay to be driven entirely
by configurable key assignments.
Note: copy mode wants you to use the `Copy` assignment to actually
do the copy, but this implementation hides the normal key assignments
by activating the copy mode key table. This will be addressed
in the following commit.
refs: https://github.com/wez/wezterm/issues/993
The launcher menu code to perform attaching has been generalized
into a key assignment action and reimplemented in terms of that
action.
A detach action has been added to disconnect and detach.
refs: https://github.com/wez/wezterm/issues/1874
If we had previously killed all the panes in a remote mux,
and then reconnected to it using the launcher menu attach option,
we could end up in a confusing state where we connect but don't
show anything for the remote; it looks like nothing happened
even though it is legitimately showing the empty remote mux.
This commit checks for that case and spawns the default program
in the remote if there are no panes.
This commit allows the currently active window to:
* Spawn a new tab in the active window (rather than spawning
a new window) to host the connection status
* Auto-close that connection UI tab (rather than the whole window)
when the window is no longer needed
* Pass the current window through to use as the primary window when
assigning remote window/tabs.
The net effect of this is that there are fewer transient windows,
and that it is easier to connect a set of domains to the active
workspace.
refs: https://github.com/wez/wezterm/issues/1874
When the screen is cleared/reset, the physical top is not reset with it,
instead the scrollback_top variable gets set with the point at which the
screen was reset / you are allowed to scroll back to. The scroll bar
code wasn't aware of that.
refs: https://github.com/wez/wezterm/issues/1866
Create a list of command definitions to hold the default key
assignments.
That list has more metadata, such as a brief and longer human
readable description of the purpose, and allows for (in the
future) reasoning about the context where the command is valid,
as well as providing more information when rendering in the
launcher menu.
refs: https://github.com/wez/wezterm/issues/1485
The heart of the issue here was due to the window-reuse logic that
tries to reuse a GUI window that is no longer associated with a mux
window.
Each GUI window subscribes to the mux for mux events, but it filters
according to is understanding of the mux_window_id that it is associated
with.
The GUI frontend maintains an mapping of GUI and mux window so that it
knows when to reuse a GUI window and when to close it.
When connecting to a remote mux, wezterm spawns a temporary connection
progress window. Once connected, workspace reconiliation is triggered
and decides that this window can be used for something else.
As part of workspace reconciliation, this mapping can be adjusted and
the frontend will notify a GUI window that its mux window has changed.
However, that updated mux window was not visible to the mux notification
subscription so the effect was that a variety of notifications were
effectively ignored, including updates from a remote mux when the output
was changed.
To make matters worse, the workspace reconciliation could "double-tap"
window creation and create excess windows only to later realize they
weren't needed and close them out again.
This commit addresses both of these concerns.
refs: #1841
refs: #1814
We're now capable of remembering an alpha value for everything
in the palette and the main window theme, but not the tab bar theme.
Whether the alpha is correctly respected at render time is a different
story!
refs: #1835
The bug here was that each paint call in a window would update
the focus state of its panes to reflect the one that had focus.
However, it didn't account for the actual window focus; it would
just assume that it was focused.
The result was that the perceived focus would alternate between each of
the windows in the wezterm process, and if you were running an
application that had enabled focus tracking, those events could cause a
repaint and drive up the CPU utilization.
This commit addresses that by gating the focus update to only occur
when we have the focus, and for extra safety, avoid generating focus
events at the terminal layer if the new state matches the current state.
refs: https://github.com/wez/wezterm/issues/1838
I wanted to use the Target::Pipe feature of env_logger so that we could
log to a log file as well as stderr, but it just doesn't work
(https://github.com/env-logger-rs/env_logger/issues/208).
Since we were already composing over the top of the logger in order
to capture data for our ringlog, this commit embraces that and makes
our logger responsible for both stderr and log file printing.
Thankfully, we can use the filter parsing code from env_logger to
avoid having to get too crazy with this.
Logs are stored in the runtime directory and look something like:
/run/user/1000/wezterm/wezterm-gui-log-596324.txt
Logs are collected on all platforms.
There isn't currently a thing to clean up logs.
Go directly to the underlying env_logger crate, as pretty_env_logger
hasn't been updated in some time, and I'd like to be able to redirect
the log output to a file more directly, and that feature is in a newer
version of the env logger than pretty_env_logger was pulling in.
This is definitely in the band-aid category, but two issues have
mentioned the AA in custom block glyphs recently.
This commit adds an `anti_alias_custom_block_glyphs` option that can be
set to false to prevent the custom block glyphs from enabling AA.
I think a better long term fix would be some kind of hinting to avoid
the degenerate AA case, but when I made an enquiry about this class of
issue in tiny skia in the past, the author didn't want to diverge from
skia-compatible behavior, so I think we'd need to find (or build!) an
alternative rasterizer for these path instructions.
refs: https://github.com/wez/wezterm/issues/1753
refs: #1817
To fix this correctly, the mux protocol would need to have some
special cases for talk to a gui server implementation, and we don't
have those today.
refs: #1794
The glium IncompatibleOpenGl Display doesn't include any of the
useful context to explain what the issue was, so this commit
renders the error both in human friendly and Debug form to
see if we can understand more about what is happening.
refs: https://github.com/wez/wezterm/issues/1813
* gui: improve mouse text selection
* implement mouse press capture between the terminal and UI, so when you
start selecting text from the terminal the tabs won't activate and
vice-versa
* selecting from the top and bottom lines won't scroll the viewport
anymore, it will only scroll if the mouse is moved out of line bounds
* change cell selection so that it behaves like text selection usually
does in other popular software
refs: https://github.com/wez/wezterm/issues/1199
refs: https://github.com/wez/wezterm/issues/1386
refs: https://github.com/wez/wezterm/issues/354
`ActivateKeyTable` pushes a new named key table entry onto the stack.
It has some parameters:
* name - required; the name of a entry in `key_tables` that should be
activated.
* timeout_milliseconds - how long the entry should remain active.
When this duration elapses, the entry will pop itself from the
stack. If omitted, the entry will not pop itself due to time.
* one_shot - if true (or omitted; true is default), the entry will pop
itself after one use. If false the entry will not pop itself after use.
But note that if timeout_milliseconds is set then it may pop itself
due to time.
* replace_current - if true, will pop the current stack entry before
activating the current entry. Most useful when combined with some
other one_shot=false activation.
`PopKeyTable` explicitly pops the top of the key table stack.
Most useful with `one_shot=false` activations.
`ClearKeyTableStack` clears the key table stack. Most useful with
`one_shot=false` activations.
```
local wezterm = require 'wezterm';
wezterm.on("update-right-status", function(window, pane)
local name = window:active_key_table()
if name then
name = "TABLE: " .. name
end
window:set_right_status(name or "")
end);
return {
debug_key_events = true,
keys = {
-- Activate the "woot" table as a one-shot with
-- a 2 second timeout, after which it will restore
-- the default table.
{
key="a", mods="CTRL",
action=wezterm.action{
ActivateKeyTable={
name="woot",
timeout_milliseconds=2000,
}
}
},
-- Activate the "woot" table.
-- The table will remain active until explicitly popped
-- by the `PopKeyTable` action. See the Escape binding below!
{
key="b", mods="CTRL",
action=wezterm.action{
ActivateKeyTable={
name="woot",
one_shot = false,
}
}
},
-- Activate the "woot" table as a one-shot with
-- no timeout. It will remain active until a key is pressed,
-- after which is will restore the default table.
{
key="c", mods="CTRL",
action=wezterm.action{
ActivateKeyTable={
name="woot",
}
}
},
},
key_tables = {
woot = {
{key="a", action=wezterm.action{SendString="woot"}},
{key="Escape", action="PopKeyTable"},
},
},
}
```
This commit introduces a new `key_tables` config option that allows
defining named groups of key assignments, but that have no effect yet.
To support this change, the InputMap type has been adjusted to allow
for the idea that multiple tables can exist.
refs: https://github.com/wez/wezterm/discussions/1812
The gist of the issue is that when setting eg: scale=1.2 to draw
a larger CJK glyph, it is drawn at the same descender level, which
makes it more likely to leave the top of the cell.
This commit adjusts the y position by the difference between the
original and the scaled descender so that is less likely to cause
problems.
refs: https://github.com/wez/wezterm/issues/1803
This is mostly a refactoring: pulling out the discrete width/height from
the `new_window` method and preparing to pass down x/y coords as well.
The types are expressed as Dimension so that screen relative sizes could
be expressed in the future... once we know how to obtain that
information on each platform.
refs: https://github.com/wez/wezterm/issues/1794
The tab bar height could vary by a couple of pixels depending on the
text shown inside it, which results in visual jitter as the title bar
changes.
Avoid that: always return our constant reserved amount of space for the
tab bar, even if it means that there are a couple of pixels "wasted".
cc: @davidrios
A bit of a PITA, this commit:
* Introduces a DeferredKeyCode type that defers resolving a concrete
keycode
* Adds key_map_preference config which can be Mapped or Physical
* Key map building resolves the keycode using key_map_preference
* Default key assignments have been re-phrased in order to produce
DeferredKeyCodes
* User-specified keys without `mapped:` or `phys:` prefixes will
resolve according to key_map_preference
refs: https://github.com/wez/wezterm/issues/1788
refs: https://github.com/wez/wezterm/issues/1784
Previously, we'd create a clipboard handler associated with a GUI window
and take care to pass that down to the underlying Pane whenever we
spawned a new pane.
For the mux server, instead of being associated with a GUI window, the
clipboard was a special RemoteClipboard that would send a PDU through
to the client that spawned the window.
The bug here was that when that client went away, the clipboard for
that window was broken.
If the mux server was the built-in mux in a gui process this could
leave a tab without working OSC 52 clipboard support.
This commit restructures things so that the Mux is responsible for
assigning a clipboard handler that rephrases the clipboard event
as a MuxNotification.
Both the GUI frontend and the mux server dispatcher already listen
for mux notifications and translate those events into appropriate
operations on the system clipboard or Pdus to send to the client(s).
refs: #1790
In https://github.com/wez/wezterm/pull/1779#issuecomment-1082058134 we
discuss a weird case where the tab bar height is computed as 0 and then
gets stuck at 0.
What's happening is that the initial `TabBarState::default()` value has
no items yet, and `build_fancy_tab` generates an area that occupies 0
pixels. This computed element is cached, and then the height from that
is cached.
When `invalidate_fancy_tab` is called, it didn't invalidate the cached
height and the resultant metrics were wonky.
One possible fix for this was to also invalidate the cached height,
but since that height is already stored in the built fancy tab,
we can remove that derived-cached value in favor of just passing
down the value.
refs: https://github.com/wez/wezterm/pull/1779
- Simplify scroll thumb calculations
- Correct thumb position when dragging with mouse
- Support border OS parameters
- Use usize for OS borders, to explicitly only accept positive integers
- Get correct tab height when using fancy tab bar
- Correctly draw depending on tab bar position
- Adjust minimum thumb size to be 1/2 of a cell height, so it has consistent size across platforms and screen densities
Fixes#1525
The condition should be: dpi-changed && (close-enough-stuff)
but was (dpi-changed && (some-close-enough-stuff)) ||
(other-close-enough-stuff).
The net result was toggling non-native full screen on macos could
falsely try to do scale change handling even though the dpi was
unchanged, because the window resized by only a couple of pixels.
Flesh out the get_os_parameters impl for macOS. When running on a
system that provides `NSScreen::safeAreaInsets`, use that to determine
the border required to avoid the "notch" on certain models of mac.
In the GUI layer: when the os parameters include a border, adjust
the render position to account for it.
This is a bit of a speculative change, as I don't have a mac with
a notch.
refs: https://github.com/wez/wezterm/issues/1737
Separates out window vs pane click-to-focus behavior more distinctly,
and fixes up the behavior when
swallow_mouse_click_on_window_focus=false.
refs: #1540
wezterm cli spawn, and wezterm cli split-pane can use this information
to pick a default for the pane id when invoked from outside of wezterm.
refs: https://github.com/wez/wezterm/issues/1531
The `open` crate blocks forever when spawning the browser via xdg-open,
which feels kinda "wrong" to me, but does offer a method that can stick
that in a background thread, so that's what we do here.
refs: #1721
* Detect mouse leaving the window
* Implement leave
* Use new API
* Fix mouse leave
* Fix mouse leave on Wayland
* Mouse leave on X11
* Detect mouse leaving window on macOS
* Fix example
refs: #1434
This change also allows removing the dep on the palette crate,
which I found to be difficult to use (API changed often, and relied
on a lot of `.into` that was hard to follow and reconcile across
upgrades). We already pulled in the csscolorparse crate as an indirect
dep of colorgrad, so we can replace the color conversion we need for
sixel with that crate while we're in here.
refs: #1615
This is using the existing attributes on the lines and rendering
the lines with doubled dimensions.
Selection on double width lines is a bit wonky because we don't
know how to translate the column position correctly.
This commit allows the following configuration:
```
wezterm -n --config 'colors = { selection_fg = "clear", selection_bg = "rgba:50% 50% 50% 50%" }'
```
which sets the selection_bg to fully transparent, and selection_bg to
50% transparent gray.
When selection_fg is fully transparent we'll use the normal fg color.
When selection_bg is partially (or fully!) transparent, it will be
alpha blended over the current cell background color.
To support this, the config file will now accept rgba colors specified
as 4 whitespace delimited numeric values. If a value ends with `%` it
is interpreted as a number in the range 0-100. Otherwise, it is
interpreted as a number in the range 0-255. The 4 values are
red, green, blue, alpha.
At this time, only the selection_fg and selection_bg settings accept
alpha values.
refs: #1615
Resolves a little bit of the awkward duplication of color types
between some of the crates by factoring them a little bit better.
This is prep for allowing specifying alpha for some colors
in the config.
This puts to final rest #478, wherein ligatured glyphs that span
cells would render portions of the glyph with the wrong fg color,
where wrong was usually the bg color and cause the glyph to turn
invisible when cursoring through the ligature.
The approach used here is to divide the glyph into 7 discrete strips
where each strip either intersects with the cursor, the selection, or
neither. That allows us to render each strip with the appropriate
foreground color.
This change simplifies some of the logic and allows some other code
to be removed, so that feels good!
As is tradition with these renderer changes, there's a good chance that
I overlooked something in testing and that the metrics or alignment
might be slightly off for some font/text combo. Let's see how this
goes!
refs: #784
refs: #478
refs: #1617
For a sequence like `e U+20d7` the intent is to render the `e` with
a vector arrow over the top.
This is typically implemented by fonts as an `e` followed by the
vector glyph (or vice versa), where either one of those may have
a zero advance so that the two elements are combined.
There were two problems here:
* During shaping we'd see the zero advance and assume that the entry
was useless and skip it
* During rendering, if we didn't think it had any cell width, we'd
not render it
Cursoring through that particular sequence can hide the vector
mark if the cursor is set to the default block cursor due to annoyances
in how the block cursor is rendered (it changes the fg color to match
the bg, but for elements outside where we think the cursor is, this
makes those elements invisible).
refs: https://github.com/wez/wezterm/issues/1617
This is a more robust approach; we make a separate pass to figure
out information about the (harfbuzz) cluster for a sequence of glyphs,
and then map that sequence back to the original cell sequence, and
from there compute the total cell width for the run, then distribute
the glyphs across the run.
This should yield more sane results for bidi.
Fixup the x-position math; it was still wonky despite the
efforts in 5f2c905db8 and
af92265ffb
refs: #1570
refs: #1607
refs: #1563
This allows unicode_version to be respected again when rendering.
The updated emoji-presentation.sh script now highlights this slightly
better by putting `.` characters after the emoji; unicode version 14
emoji presentation will show the `.` in the 3rd column, while earlier
versions will show it in the 2nd column for glyphs that are sensitive
to the version.
refs: #1607
refs: #1563
This commit does two related things, from opposite ends of the spectrum:
* Sets the sticky bit on pid files and unix sockets to avoid tmpwatch
deleting them in cleanup scenarios
* Falls back to looking at the changed time if the filesystem doesn't
support reporting creation time when wezterm does its own liveness
and cleanup checks for unix domain sockets in the runtime dir
* Allow any wezterm instance to perform that cleanup
refs: #1601
with:
```
bidi_enabled = false,
bidi_direction = "RightToLeft",
```
lines are now rendered right-justified in the terminal.
I think there's still work to do on this, because the cluster
order seems weird to me, but it's hard for me to intuit how
this should really look.
refs: #784
This commit refines bidi property handling:
* experimental_bidi has been split into two new configuration settings;
`bidi_enabled` (which controls whether the terminal performs implicit
bidi processing) and `bidi_direction` which specifies the base
direction and whether auto detection is enabled.
* The `Line` type can now store those bidi properties (they are actually
split across 3 bits representing enabled, auto-detection and
direction)
* The terminal now has a concept of active bidi properties and default
bidi properties
* The default properties are pulled from the wezterm configuration
* active bidi properties are potentially set via escape sequences,
BDSM (which sets bidi_enabled) and SCP (which sets bidi_direction).
We don't support the 2501 temporary dec private mode suggested by
the BIDI recommendation doc at this time.
* When creating new `Line`'s or clearing from the start of a `Line`, the
effective bidi properties are computed (from the active props,
falling back to default propr) and applied to the `Line`.
* When rendering the line, we now look at its bidi properties instead
of just the global config.
The default bidi properties are `bidi_enabled: false` and
`bidi_direction: LeftToRight` which corresponds to the typical
bidi-unaware mode of most terminals.
It is possible to live reload the config to change the effective
defaults, but note that they apply, by design, to new lines being
processed through the terminal. That means existing output is
left unaffected by a config reload, but subsequently printed lines
will respect it. Pressing CTRL-L or otherwise contriving to have
the running application refresh its display should cause the
refreshed display to update and apply the new bidi mode.
refs: #784
This commit is larger than it appears to due fanout from threading
through bidi parameters. The main changes are:
* When clustering cells, add an additional phase to resolve embedding
levels and further sub-divide a cluster based on the resolved bidi
runs; this is where we get the direction for a run and this needs
to be passed through to the shaper.
* When doing bidi, the forced cluster boundary hack that we use to
de-ligature when cursoring through text needs to be disabled,
otherwise the cursor appears to push/rotate the text in that
cluster when moving through it! We'll need to find a different
way to handle shading the cursor that eliminates the original
cursor/ligature/black issue.
* In the shaper, the logic for coalescing unresolved runs for font
fallback assumed LTR and needed to be adjusted to cluster RTL.
That meant also computing a little index of codepoint lengths.
* Added `experimental_bidi` boolean option that defaults to false.
When enabled, it activates the bidi processing phase in clustering
with a strong hint that the paragraph is LTR.
This implementation is incomplete and/or wrong for a number of cases:
* The config option should probably allow specifying the paragraph
direction hint to use by default.
* https://terminal-wg.pages.freedesktop.org/bidi/recommendation/paragraphs.html
recommends that bidi be applied to logical lines, not physical
lines (or really: ranges within physical lines) that we're doing
at the moment
* The paragraph direction hint should be overridden by cell attributes
and other escapes; see 85a6b178cf
and probably others.
However, as of this commit, if you `experimental_bidi=true` then
```
echo This is RTL -> عربي فارسی bidi
```
(that text was sourced from:
https://github.com/microsoft/terminal/issues/538#issuecomment-677017322)
then wezterm will display the text in the same order as the text
renders in Chrome for that github comment.
```
; ./target/debug/wezterm --config experimental_bidi=false ls-fonts --text "عربي فارسی ->"
LeftToRight
0 ع \u{639} x_adv=8 glyph=300 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
2 ر \u{631} x_adv=3.78125 glyph=273 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
4 ب \u{628} x_adv=4 glyph=244 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
6 ي \u{64a} x_adv=4 glyph=363 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
8 \u{20} x_adv=8 glyph=2 wezterm.font("Operator Mono SSm Lig", {weight="DemiLight", stretch="Normal", italic=false})
/Users/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
9 ف \u{641} x_adv=11 glyph=328 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
11 ا \u{627} x_adv=4 glyph=240 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
13 ر \u{631} x_adv=3.78125 glyph=273 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
15 س \u{633} x_adv=10 glyph=278 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
17 ی \u{6cc} x_adv=4 glyph=664 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
19 \u{20} x_adv=8 glyph=2 wezterm.font("Operator Mono SSm Lig", {weight="DemiLight", stretch="Normal", italic=false})
/Users/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
20 - \u{2d} x_adv=8 glyph=276 wezterm.font("Operator Mono SSm Lig", {weight="DemiLight", stretch="Normal", italic=false})
/Users/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
21 > \u{3e} x_adv=8 glyph=338 wezterm.font("Operator Mono SSm Lig", {weight="DemiLight", stretch="Normal", italic=false})
/Users/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
```
```
; ./target/debug/wezterm --config experimental_bidi=true ls-fonts --text "عربي فارسی ->"
RightToLeft
17 ی \u{6cc} x_adv=9 glyph=906 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
15 س \u{633} x_adv=10 glyph=277 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
13 ر \u{631} x_adv=4.78125 glyph=272 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
11 ا \u{627} x_adv=4 glyph=241 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
9 ف \u{641} x_adv=5 glyph=329 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
8 \u{20} x_adv=8 glyph=2 wezterm.font("Operator Mono SSm Lig", {weight="DemiLight", stretch="Normal", italic=false})
/Users/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
6 ي \u{64a} x_adv=9 glyph=904 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
4 ب \u{628} x_adv=4 glyph=243 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
2 ر \u{631} x_adv=5 glyph=273 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
0 ع \u{639} x_adv=6 glyph=301 wezterm.font(".Geeza Pro Interface", {weight="Regular", stretch="Normal", italic=false})
/System/Library/Fonts/GeezaPro.ttc index=2 variation=0, CoreText
LeftToRight
0 \u{20} x_adv=8 glyph=2 wezterm.font("Operator Mono SSm Lig", {weight="DemiLight", stretch="Normal", italic=false})
/Users/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
1 - \u{2d} x_adv=8 glyph=480 wezterm.font("Operator Mono SSm Lig", {weight="DemiLight", stretch="Normal", italic=false})
/Users/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
2 > \u{3e} x_adv=8 glyph=470 wezterm.font("Operator Mono SSm Lig", {weight="DemiLight", stretch="Normal", italic=false})
/Users/wez/.fonts/OperatorMonoSSmLig-Medium.otf, FontDirs
;
```
refs: https://github.com/wez/wezterm/issues/784
This commit centralizes the focus-loss logic to the Window so
that activating a new tab will deactivate the pane in the current
window.
Note that this cannot see overlays in the gui, but overlays shouldn't
care about focus, so it should be ok.
refs: https://github.com/wez/wezterm/discussions/796
This commit enables the following config to work for local (not mux yet!)
panes:
```lua
local wezterm = require 'wezterm'
wezterm.on("format-tab-title", function(tab, tabs, panes, config, hover, max_width)
if tab.is_active then
return {
{Background={Color="blue"}},
{Text=" " .. tab.active_pane.title .. " "},
}
end
local has_unseen_output = false
for _, pane in ipairs(tab.panes) do
if pane.has_unseen_output then
has_unseen_output = true
break;
end
end
if has_unseen_output then
return {
{Background={Color="Orange"}},
{Text=" " .. tab.active_pane.title .. " "},
}
end
return tab.active_pane.title
end)
return {
}
```
refs: https://github.com/wez/wezterm/discussions/796
We budget size based on the x_advance, which can be 1 pixel less
than the width of the glyph texture, so we could often end up
omitting the last character in "Launcher" or "default" in the
tab title or right status area.
This commit uses x_advance in both places.
Make the scrolling mostly independent of the active row; adjust
the top row when hitting the top/bottom edges of the display.
Mouse movement no longer changes the scroll position. Instead,
the wheel is used to scroll the list.
refs: https://github.com/wez/wezterm/issues/1485
This isn't ideal, but it is better than previously: we would
close the window and before the Drop impl had updated the
list of known windows, we'd try to re-assign that window
to another mux window in a different workspace, but it would
never appear because the window was closed.
refs: https://github.com/wez/wezterm/issues/1531
Originally I had this the other way around but it was problematic
when considering things like maximized, font scaling and full screen
states.
refs: https://github.com/wez/wezterm/issues/1531
Rather than just quitting the app and potentially silently killing off
a number of panes that might be running in other workspaces, we now
will pick one of those workspaces and activate it.
refs: #1531
This action causes the active workspace for the gui to change.
If the name is omitted a random name will be generated.
If the workspace doesn't exist, it will be be created.
The optional spawn parameter can be used to launch a specific
program into the new workspace; if omitted, the default prog
will be used.
The gui only supports a single active workspace. Switching workspaces
will repurpose existing gui windows and re-assign them to windows
in the new workspace, adjusting their size to fit those windows,
spawning new windows or closing unused windows as required.
The gui now exits when there are no panes in the active workspace,
rather than no panes at all.
refs: #1531
The mux now has a notion of which client is actively doing things.
This allows, for example, newly spawned windows to take on the
active workspace for a given client.
The gui now assigns a client id on startup, and sets the active
workspace to `default`.
The mux server temporarily overrides the active id to that of
the currently dispatching client when processing PDUs.
refs: https://github.com/wez/wezterm/issues/1531
Tidies up some code duplication within the mux protocol handler.
Move some of the logic into Mux, remove legacy Spawn Pdu to reduce
more duplication.
I want to dedup some of the similar logic that exists in the gui
spawn implementation as well in a follow up.
`ScrollByPage` can accept non-integer values in the configuration.
This allows fractional page scrolling, such as by half a page.
The default remains the same, at 1 page.
This is not exposed through any UX; the mux api allows setting
the workspace and propagating information about windows whose
workspace has changed.
Windows start with a blank workspace name.
This is just plumbing; nothing uses it yet.
refs: #1531
This is a similar race condition to one we had before with the
multiplexer, where the connection UI made us think that we didn't
need to start a new process.
Additionally, the attach method would unconditionally create a
new client without checking whether we already had one.
In the case that the published symlink is stale, our default
client connection logic was to retry connecting with backoff
to give a newly spawned server a chance to startup.
In the context of a newly launched gui process checking to see
if an existing gui process can serve the same request, we don't
need to give it any grace: it will either answer immediately
or be deemed not useful.
This commit limits us to a single connection attempt in the case
where we're not automatically starting the server, which in turn
constrains the overhead to something in the order of microseconds
rather than nearly 0.5 seconds.
While we're in here, I noticed that if we thought we had a socket
to try and that failed, we'd always try to publish a new symlink.
However, if we failed due to mismatched version info, we shouldn't
publish over the top of the already running instance.
refs: #1529
user vars were stubbed out. This commit adds storage for them
in the mux client and adds a new notification that publishes each
var as it is changed. That differential stream is applied to the
storage in the mux client when it is received.
```lua
local wezterm = require 'wezterm'
wezterm.on("update-right-status", function(window, pane)
local woot = pane:get_user_vars().woot
window:set_right_status(tostring(woot))
end);
return {
unix_domains = {
{name="unix"},
},
}
```
then running:
* `wezterm connect unix`
* in that session: `printf "\033]1337;SetUserVar=%s=%s\007" woot `echo -n nice | base64``
causes `nice` to show in the status area.
refs: #1528