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
This puts us in a better position for the future to be able
to configure whether we use wezterm, tmux or no multiplexing.
Today we allow wezterm or no multiplexing.
Add docs on this new setting.
refs: https://github.com/wez/wezterm/issues/1456
If an ssh domain is set to use_multiplexer=false, it is now
possible to `wezterm connect` to it.
Previously, it was only possible to connect to domains that
used the mux client.
refs: https://github.com/wez/wezterm/issues/1456
If we decide we want re-use and existing gui due to config differences
we shouldn't then publish the new, differently configured, gui as
the canonical path for that display/class.
Clarify the message that we print when re-using an existing gui
in case someone doesn't want that behavior.
When set, changes the default domain to the domain with the specified
name, which potentially affects the default program.
eg: default_domain = "WSL:Ubuntu-18.04" will cause the initial tab
to be spawned via WSL.
The idea is that we want to be able to spawn into wsl with the
convenience of a local domain, but without the awkwardness of
it having a different filesystem namespace.
It would also be great to be able to spawn a new tab or pane
in the same domain and pick up the cwd of the existing one.
The WslDomain allows the user to explicitly list WslDomains
and control eg: default shell, username and so on, but wezterm
will pre-fill a default list of domains based on the `wsl -l`
output that we were already using in the launcher menu.
The existing LocalDomain has been augmented to understand that
it may need to fixup a command invocation and that gives it
the opportunity to rewrite the command so that we can launch
it via `wsl.exe` and pass down the cwd and so on.
This same technique might be extensible to eg: docker instances
in the future.
This commit:
* Introduces `wsl_domains` config and its default list of wsl
distributions
* Creates LocalDomain instances from that list
* The launcher menu allows spawning a new tab via one of those domains
The client machinery would try to spawn an async attempt at
detaching the unixdomain from the mux on shutdown, but since
we're in the middle of tearing down the scoped executor,
we could sometimes panic.
The client we have in this situation isn't actually associated
with a domain, so we don't need to detach in that situation.
Formalize that by making it an Option, and address the
fanout.
Using the new publish/discovery stuff from the past couple of commits,
if we can find a matching socket path for a running gui, and the
configuration is likely a match, then use the mux protocol to talk
to the already running gui and ask it to spawn the equivalent program
into the same process.
refs: https://github.com/wez/wezterm/discussions/1486
We need 100% of the info for it to work correctly, so this commit:
* Exposes the keyboard encoding mode via the Pane trait
* Adds the scan code to the RawKeyEvent
* Has the GUI perform the encoding if the keyboard is set that way
* Removes the basic encoder from termwiz in favor of the gui level one
The net result is that we bypass the Pane::key_up/Pane::key_down methods
in almost all cases when the encoding mode is set to win32-input-mode.
There is now a config option: allow_win32_input_mode that can be
used to prevent using this mode.
refs: #1509
When spawned with no WEZTERM_UNIX_SOCKET environment set,
we now prefer to resolve the gui instance, falling back to
the mux if it doesn't look like the gui is running.
`wezterm cli --prefer-mux` will use the original behavior of
trying to resolve the path from the unix domain in the config.
Nothing generates them right now, and the mux client has no
way to represent them on the wire.
I'm considering constraining them to just win32 for now.
refs: https://github.com/wez/wezterm/issues/1509
It was showing the whole text for the cluster for each shaped
glyph.
Fix it up to map back to the corresponding cell range and
extract the text from the line.
Include the x_advance metric in the output while we're in
there.
refs: https://github.com/wez/wezterm/issues/1333
When rendering the IME composing text, I noticed that for the Korean
input sequence: shift+'ㅅ' followed by 'ㅏ' we'd render the 'ㅆ' (the
shifted first character) in black and the composing 'ㅏ' in white
against the cursor color, and that was very difficult to read,
especially at the default font size.
To resolve this, this commit:
* Forces clustering to break around the cursor boundary, so that
we treat the cursor position as its own separately styled cluster
* Adjusts cursor/bg rendering so that we always consider the start of
the cluster for the colors of that run. We are guaranteed that a
ligatured sequence will fit in the background area anyway.
This has the effect of "breaking" programming ligatures such as '->'
when cursoring through them, and decomposing them into their individual
'-' and '>' glyphs, which is a reasonable price to pay for being able
to see things better on screen.
refs: https://github.com/wez/wezterm/issues/1504
refs: https://github.com/wez/wezterm/issues/478
When we translate a dead key, send the composed event immediately
and don't try to route the current key press via the IME.
Improve rendering when in the composing state: overlay the composing
text at the cursor position to show what the composing text would
look like, even though it hasn't been committed to the input stream
yet.
refs: https://github.com/wez/wezterm/issues/1504
For Korean text input, pressing SHIFT and then typing in certain
keys begins a composition sequence. Our logic for when to route
via the IME got so distracted by ALT that it didn't consider SHIFT
and didn't send this sequence to the IME, so we'd fail to compose
those sequences.
While poking at this, I realized that we should treat this composition
similarly to dead keys, in that we can signal the term window to
highlight the cursor color and report that status.
There's some further work to do: the composing text should be rendered
by us. So far our IME integration assumes that the IME itself will
render over the top of our window, but for this particular input
it doesn't do that.
refs: https://github.com/wez/wezterm/issues/1504
The same core code is used to render both the tab navigator
and the launcher. The context is specified using some flags
so that you don't get an unholy mess in both places.
The net result of this is that the tab navigator now supports
fuzzy matching.
refs: #664
refs: 1485
* Allow selecting the first few rows by number
* Allow scrolling through long lists of items
* Add actions from key assignments to list
refs: #1485
refs: #1413
Since we now have RawKeyEvent and a sane way to indicate handling,
we don't need these any more, and it simplifies key dispatch to
remove them.
refs: #1483
Pass down whether we are in a live resize to the gui layer, so that
we don't incorrectly assume that the scale has changed, and fight
with the window manager.
Built this on my mac: will need to fixup for windows and linux.
refs: https://github.com/wez/wezterm/issues/1491
This commit adds a couple of helper methods that provide insight into
the state of the keyboard layer.
The intent is for users to add status information about the keyboard
state.
This commit also ensures that we schedule an update when the leader
key duration expires, and ensures that we close out the leader state
for an invalid key press.
refs: #686closes: #688
```lua
local wezterm = require 'wezterm';
wezterm.on("update-right-status", function(window, pane)
local leader = ""
if window:leader_is_active() then
leader = "LEADER"
end
local dead = ""
if window:dead_key_active() then
dead = "DEAD"
end
window:set_right_status(leader .. " " .. dead)
end);
return {
leader = { key="a", mods="CTRL" },
colors = {
dead_key_cursor = "orange",
},
}
```
When set, the cursor will change to this color during dead key
or leader key processing.
```lua
return {
colors = {
dead_key_cursor = "orange",
},
}
```
refs: #686
refs: #688
on macos only (for now), we generate a RawKeyEvent prior to
dead key or IME composition and route it to the window to give it
a chance to handle the event.
RawKeyEvent handling is scoped only to key assignments, not generating
input for the terminal.
A raw key event can be marked as handled to prevent moving on to
performing composition and generating cooked key input.
refs: https://github.com/wez/wezterm/issues/877
```lua
local wezterm = require 'wezterm'
return {
debug_key_events = true,
keys = {
{key="phys:Q", action=wezterm.action{SendString="woot"}},
},
}
```
The above will send "woot" to the pane whenever the key in same
physical position as Q on an ANSI standard US keyboard is pressed.
refs: https://github.com/wez/wezterm/issues/1483
This comes from a time where our quads were always locked to grid
positions. We don't need it any more: we can simply add the adjustments
to the quad positions that we set.
Removing it makes the vertex a bit smaller and reduces the amount
of GPU accessible memory we need to use.
I'm running down a weird thing where the main font renders weirdly
when the title font is 12 pt vs the main font 10 pt.
I thought there might have been a cache invalidation issue and
realized that we could have an A-B-A style issue with the font_ptr
stuff, so I replaced it with an incrementing id.
That didn't fix the thing I was looking at, but does feel a bit
nicer overall.
The default we use on macOS looks decent. Roboto is a similar
looking font that we can use for the other platforms.
I may make it the same on all three once I've had a chance
to compare it on a mac.
Previously, we would implicitly set it to the special SEQ_ZERO
value, but since that value always flags the row as changed,
it causes some over-invalidation issues downstream in wezterm.
This commit makes that parameter required, so that the code that
is creating a new Line always passes down the seqno from that event.
refs: #1472
We only need to recompute when the tab content changes, or when
the window is resized, plus invalidations of the shape cache
of texture atlas filling up.
Hover events don't need to re-shape.
We can now also place the tab bar at the bottom of the screen again.
The main tab area now takes the background color from the first
cell in a formatted tab bar item as the full background color
for the whole tab area, which looks a lot nicer than just the
using that color for the minimal bounding box of the tab text.
This commit adds a CSS box model inspired element / layout
facility, and replaces the hand implemented fancy tab bar
element render.
This makes the code for fancy tab bar much easier to read
and update.
The right status area now expands to the full height of the
tab bar area, and uses a line height of 2.0, which makes
it line up nicely in the tab bar.
Switch to the slightly more structured verbose output of `wsl -l -v`
in the hope that we are less prone to localization issues and
are more robust in the face of future changes.
refs: #1462
Rather than hardcode a fixed default value in the config crate, define
the default as optional and leave it to the font crate to compute
the value.
This is a step towards allow introducing system dependent GUI related
code to resolve/understand the title font: we can't put that directly
in the config crate.
Add `get_foreground_process_name` to both Pane and the lua wrapper.
Add `foreground_process_name` and `current_working_dir` fields to
`PaneInformation`. In order for those to be dynamically fetched,
switch the lua conversion for `PaneInformation` to be a UserData
with field access methods. It's a little more verbose but allows
us to lazily compute these two new fields.
refs: https://github.com/wez/wezterm/discussions/1421
refs: https://github.com/wez/wezterm/issues/915
refs: https://github.com/wez/wezterm/issues/876
This commit expands quick select mode so that you can trigger it
with distinct sets of patterns (eg: urls on one key assignment,
hashes on a different key assignment), different alphabets,
and lastly, the option to perform a different action from
the default copy action.
You can pair this with `action_callback` to run lua code to
do something with the selected text.
This commit also adds `wezterm.open_with`, a helper function
for opening documents/URLs.
refs: #846
refs: #1362
The label dedup code has panicked on me a couple of times.
I managed to capture the line number, so this commit aims to
capture some state to try to understand what's going on,
and importantly, to avoid the actual panic part.
refs: #1271
permits iTerm2 images to be drawn anywhere on screen without
scrolling the cursor, including the bottom row.
Also included is a check in fcwrap.rs to_range_set(), without which
was causing a panic at runtime due to subtraction from unsigned
leading to overflow.
This helps us correctly set the size of the image cell
for the case where we have a partial cell at the right/bottom
edge of an image being mapped across cells.
refs: #1270
Move away from the imprecise simple pow version and over to a
version that properly respects the linear and non-linear portions
of the curve.
refs: #1025
On Windows, both EGL and MESA render modes were too dark.
After a bit of hunting around what I found made EGL and MESA
consistent with my default nVidia GPL rendering was:
* Tell glium that our shader outputs srgb
* Add explicit gamma conversion from linear to srgb in the shader
AFAICT, that shouldn't be required, but it seems as though something
deep in glium really wants to apply some kind of gamma conversion,
and it seems to select the wrong kind unless we set things explicitly
to SRGB.
There are some people complaining about this in
https://github.com/glium/glium/issues/1615.
I actually tried to move entirely aware from the glium srgbtexture2d
type in the hope of having explicit control over the gamma, but the
issue is in what happens to the outputs rather than the inputs.
It appears to me as though the text now looks slightly less
intense, so I think this may be what we need for the gamma issue
in https://github.com/wez/wezterm/issues/544 and potentially
also https://github.com/wez/wezterm/issues/1025
refs: https://github.com/wez/wezterm/issues/1373
Adds some plumbing to allow the GUI to implement a download handler
and connect that up for iterm2 image/file transfers that have their
inline property set to false.
Previously we'd just log an error.
Now we will by default download the file to the user's download
directory.
This behavior can be turned off via the new `allow_download_protocols`
configuration setting.
File transfers can be initiated on a remote host via the
https://iterm2.com/utilities/it2dl script.
When the download completes, a toast notification is shown that will
open the file when clicked.
refs: https://github.com/wez/wezterm/discussions/1450
Remove special case for blocks where we switched it out for a blank
sprite and instead varied the cell background.
We now always render a matching cursor sprite as a separate layer
over the top of the text background color, but below the text
foreground layer.
This is preparing for https://github.com/wez/wezterm/issues/1432
Make bar/line cursors use the text foreground color when reverse
video cursors are enabled, per @VKondakoff:
https://github.com/wez/wezterm/issues/1076#issuecomment-978214136
Finally getting around to fixing this usability wart: this commit
changes the behavior of Window closing so that you can close a window
containing multiplexer panes without prompting and without killing
off those panes.
This is achieved through some plumbing:
* The mux can now advise Domains about an impending window closure,
giving them the opportunity to "do things" in readiness.
* The mux client domain informs the container ClientPane instances
to ignore the next Pane::kill call, which would otherwise inform
the mux server to kill the remote pane
* Pane:can_close_without_prompting now requires a CloseReason.
* ClientPane's can_close_without_prompting impl allows Window closing
without prompting on the assumption that the ignore-next-kill hack
above is working
refs: #848
refs: #917
refs: #1224
The mux client just returns a dummy reader, and some overlays
have panicking stubs: just allow for them to return None
instead of potentially spawning a useless thread.
Previously, we would only look at the `check_for_updates` config
on startup.
This commit adjusts the update checker logic so that we always
start it, and that we respect config reloads.
Only show the update window and/or generate a toast notification
is the current wezterm-gui process is the eldest of the set of
running wezterm-guis.
This avoids spamming the user with update information.
refs: https://github.com/wez/wezterm/issues/1402
This code was partially replicating the initial window setup
where we didn't necessarily know the dpi, but in the context
where this is run, we do know the dpi for the window, so
let's consistently use that number throughout.
refs: #1039
The intent is to workaround what appears to be an i3 bug.
Not totally sure this is a good change, but let's try it!
Might also help with an issue on macos.
refs: #1140
refs: #1310
This moves away from using special block glyphs for the lines and
just draws lines directly.
In addition, since these lines are no longer constrained to available
glyphs or glyph boundaries, we can now render lines that cross when
there are a mix of horizontal and vertical splits, which looks a
bit nicer.
refs: #1256
Assuming that the window config reloaded hook doesn't actually change
anything, this will avoid a cycle where we keep triggering the hook
over and over.
This is a fairly far-reaching commit. The idea is:
* Introduce a unicode_version config that specifies the default level
of unicode conformance for each newly created Terminal (each Pane)
* The unicode_version is passed down to the `grapheme_column_width`
function which interprets the width based on the version
* `Cell` records the width so that later calculations don't need to
know the unicode version
In a subsequent diff, I will introduce an escape sequence that allows
setting/pushing/popping the unicode version so that it can be overridden
via eg: a shell alias prior to launching an application that uses a
different version of unicode from the default.
This approach allows output from multiple applications with differing
understanding of unicode to coexist on the same screen a little more
sanely.
Note that the default `unicode_version` is set to 9, which means that
emoji presentation selectors are now by-default ignored. This was
selected to better match the level of support in widely deployed
applications.
I expect to raise that default version in the future.
Also worth noting: there are a number of callers of
`unicode_column_width` in things like overlays and lua helper functions
that pass `None` for the unicode version: these will assume the latest
known-to-wezterm/termwiz version of unicode to be desired. If those
overlays do things with emoji presentation selectors, then there may be
some alignment artifacts. That can be tackled in a follow up commit.
refs: #1231
refs: #997
It appears as though Menlo is the only font on macos to contain the
heavy ballot cross symbol, which is commonly used on macos (eg: in
`brew` output).
Our fallback list, despite starting with Menlo, didn't include menlo
itself in the candidates.
Furthermore, `ls-fonts` wouldn never see the result of the system
fallback resolution because it didn't know to try again, and was
using the list of handles from before the fallback.
This commit resolves all of these concerns.
refs: #849
Since we may have two different sizes/namespaces of fonts between
the title font and the main terminal font, we need to be a bit more
careful to pass down distinguishing font information when caching
glyphs.
In addition, I noticed that the advance for custom block glyphs
(eg: powerline!) weren't right in the tab bar. To resolve this,
when shaping, we skip using the glyph from the font and synthesize
a placeholder with the appropriate advance.
We were truncating the right-status text because we were passing
the padded number of cols for the tab bar, but since the tab bar
now exists outside the padding, that value was too small.
This commit introduces the `Dimension` type which allows specifying
a value in a variety of units; pixels, points, cells, percent.
`Dimension` needs contextual information to be evaluated as pixel
values, which makes resolving the value from the config slightly
more of a chore.
However, this type allows more flexible configurations that scale
with the font size and display dpi.
refs: #1124, #291, #195
The previous commit was partially OK, but the main cause of
emoji being wonky was this bit of macos specific code that I
added ages ago.
Remove that hack and the portion of the code from the previous
commit that was working to undo it.
This should make the baselines consistent across all platforms.
refs: #1203
Avoid accidentally scaling the tab bar when using IncreaseFontSize.
Use a "better" default title font based on the platform.
Avoid a gap between bottom of tab button and dividing line at
certain font sizes.
When split horizontally, selecting multiple lines at the top of the left
pane could paint a horizontal selection line all the way across the rest
of the terminal to the right hand edge.
Removes the dependency on knowing where the pane top/left position
is so that the line render routine could be used in more places.
Adjusts the tab bar and scroll bar positioning so that the tab bar
ignores window padding and is always flush with the top/bottom window
edge (full width as well), and that the scroll bar top/bottom respects
the tab bar position and height.
More of a "fix"; we use some heuristics based on the bearing
and glyph width to figure out if a sequence looks like a funky
ligature that moves left to render the glyph.
This may be prone to false positives, but the consequences are low:
when we think a glyph is part of a ligature, then rather than using
the cursor_fg color (which is typically black, or close to invisible),
we retain the normal text fg color.
This way the portion of the glyph outside of the cursor retains its
foreground color, and just the cell containing the cursor may have
a slightly funky fg color in the case where the heuristic was bad.
closes: #478
`use_fancy_tab_bar` switches to an alternate rendering of the tab
bar that uses the window_frame config to get a proportional
title font to use to render tabs, as well as rendering a few
additional elements to space out and make the tabs feel more
like tabs.
Computing the number of tabs doesn't respect the alternate font
at this time.
Formatted tab item foreground and background colors are also
not respected at this time.
refs: #1180
We now compute the cap-height from the rasterized glyph data.
Moved the scaling action of use_cap_height_to_scale_fallback_fonts from
glyphcache into the font resolver: when enabled, and we have data
about the baseline font and the font being resolved, then the resolving
font will be scaled such that the cap-height of both fonts has the same
pixel size.
The effect of this is that `I` glyphs from both fonts should appear to
have the same height.
Added a row of `I`'s in differing styles at the bottom of styles.txt
to make this easier to visualize.
refs: #1189
This is to handle situations such as some versions of the Terminus
bitmap font, where the individual bitmap strike sizes are broken
out across multiple individual files.
Font matching now passes down the nominal pixel height based on
the current DPI and font scale factor, and will use that to select
the font file that has the closest pixel size.
Previously, it would be potentially undefined which of the Terminus
font files would be selected.
refs: https://github.com/wez/wezterm/issues/1189
This commit adjusts the the window event routing/queuing so that
a queued event can capture a pane_id other than the focused pane.
Since we only allow one queued instance of a given named event in a
window, a consequence of this is that multiple bell events coming
from different panes at the same time may race and the loser's
event will be dropped. We log a warning in that case.
refs: #3
This commit introduces a mechanism for specifying resize increments
for a window, and then arranges for the termwindow to set those
to match the current font cell metrics.
This should help to avoid cases where there is excess padding pixels
resulting from the window being slightly larger than computed number
of cells and the font metrics.
Fast-clicking users generally expect to be able to rapidly do regular selections
or otherwise cancel double/triple/quad clicks, so significant mouse movement should end the streak.
Allowing tiny pixel movements to account for touchpads is necessary.
Fortunately, the position here is already in character grid cells, which provides enough margin for this.
Other code editors like gedit also seem to do this based on the character grid.
It appears as though kakoune hides the terminal cursor and renders
its own version of the cursor.
The hidden state was being picked up by the copymode overlay,
making it awkward to use.
This commit forces the cursor to be visible (and a block) when
copy mode is active.
closes: #1113
I think this is a hangover from the older logic to figure out
the initial sizing, and I suspect that it is what is causing
refs: 1074
So this is a speculative change to see if it helps!
This splits rendering into 3 passes:
* background pass for z-index < 0. This is for solid background colors,
background images, and image attachments with z-index < 0.
Rendered with regular alpha blending.
* glyph pass: for glyphs at z-index==0. This is rendered with dual
source blending enabled to facilitate subpixel aa appearance.
* top layer pass for z-index >= 0 graphics. This is rendered with
regular alpha blending.
This avoids weird effects, like images with alpha shining through
the back of the window when the window itself isn't transparent.
refs: #544
transparent images weren't always blending correctly, and were
instead shining through.
This might also have affected cursors.
It may also be a factor in a couple of recent reports of excessive
boldness which looked like funky over-alpha multiplication.
Let's see what people say about this.
This makes the comparison in https://github.com/wez/wezterm/issues/544
work for me on mac, linux (x11, wayland) and also on Windows but
only using WGL.
It looks like we can use the proper colorspace on all targets
except for ANGLE EGL. For whatever reason, the combination of
glium and ANGLE EGL on windows over-gamma corrects.
AFAICT, the framebuffer and perhaps the surfaces it creates
don't indicate srgb support, and whatever combination of status
they return tickles glium's srgb stuff the wrong way.
I think the "solution" is just to directly use WGL by default.
EGL was on by default because it tended to be more survivable
when graphics card drivers were updated, but the last couple
of times I updated mine it still killed wezterm anyway.
refs: #544
Add a more general dragging thingy and use that to know when we
are dragging splits or the scroll thumb.
Fixup scrollbar math, which didn't account for whether the tabbar
was shown and which might cause the scroll thumb to jump around
on first drag (resolves#568)
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