Tidy some things up to avoid some dead code and redundant impls.
Make it easier to select whether you want to implement the new
methods in terms of the old, or the old methods in terms of
the new in a given pane impl.
Remove the faulty cache key stuff and hang references to the cached
data directly off the underlying Line. That makes the association
between the the Line and the data O(1) plus some basic cache
invalidation checks.
Adjust the shape cache portion of this to use the same ID for the
shape, so that things that invalidate just the quads (such as cursor
movement when not composing, and selection) only need to recompute
the quads without re-shaping.
Adds Pane::for_each_logical_line_in_stable_range_mut and
Pane::with_lines_mut which allow iterating mutably over lines.
The idea is that this will allow the renderer to directly cache
data in the Line via its appdata without having to build cumbersome
external caching logic and managing cache keys.
This commit just swaps the implementation around for localpane
and sanity checks that the renderer functions.
Various overlays and the mux client don't properly implement these
yet and current warn at compile time and panic at runtime.
To follow is the logic to cache the data and make sure that it
works the way that I think before converting the other Pane
implementations.
The cache key isn't quite right, leading to some artifacts
in some cases.
I have a cunning plan, but it will take me a bit to wrap
it up, so in the meantime, disable these caches.
refs: https://github.com/wez/wezterm/issues/2455
It didn't really belong there; it was added as a bit of a hack
to propagate screen reverse video mode.
Move that to the RenderableDims struct and remove the related
bits from Line
Similar to selection_fg, setting the cursor_fg to transparent ("none")
will use the foreground color of the text behind the cursor.
refs: https://github.com/wez/wezterm/issues/1835
I broke this with the performance changes I pushed earlier today.
Poke a hole in caching for it as well, as it doesn't use the seqno
to track changes like the rest of the Line based data.
cc: @DeadlySquad13
This doesn't mean that it renders at 1fps, just that it goes through
the simpler path of scheduling on the boundaries rather than at
animation_fps through the intermediate stages, where it would be
useless.
Introduces a heap-based quad allocator that we cache on a per-line
basis, so if a line is unchanged we simply need to copy the previously
computed set of quads for it into the gpu quad buffer.
The results are encouraging wrt. constructing those quads; the
`quad_buffer_apply` is the cost of the copy operation, compare with
`render_screen_line_opengl` which is the cost of computing the quads;
it's 300x better at the p50 and >100x better at p95 for a full-screen
updating program:
full 2880x1800 screen top:
```
STAT p50 p75 p95
Key(quad_buffer_apply) 2.26µs 5.22µs 9.60µs
Key(render_screen_line_opengl) 610.30µs 905.22µs 1.33ms
Key(gui.paint.opengl) 35.39ms 37.75ms 45.88ms
```
However, the extra buffering does increase the latency of
`gui.paint.opengl` (the overall cost of painting a frame); contrast the
above with the latency in the same scenario with the current `main`
(rather than this branch):
```
Key(gui.paint.opengl) 19.14ms 21.10ms 28.18ms
```
Note that for an idle screen this latency is ~1.5ms but that is also true
of `main`.
While the overall latency in the histogram isn't a slam dunk,
running `time cat bigfile` is ~10% faster on my mac.
I'm sure there's something that can be shaved off to get a more
convincing win.
This is really a proof of concept commit; I want to be able to pass
more structured data into the shader as uniforms and the basic
macros provided by glium make that a bit awkward.
What I came up with is a slightly more dynamic uniform builder
thingy.
I'm using this to pass in a copy of the various blinking easing
functions.
Those are incomplete and unused, but it shows that the technique works.
Use the font height as the basis for the size, rather than the width,
to avoid the buttons being too condensed.
Explicitly use the pixel height for the dimensions so that the
buttons are square.
refs: https://github.com/wez/wezterm/issues/2399
The prior mutually exclusive behavior kept surprising people so let's
just flip this around.
This is potentially a "breaking" change for folks, but I think it is
worth it.
I was seeing a black "hole" in the center of this gradient:
```
background = {
{
source = {
Gradient={
colors = {"rgb(45,26,109)", "black"},
orientation = {
Radial={
cx = 0.75,
cy = 0.75,
radius = 1.25,
}
},
}
},
width="100%",
height="100%",
},
```
setting noise=0 "fixed" it, so this commit localizes that fix
to the center of the gradient by preventing noise from wrapping
around the gradient.
This breaking API change allows us to explicitly generate EOF when the
taken writer is dropped.
The examples have been updated to show how to manage read, write
and waiting without deadlock for both linux and windows.
Need to confirm that this is still good on macOS, but my
confidence is high.
I've also removed ssh2 support from this crate as part of this
change. We haven't used it directly in wezterm in a long while
and removing it from here means that there is slightly less code
to keep compiling over and over.
refs: https://github.com/wez/wezterm/discussions/2392
refs: https://github.com/wez/wezterm/issues/1396
Previously, we'd unconditionally enable dual source blending for the
text foreground layer when rendering. That meant that if the user had
configured the fg color to include an alpha value it would get "stamped
through" the draw all the way to the background, making that whole pixel
take on that alpha value rather than allowing it to blend through the
way you might expect.
In prior releases that didn't matter, but since we now allow configuring
the fg color with alpha, and allow using escape sequences to set the fg
for a span to something with alpha, there is now a much higher chance of
something looking weird.
Dual source blending is only really needed for subpixel-aa and that
isn't enabled by default.
This commit changes the behavior to use regular alpha blending if the
main config (rather than a per-font override) hasn't set the freetype
load/render target to one that enables subpixel-aa.
That means that alpha channel values work as expected for fg color
by default.
If you want to enable subpixel-aa you need to enable it globally
and be aware that it will cause weirdness when trying to use alpha
channels for the fg text color.
The docs now also indicate this behavior.
This limitation could be removed by making text rendering significantly
more complex and I don't fancy doing that at this time.
Since the initial attach is async, we'd create the window at the
default/initial size and then never reconcile the size of the remote
tabs once they'd attached.
This commit introduces an event that allows the gui window to do that.
The action that it takes is to take the max width and height between
its current size and the size of a newly added tab and resizes to
that new size, if it changed.
refs: https://github.com/wez/wezterm/issues/2133
refs: https://github.com/wez/wezterm/issues/2351
Allows the following assignment actions; I was just over-using z for
no real reason, I'm not suggesting that these are good assignments.
```
-- move the cursor backwards to the start of the current zone, or
-- to the prior zone if already at the start
{ key = 'z', mods = 'NONE', action = act.CopyMode 'MoveBackwardSemanticZone' },
-- move the cursor forwards to the start of the next zone
{ key = 'Z', mods = 'NONE', action = act.CopyMode 'MoveForwardSemanticZone' },
-- start selecting by zone: both the start point and the cursor
-- position will be expanded to the containing zone and the union
-- of those two will be used for the selection
{
key = 'z',
mods = 'CTRL',
action = act.CopyMode { SetSelectionMode = 'SemanticZone' },
},
-- like MoveBackwardSemanticZone by only considers zones of the
-- specified type
{ key = 'z', mods = 'ALT', action = act.CopyMode { MoveBackwardZoneOfType ='Output' }},
-- like MoveForwardSemanticZone by only considers zones of the
-- specified type
{ key = 'Z', mods = 'ALT', action = act.CopyMode { MoveForwardZoneOfType ='Output' }},
```
refs: https://github.com/wez/wezterm/issues/2346
This makes those fields usable in `wezterm cli list --format json`.
This doesn't change the ABI of the mux protocol, but prior to
this commit, those fields were always 0.
refs: #2319
Adjusts how mouse events are matched so that we can now indicate whether
mouse reporting and alt-screen should be considered as part of the event
trigger criteria.
refs: #2173
refs: #581
This doesn't really change any behavior, but adjusts the types
such that CSIs that set colors have the potential to track the
alpha channel and that can make it through to the GUI/render layer.
The recent work on the scrollback made it easier to constrain the
search region, so expose those parameters to the Pane::search
interface and to the mux protocol.
Use those new parameters to constrain quickselect search to
1000 rows above and below the current viewport by default, and
add a new parameter to QuickSelectArgs that allows overriding that
range.
A follow-up commit could make the search/copy overlay issue a series
of searches in chunks so that it avoids blocking the UI when
searching very large scrollback.
refs: https://github.com/wez/wezterm/pull/1317
In order to avoid searching for "c", "ca", "cat" when typing "cat",
this commit introduces a hard-coded 350ms debounce.
refs: https://github.com/wez/wezterm/issues/1569
If you typed "cat" in the search, the chances are that wezterm
would kick off a search for "c" before you finished typing,
then "ca" and then finally "cat".
There was a race:
clear by_line highlights,
queue search for "c"
clear by_line highlights,
queue search for "ca"
clear by_line highlights,
queue search for "cat"
accumulate highlights for "c" into by_line
accumulate highlights for "ca" into by_line
accumulate highlights for "cat" into by_line
so the final result was a superposition of all of those results,
which was weird!
The fix is simple: clear by_line when we get the results of
an async search.
Adds the option to use an alternative clusted line storage for
the cells component of the line.
This structure is not optimal for mutation, but is better structured
for:
* matching/extracting textual content
* using less memory than the prior simple vector
For some contrast: the line "hello" occupies 5 Cells in the cell based
storage; that 5 discrete Cells each with their own tiny string
and a copy of their attributes.
The clustered version of the line stores one copy of the cell
attributes, the string "hello" and some small (almost constant size)
overhead for some metadata. For simple lines of ascii text, the
clustered version is smaller as there are fewer copies of the cell
attributes. Over the span of a large scrollback and typical terminal
display composition, this saving is anticipated to be significant.
The clustered version is also cheaper to search as it doesn't require
building a copy of the search text for each line (provided the line is
already in clustered form).
This commit introduces the capability: none of the internals request the
new form yet, and there are likely a few call sites that need to be
tweaked to avoid coersion from clustered to vector form.
We didn't actually update the global config, just the per-window
configs, which led to weird stale throwbacks to earlier versions
of the config when spawning windows or new panes.
Fix that up by explicitly reloading the global config when the
window appearance is changed. That isn't ideal as we will reload
once per window, but it's "OK".
While poking at this, I noticed that the get/set config methods
on the termwiztermtab overlay weren't hooked up, and also made
a point of calling those for any overlays during a window config
reload event, so that per-window overrides are more likely to get
picked up and respected.
refs: https://github.com/wez/wezterm/issues/2295
Need to explicitly pop it in front of the tab text layer so that
the button is physically rendered on top of the tab title.
refs: https://github.com/wez/wezterm/issues/2269
This allows the hook to choose how to handle eg: `wezterm start -- top`.
Previously, if you had implemented this event you would essentially lose
the ability to specify a command that you wanted to launch.
refs: https://github.com/wez/wezterm/issues/284
This simplifies the "change scheme based on dark mode" example
a lot. This was previously impossible to do because we didn't
have a lua module associated with the gui until recently, so
the only way to reference a gui-related object was via an
event callback.
refs: https://github.com/wez/wezterm/issues/2258
It can be confusing to see the same log lines when re-opening
the debug overlay, so this commit remembers the last line
in a global to make that feel more natural.
Because that causes the initial `OpenGL Initialized!` log to
show only in the first instance of the overlay, that log line
is now changed to debug level and the overlay will now
explicitly log the version information, along with some
brief usage text:
```
Debug Overlay
wezterm version: 20220714-001416-810512c2
OpenGL version: AMD BEIGE_GOBY (LLVM 14.0.0, DRM 3.46, 5.18.10-200.fc36.x86_64) 4.6 (Compatibility Profile) Mesa 22.1.3
Enter lua statements or expressions and hit Enter.
Press ESC or CTRL-D to exit
```
Attach the mux events to the frontend workspace reconciliation function
so that the window is updated to match the new workspace.
Ensure that we correctly clear out any overlay panes as part of the
switch: we need to remove them from the mux so that the mux will
correctly identify that the mux is empty when the main panes from
the workspace are closed. The problem case was that the debug overlay
state was forgotten by the gui when activating the new workspace, but
we didn't tell the mux to kill it off, so subsequently CTRL-D'ing
the windows closed the windows but left the wezterm process running with
no head.
refs: #2248
We don't really know which of the on-screen matches the user was
looking at when they selected the text, but assume that the one
nearest the bottom of the viewport is the one they want to select,
rather than the one closest to the top.
refs: https://github.com/wez/wezterm/issues/2250
When evaluating an assignment expression like `foo = "bar"` the result
of the expression is nil and we'd print nil on the next line,
which often startles me as I'm used to other languages where the
result of such an expression is the rvalue that was just assigned.
Let's just suppress nil when it is the result of an evaluation
in the repl for a cleaner look.
Otherwise we can block the gui waiting for eg: a freshly opened firefox to
terminate.
See also comment worrying about this in
75066cb522.
That fear was realized but now resolved!
refs: https://github.com/wez/wezterm/issues/2245
The intent is that when set, it changes defaults to something
more suitable for distributions.
I've also added a readme for distro maintainers.
refs: https://github.com/wez/wezterm/issues/1795
Not sure why this only really showed up with Wayland, because the
issue was that the computed tab bar height ended up being 1 or 2
pixels shorter than the area we had allotted.
This commit resolves it by forcing the height to match, and
then aligning the content to the bottom of that region to avoid
having an undesirable line under the tab.
refs: #1256
The fixup callback can now by async, which makes it possible to use
other async functions in the callback.
There is an additional parameter to wezterm.exec_domain that allows
setting the label that is shown in the launcher menu.
It accepts either a string value or an async callback function
that can be used to compute the label dynamically.
An ExecDomain is a variation on WslDomain with the key difference
being that you can control how to map the command that would be
executed.
The idea is that the user can define eg: a domain for a docker
container, or a domain that chooses to run every command in its
own cgroup.
The example below shows a really crappy implementation as a
demonstration:
```
local wezterm = require 'wezterm'
return {
exec_domains = {
-- Commands executed in the woot domain have "WOOT" echoed
-- first and are then run via bash.
-- `cmd` is a SpawnCommand
wezterm.exec_domain("woot", function(cmd)
if cmd.args then
cmd.args = {
"bash",
"-c",
"echo WOOT && " .. wezterm.shell_join_args(cmd.args)
}
end
-- you must return the SpawnCommand that will be run
return cmd
end),
},
default_domain = "woot",
}
```
This commit unfortunately does more than should go into a single
commit, but I'm a bit too lazy to wrangle splitting it up.
* Reverts the nil/null stuff from #2177 and makes the
`ExtendSelectionToMouseCursor` parameter mandatory to dodge
a whole load of urgh around nil in table values. That is
necessary because SpawnCommand uses optional fields and the
userdata proxy was making that a PITA.
* Adds some shell quoting helper functions
* Adds ExecDomain itself, which is really just a way to
to run a callback to fixup the command that will be run.
That command is converted to a SpawnCommand for the callback
to process in lua and return an adjusted version of it,
then converted back to a command builder for execution.
refs: https://github.com/wez/wezterm/issues/1776
You can start a window in full screen mode using something like:
```lua
local wezterm = require 'wezterm'
local mux = wezterm.mux
wezterm.on("gui-startup", function()
local tab, pane, window = mux.spawn_window{}
window:gui_window():toggle_fullscreen()
end)
return {
}
```
refs: #177
refs: #284
reconciling causes gui windows to be created and allows for stuff like
this, that would otherwise fail because the gui window hadn't been
created yet.
```lua
local wezterm = require 'wezterm'
local mux = wezterm.mux
wezterm.on("gui-startup", function()
local tab, pane, window = mux.spawn_window{}
window:gui_window():set_inner_size(1200, 1200)
end)
return {
}
```
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