1
1
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:
Wez Furlong 2022-01-14 10:30:15 -07:00
parent 1bc5c5a663
commit 1704af88ba
7 changed files with 83 additions and 113 deletions

View File

@ -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,

View File

@ -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 {

View File

@ -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)]

View File

@ -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);

View File

@ -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,

View File

@ -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 {

View File

@ -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,