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
In order to support RTL/BIDI, wezterm needs a bidi implementation. I
don't think a well-conforming rust implementation exists today; what I
found were implementations that didn't pass 100% of the conformance
tests.
So I decided to port "bidiref", the reference implementation of the UBA
described in http://unicode.org/reports/tr9/ to Rust.
This implementation focuses on conformance: no special measures have
been taken to optimize it so far, with my focus having been to ensure
that all of the approx 780,000 test cases in the unicode data for
unicode 14 pass. Having the tests passing 100% allows for making
performance improvements with confidence in the future.
The API isn't completely designed/fully baked. Until I get to hooking
it up to wezterm's shaper, I'm not 100% sure exactly what I'll need.
There's a good discussion on API in
https://github.com/open-i18n/rust-unic/issues/273 that suggests omitting
"legacy" operations such as reordering. I suspect that wezterm may
actually need that function to support monospace text layout in some
terminal scenarios, but regardless: reordering is part of the
conformance test suite so it remains a part of the API.
That said: the API does model the major operations as separate
phases, so you should be able to pay for just what you use:
* Resolving the embedding levels from a paragraph
* Returning paragraph runs of those levels (and their directions)
* Returning the whitespace-level-reset runs for a line-slice within the
paragraph
* Returning the reordered indices + levels for a line-slice within the
paragraph.
refs: https://github.com/wez/wezterm/issues/784
refs: https://github.com/kas-gui/kas-text/issues/20
`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.
Define a way to compute a client ID and pass that through to the
mux server when verifying version compatibility.
Once associated, the session handler will keep some metadata
updated in the mux.
A new cli subcommand exposes the info:
```
; ./target/debug/wezterm cli list-clients
USER HOST PID CONNECTED IDLE WORKSPACE
wez mba.localdomain 52979 30.009225s 1.009225s
```
refs: #1531
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
ConPTY emits a sequence that sets the title to the name of the
program that is initially launched into it.
This commit tries to ignore that sequence in that circumstance,
so that the logic in b5d156c282
can more dynamically set the tab title.
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
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
This commit adds plumbing to support mapping the process tree to
lua objects which in turn allows a new `mux-is-process-stateful`
event to be defined by the user for finer control over closing
prompt behavior.
refs: #1412
It looks like the debian 9 test failures with libssh are the
same underlying issue as https://github.com/wez/wezterm/issues/1262
Poking around in the debug output, and then spelunking through the code,
we can use the `pubkeyacceptedtypes` ssh config option to add the key
type to the list of keys. This doesn't appear to be a documented
option in the current versions of openssh.
I'm not 100% sure that this is right, but it's worth a shot.
Route logging via the `log` crate because on Windows there is
no stderr visible to libssh.
libssh will override any explicitly set options when it parses
the config file, so we need to apply those after we've loaded it.
A recent cargo update caused openssl-sys to do a minor semver update
from 0.9.71 -> 0.9.72, but that release downgraded from openssl 3
to openssl 1 to resolve a performance regression:
<https://github.com/sfackler/rust-openssl/pull/1578>
That in turn caused libssh to fail to build because the ENGINE
feature required by libssh isn't compiled in in openssl-src 1
crate when vendoring on windows.
For now, my libssh git repo is constrained to openssl-sys 0.9.71,
and we're pointing to that from the wezterm repo.
In the mux layer, we have some code that takes a `Child` and then
does a bit of naughty reaching through the abstraction to get at
the pid/handle of the child so that we can send it signals even
if the child is itself mutably (and thus exclusively) borrowed
for the purposes of waiting.
That worked fine for local processes spawned in the mux, but we also
use LocalPane to wrap around arbitrary `Child`ren, such as Ssh,
that are not local and that don't have a local process id, which
meant that this hack wouldn't work for them.
To make things a bit worse, those ssh ptys were used to ssh2 days
where we didn't have a way to signal the remote process and just
did nothing, leading to confusing situations such as
https://github.com/wez/wezterm/issues/1197
This commit graduates the hack mentioned in the first paragraph
to its own ChildKiller trait. This makes the concept of waiting
for the Child distinct from signalling it and explicitly allows
getting a separate object that can be used for signalling.
With that in place, we're forced to implement something appropriate
for the ssh pty implementations; one in the pty crate itself,
one in wezterm-ssh and the wrapper that we use in the mux crate.
The upshot of this is that the `CloseCurrentPane` action now operates
correctly on panes that were the result of split operations.