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
This commit updates the last input time for the active client
id when calling into local pane. That time is visible in the
`wezterm cli list-clients` output.
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.
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
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
If we know that the remote host is a unix system, and that it uses some
version of the posix shell, then we can adjust our command line to cd to
the requested directory (as set by OSC 7) and then exec the requested
command.
That's what SshDomain::assume_unix indicates and what this commit does.
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
They have their own versions of these options, and logically it doesn't
make sense to use the default_prog from the `local` domain with a wsl
domain.
refs: #1242
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
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
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
When considering the fg process, we don't want a newly spawned
notepad.exe to show as the fg process in a cmd/pwsh pane, as it
runs async from the console and isn't attached to it.
We can extract the console handle from the process information and
use a 0 value handle to indicate win32 apps that are not attached
to any console.
We cannot compare console handle values directly: without probing
deeper into the handle we don't know that two differently valued
handles refer to different consoles, because a handle can be
duplicated into another with a different numeric value.
I noticed that sysinfo failed to yield info about 50% of the time on
macos!
Just go direct to the underlying system function; we don't need all
of the info that sysinfo collects in any case.
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
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.
If the pane title is the default `wezterm`, then return the
process basename instead. This makes the tab titles more useful
by default, although on Windows, conpty will set the title
to the initial executable path and defeat this.
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
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
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.
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
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.
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
* mux: unzoom when switching panes
Add `unzoom_on_switch_pane` config option:
When switching to another pane with ActivatePaneDirection, if the
current pane is zoomed, unzoom and then switch instead of doing nothing.
* Apply suggestions from code review
Co-authored-by: Wez Furlong <wez@wezfurlong.org>
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
There are some cases where we can print that status before we've
fully drained the output; it's slightly nicer to ensure that
we have an "atomic" line of its own for that, to minimize
the crappiness of the resulting output.
Previously, we'd use a 1MB buffer both to read the output from the
associated pty (blocking), and the same size buffer again to do the
non-blocking read on top of that.
For pathological cases (eg: cat 100MB+ files), we could build a
resulting `Vec<Action>` with over 1mm entries and it could take as much
as 100ms to apply those actions to the terminal model.
This meant that the output could stutter/lag and appear to be processed
more slowly.
This commit introduces a configuration value for the buffer size for the
second stage, and makes it 10KB in size. This helps to constrain the
size of the Action vec and keeps the incremental processing costs down,
while still managing the same throughput.
This commit hooks up DECRQM so that we can report that we implement
synchronized updates, and then refines the code that manages sending
data to the terminal model; the first cut at synchronized updates
was a bit simplistic, and now we make a point of "flushing" pending
actions when we start a sync point, and again as soon as we release
the sync point.
This smooths out the jaggies around the orca that I mentioned in
dcbbda7702
and while testing this, I realized that recent parser changes had
mangled processing bundled dec private mode sequences where multiple
modes were specified in the same overall escape sequence. I've
added the missing unit test case for this and made that work again.
refs: https://github.com/wez/wezterm/issues/955
refs: https://github.com/wez/wezterm/issues/882
This implementation doesn't include a timeout, but should be
recoverable via a SoftReset.
There's no query response either: I think I'm missing DECRQM
entirely at the moment.
refs: https://github.com/wez/wezterm/issues/882
This commit causes a window-config-reloaded event to trigger
when the appearance (dark/light mode) is changed on macos.
It also arranges to propagate the window level config to newly
spawned panes and tabs, created both via the gui and via the
CLI/mux interface.
refs: https://github.com/wez/wezterm/issues/894
refs: https://github.com/wez/wezterm/issues/806
This allows window-level config overrides to apply
to panes contained within the window.
For instance, this allows setting a window-level
color scheme.
I saw this in the stderr logs when the connection was offline:
```
2021-07-17T01:54:28.036Z ERROR wezterm_ssh::session > Failed to write data to channel: Failure while draining incoming flow. Now
what?
2021-07-17T01:54:28.036Z ERROR wezterm_ssh::session > Failed to write data to channel: Failure while draining incoming flow. Now
what?
2021-07-17T01:54:28.142Z ERROR wezterm_ssh::session > Failed to write data to channel: Failure while draining incoming flow. Now
what?
```
This commit propagates the error rather than logging and ignoring it.
In addition, remove a couple of sources of blocking or panicking
that are now unmasked by this.
Possibly the root cause of https://github.com/wez/wezterm/issues/857
Test scenario is:
* Create a split
* in each pane run: `printf "\e[?1004h" ; od -c`
* Focus the panes, focus another window, and focus the window again
* The I and O events appear in the panes when changing their focus.
* Previously, only the active pane would get focus events when the
window focus changed.
refs: https://github.com/wez/wezterm/issues/941
Test scenario is `cat`ing the public domain wiki text data from
http://cs.fit.edu/~mmahoney/compression/enwik8.zip in the terminal;
that file is 96M in size.
`time cat ~/Downloads/enwik8.wiki`
Prior to this change, depending on the OS, the time to cat the file
could be several minutes.
Digging in, the bottleneck appears to be that there isn't sufficient
parallelism between the reader and the parser, which means that the
rate of reading data is constrained by how long it takes to parse
and render a frame.
This commit switches away from using a synchronized vecdeque to
effectively create a non-blocking pipe, to "simply" using a socketpair
with a larger buffer size.
We now do blocking pty read -> write to socketpair in the reader
thread, and then read socketpair -> parse in the other.
The key difference between before and after being that the pty read
can continue to read and accumulate data (with an upper bound, so
that CTRL-C is still responsive) while we're parsing and rendering
a frame.
This increases the throughput for this scenario, bringing it down
from ~3:30 to ~17 seconds on this Ryzen 2700X system.
refs: https://github.com/wez/wezterm/issues/927
The issue is that the pane was only removed from the tab when explicitly
closed, leaving it to be later detected and flushed.
However, in the meantime, when performing eg: cursor blink maintenance,
if the set of panes in the tab is empty then the window would close.
The resolution is to ask the mux (rather than the tab) to kill the pane,
so that the cascading closure of the tab causes the window's active
tab to reference the correct remaining tab.
refs: #890
Expand on the changes in 3f6ff534d3,
this makes them more general and so that they can be used on unix
systems.
That in turn helps to tackle https://github.com/wez/wezterm/issues/839,
wherein `sleep 300 & disown ; exit` would linger until EOF is detected,
rather than triggering as soon as the child process terminated.
For whatever reason, that would only manifest on linux (and not macos).
Same vein as 8931afba5cee07ab12990f06c2ff34d6f8426b19; the auth
window could sometimes get stuck until an input event was sent
to it.
Wire up a mux event so that the window can close itself.
When the client connected to an empty remote mux, it would allocate an
empty window and then spawn a new tab into it.
Meanwhile, the authentication window would close and trigger a prune of
all empty windows, causing the in-flight spawn to fail because its
destination window was removed.
This commit defers window pruning while Activity is in progress;
the MuxWindowBuilder has an associated Activity count.
in the same vein as d657721163
this commit introduces more assertive signalling from the remote
mux when a pane is closed so that the client can update.
Similar to 3f6ff534d3, we need to
tickle the mux to detect when the session terminates.
In this case we can relatively simply schedule an async wait without
spawning an additional thread.
Since removing the regular periodic background tasks, we're now
prone to not noticing child processes exiting.
This commit explicictly schedules a thread to do that on Windows
so that we can close a tab as soon as it exits.
This kill/wait was added to workaround fish being weird on macos.
This is accidentally exponential as the pty layer already loops,
so we don't need to also loop here.
refs: https://github.com/wez/wezterm/issues/774
The status information now explains the exit status and the
exit_behavior, as well as links to the docs on exit_behavior.
refs: https://github.com/wez/wezterm/issues/795
As part of reducing the amount of regularly scheduled stuff wezterm
does in the background, this commit restructures how an empty mux
is detected; now when the mux prunes dead windows it will emit
an Empty event.
The Activity type will now schedule a prune when it is dropped,
which will clean up and trigger the Empty event.
refs: https://github.com/wez/wezterm/issues/770
This got a bit broken by the fix for https://github.com/wez/wezterm/issues/714
since we can be handed a range of logical line fragments, we should
test each of them to find our matching result.
Also, improve the logic for constraining the length when looking
backwards.
the binary search would falsely extend the end of the match
to the start of the subsequent match for the wrapped line case.
The resolution is to emit a coordinate for the newline that we
add to the haystack between the wrapped lines.
closes: https://github.com/wez/wezterm/issues/732
* Make alphabet and patterns configurable
* add docs
* Enhance scrollback search to support regex captures so that
searching for eg: `fo(o)` will select the last `o` in `foo`.
refs: https://github.com/wez/wezterm/issues/732
This tidies up how we pass the ssh config to the connection ui
logic, by moving the ssh_config setup to the two callers.
A couple of notable adjustments:
* SshDomain::username is now optional; it will default to the
values computed by the ssh config file loader
* no_agent_auth value wasn't hooked up to anything, but now it is
refs: https://github.com/wez/wezterm/issues/730
We weren't fixing up the active tab position correctly after removing
a tab. I think this bug crept in around the ActivateLastTab changes.
We now try harder to set active idx back to the tab that was active
prior to the remove, and ensure that we set the active index to
something within range if it was the active tab that was removed.
Refs: https://github.com/wez/wezterm/issues/690
We were handling the case where the chunk intersected a multibyte
boundary after the first chunk, but not for the first chunk itself.
Refactor the code so that we use the same chunk splitting logic
for both of those cases.
refs: https://github.com/wez/wezterm/issues/668
This function could return 1 more line than was requested in the case
where resizing had caused long lines to rewrap.
That extra line would cause the partial bottom row of the quads to
populated with bogus data and rendered over the top of the background
fill.
The resolution is to stop populating lines once we've reached the
upper bound based on the input range.
refs: https://github.com/wez/wezterm/issues/605
This replicates `last-window` in tmux. To pull this off, I
deliberately store the last tab whenever I'm activating a new one or
spawning a new one. I had to do this explicitly rather than hooking
set_active, because we end up setting the active tab briefly for some
common operations like moving a tab.
There are a few notable changes as a result:
* A number of `.ssh/config` options are now respected; host matching
and aliasing and identity file are the main things
* The authentication prompt is inline in the window, rather than
popping up a separate authentication window
Refs: https://github.com/wez/wezterm/issues/457
These now operate in terms of logical lines so they deal with
lines that have wrapped outside the viewport better than in
previous releases.
closes: https://github.com/wez/wezterm/issues/408
I don't understand how fish ends up blocking forever in the related
issue, but it shouldn't block us too! The price of this situation
is likely a lingering zombie child process but that seems fine.
refs: https://github.com/wez/wezterm/issues/558
I've had a few people comment that the screen repaints stutter
more since the most recent release.
One of the main changes in that area was to increase throughput
for timg case, where a lot of data was being pumped through.
I think that, ironically, the decreased latency results in more
frequent repaints where not all of the updated screen is visible
in a full screen redraw, so it appears more janky.
This commit introduces a small 1ms delay to see if additional
output is forthcoming when parsing the data. It will keep
delaying and accumulating until there's at least one parsed
output action to process, so there is a small constant latency
overhead added to a single character output (thread context
switch + 1ms delay).
This small delay is counter-balanced with raising the priority
of dispatching the render actions; previously we'd spawn them
at lower-than-input priority. With the batching potential,
I think spawning them at the same priority is OK; the main
reason for the lower priority was to ensure timely ctrl-c
processing when a lot of output is being dumped to the terminal.
It's hard for me to gauge whether this fixes the reported issue,
as I've been unable to reproduce it for myself.
refs: https://github.com/wez/wezterm/issues/559
refs: https://github.com/wez/wezterm/issues/546
I'm not convinced that this is 100% good, but @fanzeyi reported
some latency when using tmux to mirror two sessions. The session
that was accepting interactive input responded quickly, but the
mirroring session was laggy.
This change connects the mux pane output event to window invalidation,
which should cause repaints to happen more often.
I couldn't reproduce the scenario above on my M1 mac, but that may
just be because M1 has dark magicks.
I've been meaning to do this for a while; this commit moves
the escape sequence parsing into the thread that reads the
pty output which achieves two goals:
* Large escape sequences (eg: image protocols) that span multiple
4k buffers can be processed without ping-ponging between the
reader thread and the main gui thread
* That parsing can happen in the reader thread, keeping the gui
thread more responsive.
These changes free up the CPU during intensive operations such
as timg video playback.
This is a slight layering violation, in that this processing
really belongs to local pane (or any pane that embeds Terminal),
rather than generically at the Mux layer, but it's not any
worse a violation than `advance_bytes` already was.
refs: https://github.com/wez/wezterm/issues/537
In a couple of quick tests, this doesn't seem to break cat'ing
the emoji test data so it seems like it isn't needed anymore.
In addition, it removes a bottleneck from processing image
streams produced by timg, which tend to be very large with
new newlines.
With this change, I'm able to view a 25fps source video at
about 60fps.
refs: https://github.com/wez/wezterm/issues/537
This is defined as a trait method on Pane (default: false), and has the
obvious transitive equivalent methods in Tab and Window (eg: if all
contained items are `can_close_without_prompting`, then that container
is also `can_close_without_prompting`).
The intent is to avoid bothering the user to confirm closing a window
when the content is not stateful and doesn't warrant it.
For example: the window that is displayed in the event of a
configuration error really shouldn't prompt to the user to confirm
closing it.
All termwiztermtab panes are `can_close_without_prompting==true`
to effect this policy.
In the future, we could teach LocalPane to lookup the session leader
process against a list of "uninteresting" or "stateless" processes
and return an appropriate result (as suggested in
https://github.com/wez/wezterm/issues/280). That functionality
is NOT part of this commit.
`exit_behavior = "Hold"` will keep the pane alive until explicitly
closed. More details in the docs that are part of this commit.
refs: https://github.com/wez/wezterm/issues/499
* Add ClearBuffer action
Clears all lines, both visible and those scrolled off the top of the viewport, making the prompt line the new first line and resetting the scrollbar thumb to the full height of the window.
This is the behavior that Hyper / xterm has for clearing the terminal.
* Combine ClearBuffer into ClearScrollback as enum with associated erase mode
Makes it easier to manage the different options of clearing the terminal.
This appears to have been broken since the introduction of mouse
assignments :-/
This commit adds Pane::is_alt_screen_active so that the gui layer
can tell whether the alt screen is active, and allow passing down
the event.
refs: #429
It's been replaced with an opaque termwiz error type instead.
This is a bit of a more conservative approach than that in (refs: #407)
and has less of an impact on the surrounding code, which appeals to
me from a maintenance perspective.
refs: #406
refs: #407
Following on from 8649056ac0,
this commit should make it harder to make a similar mistake
in the future, by introducing a new TerminalSize struct for
that purpose.
* Allow injecting some initial output to new panes
* Have the update checker set this new-pane-banner to a short
upsell to let the user know there is an update.
* Refactor toast notifications into their own crate
* Have the update checker call a new stub function that triggers
a toast notification with an URL... but it does nothing because
the rust ecosystem doesn't support this on macos yet and I'm
writing this code there
Tidies up the plumbing around pixel dimensions so that ImageData
can be rendered via the termwiztermtab bits.
I put this together to play with sticking the wezterm logo in
the close confirmation dialogs. I didn't end up using that though,
but have preserved the commented code for use in future hacking.
Revise logging so that we use info level for things that we want
to always log, and adjust the logger config to always log info
level messages.
That means shifting some warning level logs down lower to debug level so
that they aren't noisy.
closes: https://github.com/wez/wezterm/issues/388
in ab342d9c46 I started to rearrange how
the output processing thread works. It wasn't quite right, so this
commit tidies things up.
The main change here is that there is now back-pressure from the output
parser on the reader; if it is taking a while to parse the output then
we don't buffer up so much input.
This makes operations like `find /` followed immediately by `CTRL-C`
more responsive.
With this change, I don't feel that the
`ratelimit_output_bytes_per_second` option is needed any more, so it
has been removed.