mirror of
https://github.com/wez/wezterm.git
synced 2024-12-28 07:55:03 +03:00
mux: Domain::spawn is now async
This was another source of hanging on windows with connecting to a unix domain.
This commit is contained in:
parent
7de282fd07
commit
e814bc4267
@ -1048,61 +1048,66 @@ impl TermWindow {
|
||||
self.move_tab(tab)
|
||||
}
|
||||
|
||||
fn spawn_tab(&mut self, domain: &SpawnTabDomain) -> anyhow::Result<TabId> {
|
||||
fn spawn_tab(&mut self, domain: &SpawnTabDomain) {
|
||||
let size = self.terminal_size;
|
||||
let mux = Mux::get().unwrap();
|
||||
|
||||
let (domain, cwd) = match domain {
|
||||
SpawnTabDomain::DefaultDomain => {
|
||||
let cwd = mux
|
||||
.get_active_tab_for_window(self.mux_window_id)
|
||||
.and_then(|tab| tab.get_current_working_dir());
|
||||
(mux.default_domain().clone(), cwd)
|
||||
}
|
||||
SpawnTabDomain::CurrentTabDomain => {
|
||||
let tab = match mux.get_active_tab_for_window(self.mux_window_id) {
|
||||
Some(tab) => tab,
|
||||
None => bail!("window has no tabs?"),
|
||||
};
|
||||
(
|
||||
mux.get_domain(tab.domain_id())
|
||||
.ok_or_else(|| anyhow!("current tab has unresolvable domain id!?"))?,
|
||||
tab.get_current_working_dir(),
|
||||
)
|
||||
}
|
||||
SpawnTabDomain::Domain(id) => (
|
||||
mux.get_domain(*id)
|
||||
.ok_or_else(|| anyhow!("spawn_tab called with unresolvable domain id!?"))?,
|
||||
None,
|
||||
),
|
||||
SpawnTabDomain::DomainName(name) => (
|
||||
mux.get_domain_by_name(&name).ok_or_else(|| {
|
||||
anyhow!("spawn_tab called with unresolvable domain name {}", name)
|
||||
})?,
|
||||
None,
|
||||
),
|
||||
};
|
||||
let cwd = match cwd {
|
||||
Some(url) if url.scheme() == "file" => Some(url.path().to_string()),
|
||||
Some(_) | None => None,
|
||||
};
|
||||
let tab = domain.spawn(size, None, cwd, self.mux_window_id)?;
|
||||
let tab_id = tab.tab_id();
|
||||
|
||||
let mux_window_id = self.mux_window_id;
|
||||
let clipboard: Arc<dyn term::Clipboard> = Arc::new(ClipboardHelper {
|
||||
window: self.window.as_ref().unwrap().clone(),
|
||||
clipboard_contents: Arc::clone(&self.clipboard_contents),
|
||||
});
|
||||
tab.set_clipboard(&clipboard);
|
||||
let domain = domain.clone();
|
||||
|
||||
let len = {
|
||||
let window = mux
|
||||
.get_window(self.mux_window_id)
|
||||
promise::spawn::spawn(async move {
|
||||
let mux = Mux::get().unwrap();
|
||||
|
||||
let (domain, cwd) = match domain {
|
||||
SpawnTabDomain::DefaultDomain => {
|
||||
let cwd = mux
|
||||
.get_active_tab_for_window(mux_window_id)
|
||||
.and_then(|tab| tab.get_current_working_dir());
|
||||
(mux.default_domain().clone(), cwd)
|
||||
}
|
||||
SpawnTabDomain::CurrentTabDomain => {
|
||||
let tab = match mux.get_active_tab_for_window(mux_window_id) {
|
||||
Some(tab) => tab,
|
||||
None => bail!("window has no tabs?"),
|
||||
};
|
||||
(
|
||||
mux.get_domain(tab.domain_id())
|
||||
.ok_or_else(|| anyhow!("current tab has unresolvable domain id!?"))?,
|
||||
tab.get_current_working_dir(),
|
||||
)
|
||||
}
|
||||
SpawnTabDomain::Domain(id) => (
|
||||
mux.get_domain(id)
|
||||
.ok_or_else(|| anyhow!("spawn_tab called with unresolvable domain id!?"))?,
|
||||
None,
|
||||
),
|
||||
SpawnTabDomain::DomainName(name) => (
|
||||
mux.get_domain_by_name(&name).ok_or_else(|| {
|
||||
anyhow!("spawn_tab called with unresolvable domain name {}", name)
|
||||
})?,
|
||||
None,
|
||||
),
|
||||
};
|
||||
let cwd = match cwd {
|
||||
Some(url) if url.scheme() == "file" => Some(url.path().to_string()),
|
||||
Some(_) | None => None,
|
||||
};
|
||||
let tab = domain.spawn(size, None, cwd, mux_window_id).await?;
|
||||
let tab_id = tab.tab_id();
|
||||
|
||||
tab.set_clipboard(&clipboard);
|
||||
|
||||
let mut window = mux
|
||||
.get_window_mut(mux_window_id)
|
||||
.ok_or_else(|| anyhow!("no such window!?"))?;
|
||||
window.len()
|
||||
};
|
||||
self.activate_tab(len - 1)?;
|
||||
Ok(tab_id)
|
||||
if let Some(idx) = window.idx_by_id(tab_id) {
|
||||
window.set_active(idx);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
fn selection_text(&self, tab: &Rc<dyn Tab>) -> String {
|
||||
@ -1141,7 +1146,7 @@ impl TermWindow {
|
||||
use KeyAssignment::*;
|
||||
match assignment {
|
||||
SpawnTab(spawn_where) => {
|
||||
self.spawn_tab(spawn_where)?;
|
||||
self.spawn_tab(spawn_where);
|
||||
}
|
||||
SpawnWindow => {
|
||||
self.spawn_new_window();
|
||||
@ -1204,10 +1209,11 @@ impl TermWindow {
|
||||
let window_id = mux.new_empty_window();
|
||||
let tab = mux
|
||||
.default_domain()
|
||||
.spawn(PtySize::default(), None, None, window_id)?;
|
||||
.spawn(PtySize::default(), None, None, window_id)
|
||||
.await?;
|
||||
let front_end = front_end().expect("to be called on gui thread");
|
||||
front_end.spawn_new_window(&fonts, &tab, window_id)?;
|
||||
Ok(())
|
||||
Ok::<(), anyhow::Error>(())
|
||||
}
|
||||
promise::spawn::spawn(async move {
|
||||
new_window().await.ok();
|
||||
@ -2355,7 +2361,7 @@ impl TermWindow {
|
||||
self.activate_tab(tab_idx).ok();
|
||||
}
|
||||
TabBarItem::NewTabButton => {
|
||||
self.spawn_tab(&SpawnTabDomain::CurrentTabDomain).ok();
|
||||
self.spawn_tab(&SpawnTabDomain::CurrentTabDomain);
|
||||
}
|
||||
TabBarItem::None => {}
|
||||
}
|
||||
|
12
src/main.rs
12
src/main.rs
@ -2,6 +2,7 @@
|
||||
#![windows_subsystem = "windows"]
|
||||
|
||||
use anyhow::{anyhow, bail, Context};
|
||||
use promise::spawn::block_on;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::DirBuilder;
|
||||
use std::io::{Read, Write};
|
||||
@ -373,7 +374,9 @@ async fn async_run_ssh(opts: SshCommand, params: SshParameters) -> anyhow::Resul
|
||||
domain.attach().await?;
|
||||
|
||||
let window_id = mux.new_empty_window();
|
||||
let tab = domain.spawn(PtySize::default(), cmd, None, window_id)?;
|
||||
let tab = domain
|
||||
.spawn(PtySize::default(), cmd, None, window_id)
|
||||
.await?;
|
||||
let fontconfig = Rc::new(FontConfiguration::new());
|
||||
gui.spawn_new_window(&fontconfig, &tab, window_id)?;
|
||||
|
||||
@ -426,10 +429,10 @@ fn run_serial(config: config::ConfigHandle, opts: &SerialCommand) -> anyhow::Res
|
||||
|
||||
let front_end = opts.front_end.unwrap_or(config.front_end);
|
||||
let gui = front_end.try_new()?;
|
||||
promise::spawn::block_on(domain.attach())?; // FIXME: blocking
|
||||
block_on(domain.attach())?; // FIXME: blocking
|
||||
|
||||
let window_id = mux.new_empty_window();
|
||||
let tab = domain.spawn(PtySize::default(), None, None, window_id)?;
|
||||
let tab = block_on(domain.spawn(PtySize::default(), None, None, window_id))?; // FIXME: blocking
|
||||
gui.spawn_new_window(&fontconfig, &tab, window_id)?;
|
||||
|
||||
gui.run_forever()
|
||||
@ -506,7 +509,8 @@ async fn spawn_tab_in_default_domain_if_mux_is_empty(
|
||||
|
||||
let tab = mux
|
||||
.default_domain()
|
||||
.spawn(PtySize::default(), cmd, None, window_id)?;
|
||||
.spawn(PtySize::default(), cmd, None, window_id)
|
||||
.await?;
|
||||
let fontconfig = Rc::new(FontConfiguration::new());
|
||||
front_end()
|
||||
.unwrap()
|
||||
|
@ -34,7 +34,7 @@ pub fn alloc_domain_id() -> DomainId {
|
||||
#[async_trait(?Send)]
|
||||
pub trait Domain: Downcast {
|
||||
/// Spawn a new command within this domain
|
||||
fn spawn(
|
||||
async fn spawn(
|
||||
&self,
|
||||
size: PtySize,
|
||||
command: Option<CommandBuilder>,
|
||||
@ -84,7 +84,7 @@ impl LocalDomain {
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl Domain for LocalDomain {
|
||||
fn spawn(
|
||||
async fn spawn(
|
||||
&self,
|
||||
size: PtySize,
|
||||
command: Option<CommandBuilder>,
|
||||
|
@ -214,7 +214,7 @@ impl Domain for ClientDomain {
|
||||
self.config.name()
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
async fn spawn(
|
||||
&self,
|
||||
size: PtySize,
|
||||
command: Option<CommandBuilder>,
|
||||
@ -234,7 +234,7 @@ impl Domain for ClientDomain {
|
||||
command,
|
||||
command_dir,
|
||||
})
|
||||
.wait()?;
|
||||
.await?;
|
||||
|
||||
inner.record_remote_to_local_window_mapping(result.window_id, window);
|
||||
|
||||
|
@ -788,42 +788,7 @@ impl<S: ReadAndWrite> ClientSession<S> {
|
||||
Pdu::Spawn(spawn) => {
|
||||
let sender = self.to_write_tx.clone();
|
||||
spawn_into_main_thread(async move {
|
||||
catch(
|
||||
move || {
|
||||
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_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 {
|
||||
mux.new_empty_window()
|
||||
};
|
||||
|
||||
let tab = domain.spawn(
|
||||
spawn.size,
|
||||
spawn.command,
|
||||
spawn.command_dir,
|
||||
window_id,
|
||||
)?;
|
||||
|
||||
let clip: Arc<dyn Clipboard> = Arc::new(RemoteClipboard {
|
||||
tab_id: tab.tab_id(),
|
||||
sender,
|
||||
});
|
||||
tab.set_clipboard(&clip);
|
||||
|
||||
Ok(Pdu::SpawnResponse(SpawnResponse {
|
||||
tab_id: tab.tab_id(),
|
||||
window_id,
|
||||
}))
|
||||
},
|
||||
send_response,
|
||||
)
|
||||
schedule_domain_spawn(spawn, sender, send_response);
|
||||
});
|
||||
}
|
||||
|
||||
@ -900,6 +865,47 @@ impl<S: ReadAndWrite> ClientSession<S> {
|
||||
}
|
||||
}
|
||||
|
||||
// Dancing around a little bit here; we can't directly spawn_into_main_thread the domain_spawn
|
||||
// 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: PollableSender<DecodedPdu>, send_response: SND)
|
||||
where
|
||||
SND: Fn(anyhow::Result<Pdu>) + 'static,
|
||||
{
|
||||
promise::spawn::spawn(async move { send_response(domain_spawn(spawn, sender).await) });
|
||||
}
|
||||
|
||||
async fn domain_spawn(spawn: Spawn, sender: PollableSender<DecodedPdu>) -> 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_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 {
|
||||
mux.new_empty_window()
|
||||
};
|
||||
|
||||
let tab = domain
|
||||
.spawn(spawn.size, spawn.command, spawn.command_dir, window_id)
|
||||
.await?;
|
||||
|
||||
let clip: Arc<dyn Clipboard> = Arc::new(RemoteClipboard {
|
||||
tab_id: tab.tab_id(),
|
||||
sender,
|
||||
});
|
||||
tab.set_clipboard(&clip);
|
||||
|
||||
Ok::<Pdu, anyhow::Error>(Pdu::SpawnResponse(SpawnResponse {
|
||||
tab_id: tab.tab_id(),
|
||||
window_id,
|
||||
}))
|
||||
}
|
||||
|
||||
/// Unfortunately, novice unix users can sometimes be running
|
||||
/// with an overly permissive umask so we take care to install
|
||||
/// a more restrictive mask while we might be creating things
|
||||
|
@ -332,7 +332,7 @@ impl RemoteSshDomain {
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl Domain for RemoteSshDomain {
|
||||
fn spawn(
|
||||
async fn spawn(
|
||||
&self,
|
||||
size: PtySize,
|
||||
command: Option<CommandBuilder>,
|
||||
|
@ -149,7 +149,7 @@ impl TermWizTerminalDomain {
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl Domain for TermWizTerminalDomain {
|
||||
fn spawn(
|
||||
async fn spawn(
|
||||
&self,
|
||||
_size: PtySize,
|
||||
_command: Option<CommandBuilder>,
|
||||
|
Loading…
Reference in New Issue
Block a user