I'm gradually improving snapshot testing macro devx in k9 and preparing
to ship v1. Before i do this i'm changing the inline snapshot macro to be
just `snapshot!()` that takes `Debug` trait an an arg and figures out
serialization of it.
This commit adjusts the default color palette to use the same color
cube calculation as xterm; it isn't the ideal color cube calculation
and results in slightly brighter colors.
This commit also memoizes the default palette calculation so that
it isn't recomputed each time a palette is created.
refs: https://github.com/wez/wezterm/issues/348
This commit is a bit noisy because it also meant flipping the key map
code from using the termwiz input types to the window input types, which
I thought I'd done some time ago, but clearly didn't.
This commit allows defining key assignments in terms of the underlying
operating system raw codes, if provided by the relevant layer in the
window crate (currently, only X11/Wayland).
The raw codes are inherently OS/Machine/Hardware dependent; they are the
rawest value that we have available and there is no meaningful
understanding that we can perform in code to understand what that key
is.
One useful property of the raw code is that, because it hasn't gone
through any OS level keymapping processing, its value reflects its
physical position on the keyboard, allowing you to map keys by position
rather than by value. That's useful if you use software to implement
eg: DVORAK or COLEMAK but want your muscle memory to kick in for some of
your key bindings.
New config option:
`debug_key_events = true` will cause wezterm to log an "error" to stderr
each time you press a key and show the details in the key event:
```
2020-12-06T21:23:10.313Z ERROR wezterm_gui::gui::termwindow > key_event KeyEvent { key: Char('@'), modifiers: SHIFT | CTRL, raw_key: None, raw_modifiers: SHIFT | CTRL, raw_code: Some(11), repeat_count: 1, key_is_down: true }
```
This is useful if you want to figure out the `raw_code` for a key in your
setup.
In your config, you can use this information to setup new key bindings.
The motivating example for me is that because `raw_key` (the unmodified
equivalent of `key`) is `None`, the built-in `CTRL-SHIFT-1` key
assignment doesn't function for me on Linux, but I can now "fix" this in
my local configuration, taking care to make it linux specific:
```lua
local wezterm = require 'wezterm';
local keys = {}
if wezterm.target_triple == "x86_64-unknown-linux-gnu" then
local tab_no = 0
-- raw codes 10 through 19 correspond to the number key 1-9 positions
-- on my keyboard on my linux system. They may be different on
-- your system!
for i = 10, 20 do
table.insert(keys, {
key="raw:"..tostring(i),
mods="CTRL|SHIFT",
action=wezterm.action{ActivateTab=tab_no},
})
tab_no = tab_no + 1
end
end
return {
keys = keys,
}
```
Notice that the key assignment accepts encoding a raw key code using
a value like `key="raw:11"` to indicate that you want a `raw_code` of
`11` to match your key assignment. The `raw_modifiers` portion of
the `KeyEvent` is used together with the `raw_code` when deciding
the key assignment.
cc: @bew
This tidies up the font-dir and built-in font management a little
bit and paves the way for codepoint -> font resolution for fonts
discovered in font-dirs.
This commit uses a bit of DirectWrite to discover which font(s)
can be used to render a set of codepoints.
While hooking this up, I found that the method we were using
to extract the font data didn't handle TTC data so this commit
improves some parser diagnostics and handling for that.
refs: https://github.com/wez/wezterm/issues/299
98f289f511 causes more metrics retrieval
than in earlier versions; each unchached glyph render would trigger
a metrics recompute for the relevant font.
Add a simple cache for this.
refs: #353
This is one of those massive time sinks that I almost regret...
As part of recent changes to dust-off the allsorts shaper, I noticed
that the harfbuzz shaper wasn't shaping as well as the allsorts one.
This commit:
* Adds emoji-test.txt, a text file you can `cat` to see how well
the emoji are shaped and rendered.
* Fixes (or at least, improves) the column width calculation for
combining sequences such as "deaf man" which was previously calculated
at 3 cells in width when it should have just been 2 cells wide, which
resulted in a weird "prismatic" effect during rendering where the
glyph would be rendered with an extra RHS portion of the glyph across
3 cells.
* Improved/simplified the clustering logic used to compute fallbacks.
Previously we could end up with some wonky/disjoint sequence of
undefined glyphs which wouldn't be successfully resolved from a
fallback font. We now make a better effort to consolidate runs of
undefined glyphs for fallback.
* For sequences such as "woman with veil: dark skin tone" that occupy a
single cell, the shaper may return 3 clusters with 3 glyphs in the
case that the font doesn't fully support this grapheme. At render
time we'd just take the last glyph from that sequence and render it,
resulting in eg: a female symbol in this particular case. It is
generally a bit more useful to show the first glyph in the sequence
(eg: person with veil) rather than the gender or skin tone, so the
renderer now checks for this kind of overlapping sequence and renders
only the first glyph from the sequence.
The current master of allsorts supports color fonts in both bitmap and
svg varieties. I'm interested to see if I can teach wezterm to render
the svg based variety in a subsequent diff.
First though, it's times to dust off our allsorts shaper logic.
This commit updates to point to the current master of allsorts at the
time of writing; there's a little bit of API fanout that makes it a bit
easier to manage font fallback.
The fallback logic has been improved so that we can now successfully
fall back to the emoji font.
The shaping logic has been improved so that we turn on the options that
enable ZWJ for combining sequences of emoji, such as "man health
worker".
Running with the allsorts shaper enabled produces generally superior
emoji/ligature substitution results compared to harfbuzz with Noto Color
Emoji; the "man health worker" and the flags (eg: `flag: England`) from
the subdivsion-flag section don't get substituted at all with harfbuzz,
but do produce appropriate glyphs with allsorts.
refs: https://github.com/wez/wezterm/issues/66
This causes `tmux -CC attach` to enter control mode and patch
into the terminal, printing out parsed event messages.
refs: https://github.com/wez/wezterm/issues/336
This command formats an OSC 7 escape sequence to inform the terminal
of the working directory.
It has two optional arguments:
* The hostname - if unspecified the hostname of the system will be used
* The working directory - if unspecified the working directory of the
process will be used
This command formats the hostname and working directory into a `file://`
URL and emits an OSC 7 escape sequence.
The intent of this is to make it a bit easier to produce shell
integration scripts for various shell environments without trying
to implement URL encoding in eg: bash.
Adds some supporting methods for computing the `SemanticZone`s
in the display and a key assignment that allows scrolling the
viewport to jump to the next/prev Prompt zone.
This commit introduces a small, bounded, LRU cache for recently
decoded images.
This allows the same image ID to be used in the cache that the
same image bits are repeatedly sent to the terminal.
This is advantageous because it reduces the amount of texture
space required by the gui layer.
This wasn't used by anything and the version was getting pretty stale.
Upgrading is awkward because newer versions pull in an incompatible
freetype library version.
This commit moves a bunch of stuff around such that `wezterm` is now a
lighter-weight executable that knows how to spawn the gui, talk to
the mux or emit some escape sequences for imgcat.
The gui portion has been moved into `wezterm-gui`, a separate executable
that doesn't know about the CLI or imgcat functionality.
Importantly, `wezterm.exe` is no longer a window subsystem executable
on windows, which makes interactions such as `wezterm -h` feel more
natural when spawned from `cmd`, and should allow
`type foo.png | wezterm imgcat` to work as expected.
That said, I've only tested this on linux so far, and there's a good
chance that something mac or windows specific is broken by this
change and will need fixing up.
refs: #301
This commit uses the guillotine algorithm to assign rectangles,
which is superior to the dumb algorithm previously in use.
In addition, in the first pass of painting, if we get a texture
space error, we clear the atlas and try again without increasing
it size, which should serve as the ultimate defrag.
Subsequent passes will cause the texture to grow if needed.
refs: #306
Replaces SmallVec with an internal TeenyString that only
occupies a single machine word and avoids heap allocation
in the common case on most architectures. This takes the
textual portion of Cell from 32 bytes to 8 bytes.
This commit adds very basic first passes at representing the Pane
and GuiWindow types in lua script.
The `open-uri` event from 9397f2a2db
has been redefined to receive `(window, pane, uri)` parameters
instead of its prior very basic `uri` parameter.
A new key assignment `wezterm.action{EmitEvent="event-name"}` is
now available that allows a key binding assignment to emit an arbitrary
event, which in turn allows for triggering an arbitrary lua callback
in response to a key or mouse click.
`EmitEvent` passes the `(window, pane)` from the triggering window and
pane as parameters.
Here's a brief example:
```lua
local wezterm = require 'wezterm';
wezterm.on("my-thingy", function(window, pane)
local dims = pane:get_dimensions();
wezterm.log_error("did my thingy with window " .. window:window_id() ..
" pane " .. pane:pane_id() .. " " .. dims.cols .. "x" .. dims.viewport_rows);
window:perform_action("IncreaseFontSize", pane);
end)
return {
keys = {
{key="E", mods="CTRL", action=wezterm.action{EmitEvent="my-thingy"}},
}
}
```
refs: #223
refs: #225
This was broken by the changes in
aad493ab2a. The issue was that the
channel send didn't wakeup the receiver. I'm not sure why, and I tried
a couple of different async channel implementation.
Doing the simplistic solution here works reliably.
This builds on the new lua event handler plumbing added
in ccea650a93 to co-opt
the default URI opening action:
```lua
wezterm.on("open-uri", function(uri)
if uri:find("jira") then
wezterm.log_error("do something with jira")
wezterm.run_child_process({
"wezterm",
"start",
"--",
"jira",
"view",
extract_task_from_uri(uri)
})
-- prevent the default action from opening in a browser
return false
else
-- log but allow the uri to be opened in the browser
wezterm.log_error("clicken " .. uri)
end
end)
```
This doesn't allow exactly the sketched out option from
issue #223 to be implemented, but may be close enough
to be useful.
refs: #223
refs: #225
* `wezterm.on("event-name", func)`
* `wezterm.emit("event-name", "arg1", "arg2")`
`on` allows registering multiple functions.
`emit` will call each of the registered functions in turn, passing
a copy of the arguments. If a handler returns false, no additional
handlers are called and `emit` will return false. Otherwise,
once all the handlers have been called, `emit` will return true.
`emit` is capable of being called by async code.
These functions are available to the config layer, but nothing in
wezterm uses them at this time.
refs: #225
* Taught wezterm-mux-server how to `--daemonize` on windows
* Removed pty based command spawn used to spawn unix domain servers.
This was present because it was the only way to successfully spawn
wsl in the past. What I'm finding today is that it doesn't work
at all for me, generating an `0xc0000142` Application failed to
initialize error. A plain command builder spawn seems to work,
so that's what we're going with.
* Ensure that we put `.exe` on executable name on windows, otherwise
the spawn may fail.
* `Path::exists()` always returns false for unix domain sockets on
Windows, so unconditionally try to remove the socket before binding,
otherwise the bind will falsely fail, claiming that another process
is already bound.
The docs for mux will need to be updated to show how to revise them
for the new mux server invocation:
```lua
unix_domains = {
{
name = "wsl",
serve_command = {"wsl", "wezterm-mux-server", "--daemonize"}
},
}
```
This version no longer generates invalid CA certificates and
allows TLS connections using the internal PKI to advance
further. Still need to debug an early disconnect.
kindof a lot going on in this commit, unintentionally:
* Need the lua context set to be moved into the config crate
otherwise configs cannot be parsed by the server and we end
up with the default configs
* Make the server use smol for async io
* Drop the use of the daemonize crate, which I had forked anyway.
Just inline our own tighter daemonize module
* Improve daemon spawning synchronization, however, it still needs
work for windows to avoid blocking forever where we don't do
daemonizing.
This commit adds support for left/right margins and has been
tested against esctest, with a final status of:
```
309 tests passed, 239 known bugs
```
"known bugs" also includes unimplemented features; we have a
similar degree as iTerm2.
As of this commit, we now report as a vt520ish machine to DA1.
I confess to not having read enough of the relevant docs
to know whether this is totally righteous.
This corrects an issue where the mode byte of the DCS sequence was
discarded from the DcsHook, making it impossible to know what sequence
is being activated.
So far this hasn't come up as these sequences are relatively rare,
but in looking at sixel parsing I noticed the error.
This commit doesn't do anything specific to scrollback though!
It moves the implementation of the TermWizTermTab away from
a directly manipulated Surface and over to using the term::Terminal,
making the renderer look more like the one used by the local tab
and domain implementation.
As a side effect of doing this, we get scrollback management
for free.
refs: https://github.com/wez/wezterm/issues/201
Since the last release we've migrated from failure -> anyhow,
added more functions to the command builder, improved windows
support and have compatibility with the `smol` crate.
refs: https://github.com/wez/wezterm/issues/166
This commit adds some plumbing that will use the github API to
probe the currently released version of wezterm, and if it is
newer than the running version, show a window with some release
information and links to the changelog and download page.
The checks can be disabled in the config (but require a restart
to take effect!) and default to checking every 24 hours.
If running an AppImage on linux, links directly to the appimage
download. In the future I'd like to have the download button
use zsync to apply the update to the local image.
This commit changes the behavior on Windows:
* If $TERM is set and the `terminfo` crate is able to
successfully initialize and locate a terminfo database (this also
requires that $TERMINFO be set in the environment), then we'll
use the `TerminfoRenderer` instead of the `WindowsConsoleRenderer`
* If $TERM is set to `xterm-256color` and no terminfo database was
found, use our modern compiled-in copy (look in the `termwiz/data/`
directory for the source and compiled version of this) and use
the `TerminfoRenderer`.
* Otherwise use the `WindowsConsoleRenderer`.
In practice, this allows termwiz apps to opt in to features such as
true color support on Windows 10 build 1903 an later by setting their
`TERM=xterm-256color`. This happens to be the default behavior when
`ssh`ing in to a windows host via `wezterm`.
You can see the truecolor mode get applied by running this example:
```
cargo run --example widgets_basic --features widgets
```
with TERM set as above the background region that is painted by the app
will be a blueish/purplish color, but with it unset or set to something
invalid, it will fall back to black.
I'd like to eventually make termwiz assume the equivalent configuration
to `TERM=xterm-256color` by default on Windows 10 build 1903 and later,
but it's worth getting some feedback on how this works for clients such
as `streampager`.
cc: @quark-zju and @markbt
The predictive echo feels pretty reasonable, but if the connection
is having problems and we're showing the tardiness indicator, the
echo can give the impression that your input is going to get processed.
That may not be (usually is not!) the case.
This commit makes it a bit more visually distinctive that something
isn't right by greying out the color palette in that case.
refs: https://github.com/wez/wezterm/issues/127
Make a reasonable suggestion to the user based on similarity with
possible field names, but don't error out.
This facilitates evolving the configuration over time, and makes
the config more forgiving of typos.
This allows for slightly more fancy configuration in the future, but for
now it is rather simple: your lua script returns a configuration struct
with the same shape as that from the TOML file.
A `wezterm` module is provided to the script that provides some
constants to help understand the environment in which wezterm
is running.
I want to add some helpers that make setting up the fonts feel less
weird (lots of nesting in the data model makes this weird).
The ability to conditionally construct configuration is powerful
and helps to address the broader request in
refs: https://github.com/wez/wezterm/issues/152
An example config looks like this:
```lua
local wezterm = require 'wezterm';
print(wezterm.config_dir);
print(wezterm.executable_dir);
wezterm.log_error("w00t! running " .. wezterm.version
.. " on " .. wezterm.target_triple .. " " .. wezterm.home_dir);
return {
enable_scroll_bar = true,
enable_tab_bar = true,
ratelimit_output_bytes_per_second = 400000,
scrollback_lines = 350000,
font_dirs = {".dotfiles/fonts"},
window_padding = {
left = 2,
bottom = 2,
},
font = {
font = {{
family = "Operator Mono SSm Lig Medium",
}},
},
unix_domains = {
{
name = "unix",
}
},
ssh_domains = {
{
name = "localhost",
remote_address = "localhost",
username = "wez",
},
},
tls_clients = {
{
name = "cubetls",
remote_address = "cube-localdomain:8080",
bootstrap_via_ssh = "cube-localdomain",
},
},
tls_servers = {
{
bind_address = "192.168.1.8:8080",
},
},
hyperlink_rules = {
{
regex = "\\b\\w+://(?:[\\w.-]+)\\.[a-z]{2,15}\\S*\\b",
format = "$0",
},
},
font_rules= {
{
italic = true,
font = {
font = {{
family = "Operator Mono SSm Lig Medium Italic",
}}
},
},
{
italic = true,
intensity = "Bold",
font = {
font = {{
family = "Operator Mono SSm Lig Book Italic",
}}
},
},
{
intensity = "Bold",
font = {
foreground = "tomato",
font = {{
family = "Operator Mono SSm Lig Bold",
}}
},
},
{
intensity = "Half",
font = {
font = {{
family = "Operator Mono SSm Lig Light",
}}
},
},
},
}
```
That version has the ability to use SSH agent forwarding.
This commit doesn't enable that functionality, it's just updating
the version and adjusting for changes in the upstream.
Embed rgb.txt and parse it on the fly to produce the list of colors.
This list is a superset of palette's SVG color list.
refs: https://github.com/wez/wezterm/pull/144
The default values are 3 lines. With this change, scrolling speed now seems
similar to other programs like cmd.exe. Before this change it feels too slow.
I got to the bottom of the hang on startup when trying to connect
to the multiplexer on windows and it was because of the change
in 367a44fb96 to try to drain the pollable
channel.
This mapped to ReadFile on windows which always tries to fill the buffer
even if it is a socket under the covers.
348421b010
teaches filedescriptor to use the recv/send if the filedescriptor is
really a socket and that resolves the hang.
Matching against the current dir when it includes a host and a
path seems like a handy way to automate selecting appropriate
theme/color/profile settings, so I'd like to make sure that
we have the full URL content available for that.
Refs: https://github.com/wez/wezterm/issues/115
Refs: https://github.com/wez/wezterm/issues/117
This mostly works, but has a cache invalidation issue wrt.
passing invalidated rows from the server to the client...
sometimes.
However, scrollback is cached on demand and selection works.
We need to build in release mode so targets are cacheable.
GH has a limit of 400MB per cache blob and we're at 750MB with
the debug build. Slim it down a bit.
The cache wants to hash the Cargo.lock file so I've removed that
from the ignore file and added it to the repo. This might cause
an error for users checking out the repo after this change is
pushed; removing the local Cargo.lock should resolve that.