1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

expose some mux domain stuff to lua

refs: https://github.com/wez/wezterm/issues/2933
This commit is contained in:
Wez Furlong 2023-01-09 08:38:05 -07:00
parent d34297cd2c
commit 37055d2fab
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
17 changed files with 261 additions and 1 deletions

1
.gitignore vendored
View File

@ -22,6 +22,7 @@ dhat-heap.json
/docs/config/lua/keyassignment/CopyMode/index.md
/docs/config/lua/mux-events/index.md
/docs/config/lua/mux-window/index.md
/docs/config/lua/MuxDomain/index.md
/docs/config/lua/MuxTab/index.md
/docs/config/lua/MuxPane/index.md
/docs/config/lua/pane/index.md

View File

@ -391,6 +391,7 @@ TOC = [
Gen("object: Color", "config/lua/color"),
Page("object: ExecDomain", "config/lua/ExecDomain.md"),
Page("object: LocalProcessInfo", "config/lua/LocalProcessInfo.md"),
Gen("object: MuxDomain", "config/lua/MuxDomain"),
Gen("object: MuxWindow", "config/lua/mux-window"),
Gen("object: MuxTab", "config/lua/MuxTab"),
Page("object: PaneInformation", "config/lua/PaneInformation.md"),

View File

@ -21,6 +21,10 @@ As features stabilize some brief notes about them will accumulate here.
[#2741](https://github.com/wez/wezterm/issues/2741)
* macOS: initial cut at macOS native menu bar
[#1485](https://github.com/wez/wezterm/issues/1485)
* mux: exposed [MuxDomain](config/lua/MuxDomain/index.md) to lua, along with
[wezterm.mux.get_domain()](config/lua/wezterm.mux/get_domain.md),
[wezterm.mux.all_domains()](config/lua/wezterm.mux/all_domains.md) and
[wezterm.mux.set_default_domain()](config/lua/wezterm.mux/set_default_domain.md).
#### Fixed
* X11: hanging or killing the IME could hang wezterm

View File

@ -0,0 +1,17 @@
# `domain:attach()`
*Since: nightly builds only*
Attempts to attach the domain.
Attaching a domain will attempt to import the windows, tabs and panes from the
remote system into those of the local GUI.
Unlike the [AttachDomain](../keyassignment/AttachDomain.md) key assignment,
calling `domain:attach()` will *not* implicitly spawn a new pane into the
domain if the domain contains no panes. This is to provide flexibility when
used in the [gui-startup](../gui-events/gui-startup.md) event.
If the domain is already attached, calling this method again has no effect.
See also: [domain:detach()](detach.md) and [domain:state()](state.md).

View File

@ -0,0 +1,12 @@
# `domain:detach()`
*Since: nightly builds only*
Attempts to detach the domain.
Detaching a domain causes it to disconnect and remove its set of windows, tabs
and panes from the local GUI. Detaching does not cause those panes to close; if
or when you later attach to the domain, they'll still be there.
Not every domain supports detaching, and will log an error to the error
log/debug overlay.

View File

@ -0,0 +1,6 @@
# `domain:domain_id()`
*Since: nightly builds only*
Returns the domain id.

View File

@ -0,0 +1,9 @@
# `domain:has_any_panes()`
*Since: nightly builds only*
Returns `true` if the mux has any panes that belong to this domain.
This can be useful when deciding whether to spawn additional panes after
attaching to a domain.

View File

@ -0,0 +1,8 @@
# MuxDomain
*Since: nightly builds only*
`MuxDomain` represents a domain that is managed by the multiplexer.
It has the following methods:

View File

@ -0,0 +1,9 @@
# `domain:is_spawnable()`
*Since: nightly builds only*
Returns `false` if this domain will never be able to spawn a new pane/tab/window, `true` otherwise.
Serial ports are represented by a serial domain that is not spawnable.

View File

@ -0,0 +1,9 @@
# `domain:label()`
*Since: nightly builds only*
Computes a label describing the name and state of the domain.
The label can change depending on the state of the domain.
See also: [domain:name()](name.md).

View File

@ -0,0 +1,8 @@
# `domain:name()`
*Since: nightly builds only*
Returns the name of the domain. Domain names are unique; no two domains can
have the same name, and the name is fixed for the lifetime of the domain.
See also: [domain:label()](label.md).

View File

@ -0,0 +1,10 @@
# `domain:state()`
*Since: nightly builds only*
Returns whether the domain is attached or not. The result is a string that is either:
* `"Attached"` - the domain is attached
* `"Detached"` - the domain is not attached
See also: [domain:detach()](detach.md) and [domain:detach()](detach.md).

View File

@ -0,0 +1,6 @@
# `wezterm.mux.all_domains()`
*Since: nightly builds only*
Returns an array table holding all of the known
[MuxDomain](../MuxDomain/index.md) objects.

View File

@ -0,0 +1,16 @@
# `wezterm.mux.get_domain(name_or_id)`
*Since: nightly builds only*
Resolves `name_or_id` to a domain and returns a
[MuxDomain](../MuxDomain/index.md) object representation of it.
`name_or_id` can be:
* A domain name string to resolve the domain by name
* A domain id to resolve the domain by id
* `nil` or omitted to return the current default domain
* other lua types will generate a lua error
If the name or id don't map to a valid domain, this function will return `nil`.

View File

@ -0,0 +1,10 @@
# `wezterm.mux.set_default_domain(MuxDomain)`
*Since: nightly builds only*
Assign a new default domain in the mux.
The domain that you assign here will override any configured
[default_domain](../config/default_domain.md) or the implicit assignment of the
default domain that may have happened as a result of starting wezterm via
`wezterm connect` or `wezterm serial`.

View File

@ -0,0 +1,83 @@
use super::*;
use mux::domain::{Domain, DomainId, DomainState};
use std::sync::Arc;
#[derive(Clone, Copy, Debug)]
pub struct MuxDomain(pub DomainId);
impl MuxDomain {
pub fn resolve<'a>(&self, mux: &'a Arc<Mux>) -> mlua::Result<Arc<dyn Domain>> {
mux.get_domain(self.0)
.ok_or_else(|| mlua::Error::external(format!("domain id {} not found in mux", self.0)))
}
}
impl UserData for MuxDomain {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, _: ()| {
Ok(format!("MuxDomain(pane_id:{}, pid:{})", this.0, unsafe {
libc::getpid()
}))
});
methods.add_method("domain_id", |_, this, _: ()| Ok(this.0));
methods.add_method("is_spawnable", |_, this, _: ()| {
let mux = get_mux()?;
let domain = this.resolve(&mux)?;
Ok(domain.spawnable())
});
methods.add_async_method("attach", |_, this, window: Option<MuxWindow>| async move {
let mux = get_mux()?;
let domain = this.resolve(&mux)?;
domain.attach(window.map(|w| w.0)).await.map_err(|err| {
mlua::Error::external(format!(
"failed to attach domain {}: {err:#}",
domain.domain_name()
))
})
});
methods.add_method("detach", |_, this, _: ()| {
let mux = get_mux()?;
let domain = this.resolve(&mux)?;
domain.detach().map_err(|err| {
mlua::Error::external(format!(
"failed to detach domain {}: {err:#}",
domain.domain_name()
))
})
});
methods.add_method("state", |_, this, _: ()| {
let mux = get_mux()?;
let domain = this.resolve(&mux)?;
Ok(match domain.state() {
DomainState::Attached => "Attached",
DomainState::Detached => "Detached",
})
});
methods.add_method("name", |_, this, _: ()| {
let mux = get_mux()?;
let domain = this.resolve(&mux)?;
Ok(domain.domain_name().to_string())
});
methods.add_async_method("label", |_, this, _: ()| async move {
let mux = get_mux()?;
let domain = this.resolve(&mux)?;
Ok(domain.domain_label().await)
});
methods.add_method("has_any_panes", |_, this, _: ()| {
let mux = get_mux()?;
let domain = this.resolve(&mux)?;
let have_panes_in_domain = mux
.iter_panes()
.iter()
.any(|p| p.domain_id() == domain.domain_id());
Ok(have_panes_in_domain)
});
}
}

View File

@ -2,7 +2,7 @@ use config::keyassignment::SpawnTabDomain;
use config::lua::mlua::{self, Lua, UserData, UserDataMethods, Value as LuaValue};
use config::lua::{get_or_create_module, get_or_create_sub_module};
use luahelper::impl_lua_conversion_dynamic;
use mux::domain::SplitSource;
use mux::domain::{DomainId, SplitSource};
use mux::pane::{Pane, PaneId};
use mux::tab::{SplitDirection, SplitRequest, SplitSize, Tab, TabId};
use mux::window::{Window, WindowId};
@ -13,10 +13,12 @@ use std::sync::Arc;
use wezterm_dynamic::{FromDynamic, ToDynamic};
use wezterm_term::TerminalSize;
mod domain;
mod pane;
mod tab;
mod window;
pub use domain::MuxDomain;
pub use pane::MuxPane;
pub use tab::MuxTab;
pub use window::MuxWindow;
@ -107,6 +109,55 @@ pub fn register(lua: &Lua) -> anyhow::Result<()> {
})?,
)?;
mux_mod.set(
"get_domain",
lua.create_function(|_, domain: LuaValue| {
let mux = get_mux()?;
match domain {
LuaValue::Nil => Ok(Some(MuxDomain(mux.default_domain().domain_id()))),
LuaValue::String(s) => match s.to_str() {
Ok(name) => Ok(mux
.get_domain_by_name(name)
.map(|dom| MuxDomain(dom.domain_id()))),
Err(err) => Err(mlua::Error::external(format!(
"invalid domain identifier passed to mux.get_domain: {err:#}"
))),
},
LuaValue::Integer(id) => match TryInto::<DomainId>::try_into(id) {
Ok(id) => Ok(mux.get_domain(id).map(|dom| MuxDomain(dom.domain_id()))),
Err(err) => Err(mlua::Error::external(format!(
"invalid domain identifier passed to mux.get_domain: {err:#}"
))),
},
_ => Err(mlua::Error::external(
"invalid domain identifier passed to mux.get_domain".to_string(),
)),
}
})?,
)?;
mux_mod.set(
"all_domains",
lua.create_function(|_, _: ()| {
let mux = get_mux()?;
Ok(mux
.iter_domains()
.into_iter()
.map(|dom| MuxDomain(dom.domain_id()))
.collect::<Vec<MuxDomain>>())
})?,
)?;
mux_mod.set(
"set_default_domain",
lua.create_function(|_, domain: MuxDomain| {
let mux = get_mux()?;
let domain = domain.resolve(&mux)?;
mux.set_default_domain(&domain);
Ok(())
})?,
)?;
Ok(())
}