1
1
mirror of https://github.com/wez/wezterm.git synced 2024-09-11 14:25:57 +03:00

add wezterm cli spawn command

This spawns a new tab into the current window by default.
This commit is contained in:
Wez Furlong 2021-03-28 13:57:29 -07:00
parent 98604ff52e
commit 5cfce34b12
4 changed files with 173 additions and 0 deletions

View File

@ -435,6 +435,7 @@ pdu! {
SetPaneZoomed: 33,
SplitPane: 34,
KillPane: 35,
SpawnV2: 36,
}
impl Pdu {
@ -578,6 +579,16 @@ pub struct SplitPane {
pub domain: config::keyassignment::SpawnTabDomain,
}
#[derive(Deserialize, Serialize, PartialEq, Debug)]
pub struct SpawnV2 {
pub domain: config::keyassignment::SpawnTabDomain,
/// If None, create a new window for this new tab
pub window_id: Option<WindowId>,
pub command: Option<CommandBuilder>,
pub command_dir: Option<String>,
pub size: PtySize,
}
#[derive(Deserialize, Serialize, PartialEq, Debug)]
pub struct KillPane {
pub pane_id: PaneId,

View File

@ -932,6 +932,7 @@ impl Client {
rpc!(ping, Ping = (), Pong);
rpc!(list_panes, ListPanes = (), ListPanesResponse);
rpc!(spawn, Spawn, SpawnResponse);
rpc!(spawn_v2, SpawnV2, SpawnResponse);
rpc!(split_pane, SplitPane, SpawnResponse);
rpc!(write_to_pane, WriteToPane, UnitResponse);
rpc!(send_paste, SendPaste, UnitResponse);

View File

@ -426,6 +426,14 @@ impl SessionHandler {
.detach();
}
Pdu::SpawnV2(spawn) => {
let sender = self.to_write_tx.clone();
spawn_into_main_thread(async move {
schedule_domain_spawn_v2(spawn, sender, send_response);
})
.detach();
}
Pdu::SplitPane(split) => {
let sender = self.to_write_tx.clone();
spawn_into_main_thread(async move {
@ -541,6 +549,14 @@ where
promise::spawn::spawn(async move { send_response(domain_spawn(spawn, sender).await) }).detach();
}
fn schedule_domain_spawn_v2<SND>(spawn: SpawnV2, sender: PduSender, send_response: SND)
where
SND: Fn(anyhow::Result<Pdu>) + 'static,
{
promise::spawn::spawn(async move { send_response(domain_spawn_v2(spawn, sender).await) })
.detach();
}
fn schedule_split_pane<SND>(split: SplitPane, sender: PduSender, send_response: SND)
where
SND: Fn(anyhow::Result<Pdu>) + 'static,
@ -659,3 +675,47 @@ async fn domain_spawn(spawn: Spawn, sender: PduSender) -> anyhow::Result<Pdu> {
size: tab.get_size(),
}))
}
async fn domain_spawn_v2(spawn: SpawnV2, sender: PduSender) -> anyhow::Result<Pdu> {
let mux = Mux::get().unwrap();
let domain = match spawn.domain {
SpawnTabDomain::DefaultDomain => mux.default_domain(),
SpawnTabDomain::CurrentPaneDomain => anyhow::bail!("must give a domain"),
SpawnTabDomain::DomainName(name) => mux
.get_domain_by_name(&name)
.ok_or_else(|| anyhow!("domain name {} is invalid", name))?,
};
let window_builder;
let window_id = if let Some(window_id) = spawn.window_id {
mux.get_window_mut(window_id)
.ok_or_else(|| anyhow!("window_id {} not found on this server", window_id))?;
window_id
} else {
window_builder = mux.new_empty_window();
*window_builder
};
let tab = domain
.spawn(spawn.size, spawn.command, spawn.command_dir, window_id)
.await?;
let pane = tab
.get_active_pane()
.ok_or_else(|| anyhow!("missing active pane on tab!?"))?;
let clip: Arc<dyn Clipboard> = Arc::new(RemoteClipboard {
pane_id: pane.pane_id(),
sender,
});
pane.set_clipboard(&clip);
Ok::<Pdu, anyhow::Error>(Pdu::SpawnResponse(SpawnResponse {
pane_id: pane.pane_id(),
tab_id: tab.tab_id(),
window_id,
size: tab.get_size(),
}))
}

View File

@ -1,8 +1,10 @@
use anyhow::{anyhow, Context};
use config::keyassignment::SpawnTabDomain;
use config::wezterm_version;
use mux::activity::Activity;
use mux::pane::PaneId;
use mux::tab::SplitDirection;
use mux::window::WindowId;
use mux::Mux;
use portable_pty::cmdbuilder::CommandBuilder;
use std::ffi::OsString;
@ -124,6 +126,41 @@ Outputs the pane-id for the newly created pane on success"
#[structopt(parse(from_os_str))]
prog: Vec<OsString>,
},
#[structopt(
name = "spawn",
about = "Spawn a command into a new window or tab
Outputs the pane-id for the newly created pane on success"
)]
SpawnCommand {
/// Specify the current pane.
/// The default is to use the current pane based on the
/// environment variable WEZTERM_PANE.
/// The pane is used to determine the current domain
/// and window.
#[structopt(long = "pane-id")]
pane_id: Option<PaneId>,
#[structopt(long = "domain-name")]
domain_name: Option<String>,
/// Specify the window into which to spawn a tab.
/// If omitted, the window associated with the current
/// pane is used.
#[structopt(long = "window-id")]
window_id: Option<WindowId>,
/// Specify the current working directory for the initially
/// spawned program
#[structopt(long = "cwd", parse(from_os_str))]
cwd: Option<OsString>,
/// Instead of executing your shell, run PROG.
/// For example: `wezterm start -- bash -l` will spawn bash
/// as if it were a login shell.
#[structopt(parse(from_os_str))]
prog: Vec<OsString>,
},
}
use termwiz::escape::osc::{
@ -412,6 +449,70 @@ async fn run_cli_async(config: config::ConfigHandle, cli: CliCommand) -> anyhow:
log::debug!("{:?}", spawned);
println!("{}", spawned.pane_id);
}
CliSubCommand::SpawnCommand {
cwd,
prog,
pane_id,
domain_name,
window_id,
} => {
let window_id = match window_id {
Some(w) => Some(w),
None => {
let pane_id: PaneId = match pane_id {
Some(p) => p,
None => std::env::var("WEZTERM_PANE")
.map_err(|_| {
anyhow!(
"--pane-id was not specified and $WEZTERM_PANE
is not set in the environment"
)
})?
.parse()?,
};
let panes = client.list_panes().await?;
let mut window_id = None;
'outer: for tabroot in panes.tabs {
let mut cursor = tabroot.into_tree().cursor();
loop {
if let Some(entry) = cursor.leaf_mut() {
if entry.pane_id == pane_id {
window_id.replace(entry.window_id);
break 'outer;
}
}
match cursor.preorder_next() {
Ok(c) => cursor = c,
Err(_) => break,
}
}
}
window_id
}
};
let spawned = client
.spawn_v2(codec::SpawnV2 {
domain: domain_name.map_or(SpawnTabDomain::DefaultDomain, |name| {
SpawnTabDomain::DomainName(name)
}),
window_id,
command: if prog.is_empty() {
None
} else {
let builder = CommandBuilder::from_argv(prog);
Some(builder)
},
command_dir: cwd.and_then(|c| c.to_str().map(|s| s.to_string())),
size: config::configuration().initial_size(),
})
.await?;
log::debug!("{:?}", spawned);
println!("{}", spawned.pane_id);
}
CliSubCommand::Proxy => {
// The client object we created above will have spawned
// the server if needed, so now all we need to do is turn