diff --git a/wezterm-gui/src/overlay/launcher.rs b/wezterm-gui/src/overlay/launcher.rs index 90da5fee8..f7a52c9cf 100644 --- a/wezterm-gui/src/overlay/launcher.rs +++ b/wezterm-gui/src/overlay/launcher.rs @@ -103,7 +103,7 @@ pub fn launcher( domain_id_of_current_tab: DomainId, mut term: TermWizTerminal, mux_window_id: WindowId, - domains: Vec<(DomainId, DomainState, String)>, + domains: Vec<(DomainId, String, DomainState, String)>, clipboard: ClipboardHelper, size: PtySize, ) -> anyhow::Result<()> { @@ -137,10 +137,10 @@ pub fn launcher( } } - for (domain_id, domain_state, domain_name) in &domains { + for (domain_id, domain_name, domain_state, domain_label) in &domains { let entry = if *domain_state == DomainState::Attached { Entry::Spawn { - label: format!("New Tab ({})", domain_name), + label: format!("New Tab ({})", domain_label), command: SpawnCommand { domain: SpawnTabDomain::DomainName(domain_name.to_string()), ..SpawnCommand::default() @@ -149,7 +149,7 @@ pub fn launcher( } } else { Entry::Attach { - label: format!("Attach {}", domain_name), + label: format!("Attach {}", domain_label), domain: *domain_id, } }; diff --git a/wezterm-gui/src/termwindow/mod.rs b/wezterm-gui/src/termwindow/mod.rs index b2d727a93..5cc6272f6 100644 --- a/wezterm-gui/src/termwindow/mod.rs +++ b/wezterm-gui/src/termwindow/mod.rs @@ -1217,7 +1217,7 @@ impl TermWindow { a.domain_id().cmp(&b.domain_id()) }); domains.retain(|dom| dom.spawnable()); - let domains: Vec<(DomainId, DomainState, String)> = domains + let domains: Vec<(DomainId, String, DomainState, String)> = domains .iter() .map(|dom| { let name = dom.domain_name(); @@ -1227,7 +1227,7 @@ impl TermWindow { } else { format!("domain `{}` - {}", name, label) }; - (dom.domain_id(), dom.state(), label) + (dom.domain_id(), name.to_string(), dom.state(), label) }) .collect(); diff --git a/wezterm-gui/src/termwindow/spawn.rs b/wezterm-gui/src/termwindow/spawn.rs index fe3d3d509..cec24e296 100644 --- a/wezterm-gui/src/termwindow/spawn.rs +++ b/wezterm-gui/src/termwindow/spawn.rs @@ -44,144 +44,158 @@ impl super::TermWindow { let spawn = spawn.clone(); promise::spawn::spawn(async move { - let mux = Mux::get().unwrap(); - let activity = Activity::new(); - let mux_builder; + if let Err(err) = + Self::spawn_command_internal(spawn, spawn_where, size, src_window_id, clipboard) + .await + { + log::error!("Failed to spawn: {:#}", err); + } + }) + .detach(); + } - let target_window_id = if spawn_where == SpawnWhere::NewWindow { - mux_builder = mux.new_empty_window(); - *mux_builder - } else { - src_window_id - }; + async fn spawn_command_internal( + spawn: SpawnCommand, + spawn_where: SpawnWhere, + size: PtySize, + src_window_id: MuxWindowId, + clipboard: ClipboardHelper, + ) -> anyhow::Result<()> { + let mux = Mux::get().unwrap(); + let activity = Activity::new(); + let mux_builder; - let (domain, cwd) = match spawn.domain { - SpawnTabDomain::DefaultDomain => { + let target_window_id = if spawn_where == SpawnWhere::NewWindow { + mux_builder = mux.new_empty_window(); + *mux_builder + } else { + src_window_id + }; + + let (domain, cwd) = match spawn.domain { + SpawnTabDomain::DefaultDomain => { + let cwd = mux + .get_active_tab_for_window(src_window_id) + .and_then(|tab| tab.get_active_pane()) + .and_then(|pane| pane.get_current_working_dir()); + (mux.default_domain().clone(), cwd) + } + SpawnTabDomain::CurrentPaneDomain => { + if spawn_where == SpawnWhere::NewWindow { + // CurrentPaneDomain is the default value for the spawn domain. + // It doesn't make sense to use it when spawning a new window, + // so we treat it as DefaultDomain instead. let cwd = mux .get_active_tab_for_window(src_window_id) .and_then(|tab| tab.get_active_pane()) .and_then(|pane| pane.get_current_working_dir()); (mux.default_domain().clone(), cwd) - } - SpawnTabDomain::CurrentPaneDomain => { - if spawn_where == SpawnWhere::NewWindow { - // CurrentPaneDomain is the default value for the spawn domain. - // It doesn't make sense to use it when spawning a new window, - // so we treat it as DefaultDomain instead. - let cwd = mux - .get_active_tab_for_window(src_window_id) - .and_then(|tab| tab.get_active_pane()) - .and_then(|pane| pane.get_current_working_dir()); - (mux.default_domain().clone(), cwd) - } else { - let tab = match mux.get_active_tab_for_window(src_window_id) { - Some(tab) => tab, - None => bail!("window has no tabs?"), - }; - let pane = tab - .get_active_pane() - .ok_or_else(|| anyhow!("current tab has no pane!?"))?; - ( - mux.get_domain(pane.domain_id()).ok_or_else(|| { - anyhow!("current tab has unresolvable domain id!?") - })?, - pane.get_current_working_dir(), - ) - } - } - SpawnTabDomain::DomainName(name) => ( - mux.get_domain_by_name(&name).ok_or_else(|| { - anyhow!("spawn_tab called with unresolvable domain name {}", name) - })?, - None, - ), - }; - - if domain.state() == DomainState::Detached { - bail!("Cannot spawn a tab into a Detached domain"); - } - - let cwd = if let Some(cwd) = spawn.cwd.as_ref() { - Some(cwd.to_str().map(|s| s.to_owned()).ok_or_else(|| { - anyhow!( - "Domain::spawn requires that the cwd be unicode in {:?}", - cwd - ) - })?) - } else { - match cwd { - Some(url) if url.scheme() == "file" => { - let path = url.path().to_string(); - // On Windows the file URI can produce a path like: - // `/C:\Users` which is valid in a file URI, but the leading slash - // is not liked by the windows file APIs, so we strip it off here. - let bytes = path.as_bytes(); - if bytes.len() > 2 && bytes[0] == b'/' && bytes[2] == b':' { - Some(path[1..].to_owned()) - } else { - Some(path) - } - } - Some(_) | None => None, - } - }; - - let cmd_builder = if let Some(args) = spawn.args { - let mut builder = CommandBuilder::from_argv(args.iter().map(Into::into).collect()); - for (k, v) in spawn.set_environment_variables.iter() { - builder.env(k, v); - } - if let Some(cwd) = spawn.cwd { - builder.cwd(cwd); - } - Some(builder) - } else { - None - }; - - match spawn_where { - SpawnWhere::SplitPane(direction) => { - let mux = Mux::get().unwrap(); - if let Some(tab) = mux.get_active_tab_for_window(target_window_id) { - let pane = tab - .get_active_pane() - .ok_or_else(|| anyhow!("tab to have a pane"))?; - - log::trace!("doing split_pane"); - domain - .split_pane(cmd_builder, cwd, tab.tab_id(), pane.pane_id(), direction) - .await?; - } else { - log::error!("there is no active tab while splitting pane!?"); - } - } - _ => { - let tab = domain - .spawn(size, cmd_builder, cwd, target_window_id) - .await?; - let tab_id = tab.tab_id(); + } else { + let tab = match mux.get_active_tab_for_window(src_window_id) { + Some(tab) => tab, + None => bail!("window has no tabs?"), + }; let pane = tab .get_active_pane() - .ok_or_else(|| anyhow!("newly spawned tab to have a pane"))?; + .ok_or_else(|| anyhow!("current tab has no pane!?"))?; + ( + mux.get_domain(pane.domain_id()) + .ok_or_else(|| anyhow!("current tab has unresolvable domain id!?"))?, + pane.get_current_working_dir(), + ) + } + } + SpawnTabDomain::DomainName(name) => ( + mux.get_domain_by_name(&name).ok_or_else(|| { + anyhow!("spawn_tab called with unresolvable domain name {}", name) + })?, + None, + ), + }; - if spawn_where != SpawnWhere::NewWindow { - let clipboard: Arc = Arc::new(clipboard); - pane.set_clipboard(&clipboard); - let mut window = mux - .get_window_mut(target_window_id) - .ok_or_else(|| anyhow!("no such window!?"))?; - if let Some(idx) = window.idx_by_id(tab_id) { - window.set_active(idx); - } + if domain.state() == DomainState::Detached { + bail!("Cannot spawn a tab into a Detached domain"); + } + + let cwd = if let Some(cwd) = spawn.cwd.as_ref() { + Some(cwd.to_str().map(|s| s.to_owned()).ok_or_else(|| { + anyhow!( + "Domain::spawn requires that the cwd be unicode in {:?}", + cwd + ) + })?) + } else { + match cwd { + Some(url) if url.scheme() == "file" => { + let path = url.path().to_string(); + // On Windows the file URI can produce a path like: + // `/C:\Users` which is valid in a file URI, but the leading slash + // is not liked by the windows file APIs, so we strip it off here. + let bytes = path.as_bytes(); + if bytes.len() > 2 && bytes[0] == b'/' && bytes[2] == b':' { + Some(path[1..].to_owned()) + } else { + Some(path) } } - }; + Some(_) | None => None, + } + }; - drop(activity); + let cmd_builder = if let Some(args) = spawn.args { + let mut builder = CommandBuilder::from_argv(args.iter().map(Into::into).collect()); + for (k, v) in spawn.set_environment_variables.iter() { + builder.env(k, v); + } + if let Some(cwd) = spawn.cwd { + builder.cwd(cwd); + } + Some(builder) + } else { + None + }; - Ok(()) - }) - .detach(); + match spawn_where { + SpawnWhere::SplitPane(direction) => { + let mux = Mux::get().unwrap(); + if let Some(tab) = mux.get_active_tab_for_window(target_window_id) { + let pane = tab + .get_active_pane() + .ok_or_else(|| anyhow!("tab to have a pane"))?; + + log::trace!("doing split_pane"); + domain + .split_pane(cmd_builder, cwd, tab.tab_id(), pane.pane_id(), direction) + .await?; + } else { + log::error!("there is no active tab while splitting pane!?"); + } + } + _ => { + let tab = domain + .spawn(size, cmd_builder, cwd, target_window_id) + .await?; + let tab_id = tab.tab_id(); + let pane = tab + .get_active_pane() + .ok_or_else(|| anyhow!("newly spawned tab to have a pane"))?; + + if spawn_where != SpawnWhere::NewWindow { + let clipboard: Arc = Arc::new(clipboard); + pane.set_clipboard(&clipboard); + let mut window = mux + .get_window_mut(target_window_id) + .ok_or_else(|| anyhow!("no such window!?"))?; + if let Some(idx) = window.idx_by_id(tab_id) { + window.set_active(idx); + } + } + } + }; + + drop(activity); + + Ok(()) } pub fn spawn_tab(&mut self, domain: &SpawnTabDomain) {