mirror of
https://github.com/wez/wezterm.git
synced 2024-11-22 13:16:39 +03:00
refactor: move logic -> Mux::spawn_tab_or_window
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 commit is contained in:
parent
1bc5c5a663
commit
1704af88ba
@ -13,7 +13,6 @@
|
||||
|
||||
use anyhow::{bail, Context as _, Error};
|
||||
use mux::client::{ClientId, ClientInfo};
|
||||
use mux::domain::DomainId;
|
||||
use mux::pane::PaneId;
|
||||
use mux::renderable::{RenderableDimensions, StableCursorPosition};
|
||||
use mux::tab::{PaneNode, SerdeUrl, SplitDirection, TabId};
|
||||
@ -406,7 +405,7 @@ macro_rules! pdu {
|
||||
/// The overall version of the codec.
|
||||
/// This must be bumped when backwards incompatible changes
|
||||
/// are made to the types and protocol.
|
||||
pub const CODEC_VERSION: usize = 15;
|
||||
pub const CODEC_VERSION: usize = 16;
|
||||
|
||||
// Defines the Pdu enum.
|
||||
// Each struct has an explicit identifying number.
|
||||
@ -418,7 +417,6 @@ pdu! {
|
||||
Pong: 2,
|
||||
ListPanes: 3,
|
||||
ListPanesResponse: 4,
|
||||
Spawn: 7,
|
||||
SpawnResponse: 8,
|
||||
WriteToPane: 9,
|
||||
UnitResponse: 10,
|
||||
@ -577,16 +575,6 @@ pub struct ListPanesResponse {
|
||||
pub tabs: Vec<PaneNode>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, PartialEq, Debug)]
|
||||
pub struct Spawn {
|
||||
pub domain_id: DomainId,
|
||||
/// 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 SplitPane {
|
||||
pub pane_id: PaneId,
|
||||
|
@ -70,6 +70,8 @@ pub enum SpawnTabDomain {
|
||||
CurrentPaneDomain,
|
||||
/// Use a specific domain by name
|
||||
DomainName(String),
|
||||
/// Use a specific domain by id
|
||||
DomainId(usize),
|
||||
}
|
||||
|
||||
impl Default for SpawnTabDomain {
|
||||
|
@ -3,6 +3,7 @@ use crate::pane::{Pane, PaneId};
|
||||
use crate::tab::{Tab, TabId};
|
||||
use crate::window::{Window, WindowId};
|
||||
use anyhow::{anyhow, Context, Error};
|
||||
use config::keyassignment::SpawnTabDomain;
|
||||
use config::{configuration, ExitBehavior};
|
||||
use domain::{Domain, DomainId};
|
||||
use filedescriptor::{socketpair, AsRawSocketDescriptor, FileDescriptor};
|
||||
@ -10,7 +11,7 @@ use filedescriptor::{socketpair, AsRawSocketDescriptor, FileDescriptor};
|
||||
use libc::{SOL_SOCKET, SO_RCVBUF, SO_SNDBUF};
|
||||
use log::error;
|
||||
use metrics::histogram;
|
||||
use portable_pty::ExitStatus;
|
||||
use portable_pty::{CommandBuilder, ExitStatus, PtySize};
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
use std::collections::HashMap;
|
||||
use std::io::{Read, Write};
|
||||
@ -698,6 +699,64 @@ impl Mux {
|
||||
pub fn set_banner(&self, banner: Option<String>) {
|
||||
*self.banner.borrow_mut() = banner;
|
||||
}
|
||||
|
||||
pub async fn spawn_tab_or_window(
|
||||
&self,
|
||||
window_id: Option<WindowId>,
|
||||
domain: SpawnTabDomain,
|
||||
command: Option<CommandBuilder>,
|
||||
command_dir: Option<String>,
|
||||
size: PtySize,
|
||||
) -> anyhow::Result<(Rc<Tab>, Rc<dyn Pane>, WindowId)> {
|
||||
let domain = match domain {
|
||||
SpawnTabDomain::DefaultDomain => self.default_domain(),
|
||||
SpawnTabDomain::CurrentPaneDomain => anyhow::bail!("must give a domain"),
|
||||
SpawnTabDomain::DomainId(domain_id) => self
|
||||
.get_domain(domain_id)
|
||||
.ok_or_else(|| anyhow!("domain id {} is invalid", domain_id))?,
|
||||
SpawnTabDomain::DomainName(name) => self
|
||||
.get_domain_by_name(&name)
|
||||
.ok_or_else(|| anyhow!("domain name {} is invalid", name))?,
|
||||
};
|
||||
|
||||
let window_builder;
|
||||
let term_config;
|
||||
|
||||
let (window_id, size) = if let Some(window_id) = window_id {
|
||||
let window = self
|
||||
.get_window_mut(window_id)
|
||||
.ok_or_else(|| anyhow!("window_id {} not found on this server", window_id))?;
|
||||
let tab = window
|
||||
.get_active()
|
||||
.ok_or_else(|| anyhow!("window {} has no tabs", window_id))?;
|
||||
let pane = tab
|
||||
.get_active_pane()
|
||||
.ok_or_else(|| anyhow!("active tab in window {} has no panes", window_id))?;
|
||||
term_config = pane.get_config();
|
||||
|
||||
let size = tab.get_size();
|
||||
|
||||
(window_id, size)
|
||||
} else {
|
||||
term_config = None;
|
||||
window_builder = self.new_empty_window();
|
||||
(*window_builder, size)
|
||||
};
|
||||
|
||||
let tab = domain.spawn(size, command, command_dir, window_id).await?;
|
||||
|
||||
let pane = tab
|
||||
.get_active_pane()
|
||||
.ok_or_else(|| anyhow!("missing active pane on tab!?"))?;
|
||||
|
||||
if let Some(config) = term_config {
|
||||
pane.set_config(config);
|
||||
}
|
||||
|
||||
// FIXME: clipboard?
|
||||
|
||||
Ok((tab, pane, window_id))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
@ -1137,7 +1137,6 @@ 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);
|
||||
|
@ -2,7 +2,7 @@ use crate::client::Client;
|
||||
use crate::pane::ClientPane;
|
||||
use anyhow::{anyhow, bail};
|
||||
use async_trait::async_trait;
|
||||
use codec::{ListPanesResponse, Spawn, SplitPane};
|
||||
use codec::{ListPanesResponse, SpawnV2, SplitPane};
|
||||
use config::keyassignment::SpawnTabDomain;
|
||||
use config::{SshDomain, TlsDomainClient, UnixDomain};
|
||||
use mux::connui::ConnectionUI;
|
||||
@ -447,8 +447,8 @@ impl Domain for ClientDomain {
|
||||
.ok_or_else(|| anyhow!("domain is not attached"))?;
|
||||
let result = inner
|
||||
.client
|
||||
.spawn(Spawn {
|
||||
domain_id: inner.remote_domain_id,
|
||||
.spawn_v2(SpawnV2 {
|
||||
domain: SpawnTabDomain::DomainId(inner.remote_domain_id),
|
||||
window_id: inner.local_to_remote_window(window),
|
||||
size,
|
||||
command,
|
||||
|
@ -123,6 +123,12 @@ impl super::TermWindow {
|
||||
})?,
|
||||
None,
|
||||
),
|
||||
SpawnTabDomain::DomainId(domain_id) => (
|
||||
mux.get_domain(domain_id).ok_or_else(|| {
|
||||
anyhow!("spawn_tab called with unresolvable domain id {}", domain_id)
|
||||
})?,
|
||||
None,
|
||||
),
|
||||
};
|
||||
|
||||
if domain.state() == DomainState::Detached {
|
||||
|
@ -532,14 +532,6 @@ impl SessionHandler {
|
||||
.detach();
|
||||
}
|
||||
|
||||
Pdu::Spawn(spawn) => {
|
||||
let sender = self.to_write_tx.clone();
|
||||
spawn_into_main_thread(async move {
|
||||
schedule_domain_spawn(spawn, sender, send_response);
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
Pdu::SpawnV2(spawn) => {
|
||||
let sender = self.to_write_tx.clone();
|
||||
spawn_into_main_thread(async move {
|
||||
@ -666,13 +658,6 @@ impl SessionHandler {
|
||||
// function below because the compiler thinks that all of its locals then need to be Send.
|
||||
// We need to shimmy through this helper to break that aspect of the compiler flow
|
||||
// analysis and allow things to compile.
|
||||
fn schedule_domain_spawn<SND>(spawn: Spawn, sender: PduSender, send_response: SND)
|
||||
where
|
||||
SND: Fn(anyhow::Result<Pdu>) + 'static,
|
||||
{
|
||||
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,
|
||||
@ -722,6 +707,9 @@ async fn split_pane(split: SplitPane, sender: PduSender) -> anyhow::Result<Pdu>
|
||||
SpawnTabDomain::CurrentPaneDomain => mux
|
||||
.get_domain(pane_domain_id)
|
||||
.expect("resolve_pane_id to give valid domain_id"),
|
||||
SpawnTabDomain::DomainId(domain_id) => mux
|
||||
.get_domain(domain_id)
|
||||
.ok_or_else(|| anyhow!("domain id {} is invalid", domain_id))?,
|
||||
SpawnTabDomain::DomainName(name) => mux
|
||||
.get_domain_by_name(&name)
|
||||
.ok_or_else(|| anyhow!("domain name {} is invalid", name))?,
|
||||
@ -783,91 +771,19 @@ async fn split_pane(split: SplitPane, sender: PduSender) -> anyhow::Result<Pdu>
|
||||
}))
|
||||
}
|
||||
|
||||
async fn domain_spawn(spawn: Spawn, sender: PduSender) -> anyhow::Result<Pdu> {
|
||||
let mux = Mux::get().unwrap();
|
||||
let domain = mux
|
||||
.get_domain(spawn.domain_id)
|
||||
.ok_or_else(|| anyhow!("domain {} not found on this server", spawn.domain_id))?;
|
||||
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(),
|
||||
}))
|
||||
}
|
||||
|
||||
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 term_config;
|
||||
|
||||
let (window_id, size) = if let Some(window_id) = spawn.window_id {
|
||||
let window = mux
|
||||
.get_window_mut(window_id)
|
||||
.ok_or_else(|| anyhow!("window_id {} not found on this server", window_id))?;
|
||||
let tab = window
|
||||
.get_active()
|
||||
.ok_or_else(|| anyhow!("window {} has no tabs", window_id))?;
|
||||
let pane = tab
|
||||
.get_active_pane()
|
||||
.ok_or_else(|| anyhow!("active tab in window {} has no panes", window_id))?;
|
||||
term_config = pane.get_config();
|
||||
|
||||
let size = tab.get_size();
|
||||
|
||||
(window_id, size)
|
||||
} else {
|
||||
term_config = None;
|
||||
window_builder = mux.new_empty_window();
|
||||
(*window_builder, spawn.size)
|
||||
};
|
||||
|
||||
let tab = domain
|
||||
.spawn(size, spawn.command, spawn.command_dir, window_id)
|
||||
let (tab, pane, window_id) = mux
|
||||
.spawn_tab_or_window(
|
||||
spawn.window_id,
|
||||
spawn.domain,
|
||||
spawn.command,
|
||||
spawn.command_dir,
|
||||
spawn.size,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let pane = tab
|
||||
.get_active_pane()
|
||||
.ok_or_else(|| anyhow!("missing active pane on tab!?"))?;
|
||||
|
||||
if let Some(config) = term_config {
|
||||
pane.set_config(config);
|
||||
}
|
||||
|
||||
let clip: Arc<dyn Clipboard> = Arc::new(RemoteClipboard {
|
||||
pane_id: pane.pane_id(),
|
||||
sender,
|
||||
|
Loading…
Reference in New Issue
Block a user