1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 13:52:55 +03:00

refactor: split out termwindow spawn functions

This commit is contained in:
Wez Furlong 2021-02-27 17:22:11 -08:00
parent 6ff349308b
commit 63ca8e88b6
4 changed files with 202 additions and 193 deletions

View File

@ -5,7 +5,8 @@
//! be rendered as a popup/context menu if the system supports it; at the
//! time of writing our window layer doesn't provide an API for context
//! menus.
use crate::gui::termwindow::{ClipboardHelper, SpawnWhere, TermWindow};
use crate::gui::termwindow::spawn::SpawnWhere;
use crate::gui::termwindow::{ClipboardHelper, TermWindow};
use anyhow::anyhow;
use config::configuration;
use config::keyassignment::{SpawnCommand, SpawnTabDomain};

View File

@ -21,7 +21,7 @@ use ::window::glium::Surface;
use ::window::MouseButtons as WMB;
use ::window::MouseEventKind as WMEK;
use ::window::*;
use anyhow::{anyhow, bail, ensure};
use anyhow::{anyhow, ensure};
use config::keyassignment::{
ClipboardCopyDestination, ClipboardPasteSource, InputMap, KeyAssignment, MouseEventTrigger,
SpawnCommand, SpawnTabDomain,
@ -36,7 +36,7 @@ use mux::renderable::{RenderableDimensions, StableCursorPosition};
use mux::tab::{PositionedPane, PositionedSplit, SplitDirection, TabId};
use mux::window::WindowId as MuxWindowId;
use mux::Mux;
use portable_pty::{CommandBuilder, PtySize};
use portable_pty::PtySize;
use std::any::Any;
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
@ -57,6 +57,8 @@ use wezterm_term::input::LastMouseClick;
use wezterm_term::{ClipboardSelection, Line, StableRowIndex, TerminalConfiguration};
mod render;
pub mod spawn;
use spawn::SpawnWhere;
const ATLAS_SIZE: usize = 128;
@ -70,13 +72,6 @@ pub fn set_window_class(cls: &str) {
*WINDOW_CLASS.lock().unwrap() = cls.to_owned();
}
#[derive(Copy, Debug, Clone, Eq, PartialEq)]
pub enum SpawnWhere {
NewWindow,
NewTab,
SplitPane(SplitDirection),
}
#[derive(Debug, Clone, Copy)]
struct RowsAndCols {
rows: usize,
@ -1682,179 +1677,6 @@ impl TermWindow {
self.move_tab(tab)
}
fn spawn_command(&mut self, spawn: &SpawnCommand, spawn_where: SpawnWhere) {
Self::spawn_command_impl(
spawn,
spawn_where,
self.terminal_size,
self.mux_window_id,
ClipboardHelper {
window: self.window.as_ref().unwrap().clone(),
clipboard_contents: Arc::clone(&self.clipboard_contents),
},
)
}
pub fn spawn_command_impl(
spawn: &SpawnCommand,
spawn_where: SpawnWhere,
size: PtySize,
src_window_id: MuxWindowId,
clipboard: ClipboardHelper,
) {
let spawn = spawn.clone();
promise::spawn::spawn(async move {
let mux = Mux::get().unwrap();
let activity = Activity::new();
let mux_builder;
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)
} 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();
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<dyn wezterm_term::Clipboard> = 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(())
})
.detach();
}
fn spawn_tab(&mut self, domain: &SpawnTabDomain) {
self.spawn_command(
&SpawnCommand {
domain: domain.clone(),
..Default::default()
},
SpawnWhere::NewTab,
);
}
fn selection_text(&self, pane: &Rc<dyn Pane>) -> String {
let mut s = String::new();
if let Some(sel) = self

View File

@ -1,10 +1,7 @@
use crate::gui::termwindow::rgbcolor_alpha_to_window_color;
use crate::gui::termwindow::rgbcolor_to_window_color;
use crate::gui::termwindow::BorrowedShapeCacheKey;
use crate::gui::termwindow::MappedQuads;
use crate::gui::termwindow::RenderState;
use crate::gui::termwindow::ScrollHit;
use crate::gui::termwindow::ShapedInfo;
use crate::gui::termwindow::{
rgbcolor_alpha_to_window_color, rgbcolor_to_window_color, BorrowedShapeCacheKey, MappedQuads,
RenderState, ScrollHit, ShapedInfo,
};
use ::window::bitmaps::{Texture2d, TextureCoord, TextureRect, TextureSize};
use ::window::glium;
use ::window::glium::uniforms::{
@ -21,9 +18,7 @@ use std::rc::Rc;
use std::sync::Arc;
use termwiz::surface::{CursorShape, CursorVisibility};
use wezterm_font::units::PixelLength;
use wezterm_term::color::ColorAttribute;
use wezterm_term::color::ColorPalette;
use wezterm_term::color::RgbColor;
use wezterm_term::color::{ColorAttribute, ColorPalette, RgbColor};
use wezterm_term::{CellAttributes, Line, StableRowIndex};
use window::bitmaps::atlas::SpriteSlice;
use window::Color;

View File

@ -0,0 +1,191 @@
use crate::gui::termwindow::{ClipboardHelper, MuxWindowId};
use anyhow::{anyhow, bail};
use config::keyassignment::{SpawnCommand, SpawnTabDomain};
use mux::activity::Activity;
use mux::domain::DomainState;
use mux::tab::SplitDirection;
use mux::Mux;
use portable_pty::{CommandBuilder, PtySize};
use std::sync::Arc;
#[derive(Copy, Debug, Clone, Eq, PartialEq)]
pub enum SpawnWhere {
NewWindow,
NewTab,
SplitPane(SplitDirection),
}
impl super::TermWindow {
pub fn spawn_command(&mut self, spawn: &SpawnCommand, spawn_where: SpawnWhere) {
Self::spawn_command_impl(
spawn,
spawn_where,
self.terminal_size,
self.mux_window_id,
ClipboardHelper {
window: self.window.as_ref().unwrap().clone(),
clipboard_contents: Arc::clone(&self.clipboard_contents),
},
)
}
pub fn spawn_command_impl(
spawn: &SpawnCommand,
spawn_where: SpawnWhere,
size: PtySize,
src_window_id: MuxWindowId,
clipboard: ClipboardHelper,
) {
let spawn = spawn.clone();
promise::spawn::spawn(async move {
let mux = Mux::get().unwrap();
let activity = Activity::new();
let mux_builder;
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)
} 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();
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<dyn wezterm_term::Clipboard> = 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(())
})
.detach();
}
pub fn spawn_tab(&mut self, domain: &SpawnTabDomain) {
self.spawn_command(
&SpawnCommand {
domain: domain.clone(),
..Default::default()
},
SpawnWhere::NewTab,
);
}
}