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:
parent
98604ff52e
commit
5cfce34b12
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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(),
|
||||
}))
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user