From 6e06b9af025459be789c02dc6b372803d3f54d66 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Wed, 23 Nov 2022 09:05:30 -0700 Subject: [PATCH] mux: Pane is now required to be Send+Sync. Use Arc --- Cargo.lock | 3 + lua-api-crates/mux/src/pane.rs | 3 +- mux/Cargo.toml | 1 + mux/src/domain.rs | 10 +- mux/src/lib.rs | 22 +-- mux/src/localpane.rs | 145 +++++++++--------- mux/src/pane.rs | 22 +-- mux/src/ssh.rs | 7 +- mux/src/tab.rs | 75 ++++----- mux/src/termwiztermtab.rs | 73 ++++----- mux/src/tmux.rs | 62 ++++---- mux/src/tmux_commands.rs | 20 +-- mux/src/tmux_pty.rs | 21 +-- term/src/config.rs | 2 +- term/src/terminal.rs | 10 +- term/src/terminalstate/keyboard.rs | 1 + term/src/terminalstate/kitty.rs | 1 + term/src/terminalstate/mod.rs | 7 +- term/src/terminalstate/mouse.rs | 1 + term/src/terminalstate/performer.rs | 1 + term/src/test/mod.rs | 9 +- wezterm-client/Cargo.toml | 1 + wezterm-client/src/domain.rs | 14 +- wezterm-client/src/pane/clientpane.rs | 121 +++++++-------- wezterm-client/src/pane/mousestate.rs | 14 +- wezterm-client/src/pane/renderable.rs | 4 +- wezterm-gui/Cargo.toml | 1 + wezterm-gui/src/overlay/copy.rs | 57 ++++--- wezterm-gui/src/overlay/mod.rs | 6 +- wezterm-gui/src/overlay/quickselect.rs | 53 ++++--- wezterm-gui/src/termwindow/clipboard.rs | 4 +- wezterm-gui/src/termwindow/keyevent.rs | 8 +- wezterm-gui/src/termwindow/mod.rs | 28 ++-- wezterm-gui/src/termwindow/mouseevent.rs | 17 +- wezterm-gui/src/termwindow/render.rs | 8 +- wezterm-gui/src/termwindow/selection.rs | 12 +- wezterm-mux-server-impl/src/sessionhandler.rs | 5 +- 37 files changed, 423 insertions(+), 426 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04ff0c832..4ced570bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2918,6 +2918,7 @@ dependencies = [ "names", "nix 0.25.1", "ntapi", + "parking_lot 0.12.1", "percent-encoding", "portable-pty", "procinfo", @@ -5781,6 +5782,7 @@ dependencies = [ "metrics", "mux", "openssl", + "parking_lot 0.12.1", "portable-pty", "promise", "rangeset", @@ -5918,6 +5920,7 @@ dependencies = [ "mux-lua", "open", "ordered-float", + "parking_lot 0.12.1", "portable-pty", "promise", "pulldown-cmark", diff --git a/lua-api-crates/mux/src/pane.rs b/lua-api-crates/mux/src/pane.rs index 051fc964b..c878d5ca4 100644 --- a/lua-api-crates/mux/src/pane.rs +++ b/lua-api-crates/mux/src/pane.rs @@ -1,11 +1,12 @@ use super::*; use luahelper::dynamic_to_lua_value; +use std::sync::Arc; #[derive(Clone, Copy, Debug)] pub struct MuxPane(pub PaneId); impl MuxPane { - pub fn resolve<'a>(&self, mux: &'a Rc) -> mlua::Result> { + pub fn resolve<'a>(&self, mux: &'a Rc) -> mlua::Result> { mux.get_pane(self.0) .ok_or_else(|| mlua::Error::external(format!("pane id {} not found in mux", self.0))) } diff --git a/mux/Cargo.toml b/mux/Cargo.toml index 30fed5531..6f0d32d5f 100644 --- a/mux/Cargo.toml +++ b/mux/Cargo.toml @@ -27,6 +27,7 @@ metrics = { version="0.17", features=["std"]} mlua = "0.8.3" names = { version = "0.12", default-features = false } nix = {version="0.25", features=["term"]} +parking_lot = "0.12" percent-encoding = "2" portable-pty = { path = "../pty", features = ["serde_support"]} procinfo = { path = "../procinfo" } diff --git a/mux/src/domain.rs b/mux/src/domain.rs index 6c0891c45..d21eed524 100644 --- a/mux/src/domain.rs +++ b/mux/src/domain.rs @@ -74,7 +74,7 @@ pub trait Domain: Downcast { tab: TabId, pane_id: PaneId, split_request: SplitRequest, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let mux = Mux::get().unwrap(); let tab = match mux.get_tab(tab) { Some(t) => t, @@ -124,7 +124,7 @@ pub trait Domain: Downcast { } }; - tab.split_and_insert(pane_index, split_request, Rc::clone(&pane))?; + tab.split_and_insert(pane_index, split_request, Arc::clone(&pane))?; Ok(pane) } @@ -133,7 +133,7 @@ pub trait Domain: Downcast { size: TerminalSize, command: Option, command_dir: Option, - ) -> anyhow::Result>; + ) -> anyhow::Result>; /// Returns false if the `spawn` method will never succeed. /// There are some internal placeholder domains that are @@ -475,7 +475,7 @@ impl Domain for LocalDomain { size: TerminalSize, command: Option, command_dir: Option, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let pane_id = alloc_pane_id(); let cmd = self.build_command(command, command_dir, pane_id).await?; let pair = self @@ -510,7 +510,7 @@ impl Domain for LocalDomain { terminal.enable_conpty_quirks(); } - let pane: Rc = Rc::new(LocalPane::new( + let pane: Arc = Arc::new(LocalPane::new( pane_id, terminal, child, diff --git a/mux/src/lib.rs b/mux/src/lib.rs index a1acc9d89..de88b6de5 100644 --- a/mux/src/lib.rs +++ b/mux/src/lib.rs @@ -82,7 +82,7 @@ static SUB_ID: AtomicUsize = AtomicUsize::new(0); pub struct Mux { tabs: RefCell>>, - panes: RefCell>>, + panes: RefCell>>, windows: RefCell>, default_domain: RefCell>>, domains: RefCell>>, @@ -616,15 +616,15 @@ impl Mux { res } - pub fn get_pane(&self, pane_id: PaneId) -> Option> { - self.panes.borrow().get(&pane_id).map(Rc::clone) + pub fn get_pane(&self, pane_id: PaneId) -> Option> { + self.panes.borrow().get(&pane_id).map(Arc::clone) } pub fn get_tab(&self, tab_id: TabId) -> Option> { self.tabs.borrow().get(&tab_id).map(Rc::clone) } - pub fn add_pane(&self, pane: &Rc) -> Result<(), Error> { + pub fn add_pane(&self, pane: &Arc) -> Result<(), Error> { if self.panes.borrow().contains_key(&pane.pane_id()) { return Ok(()); } @@ -639,7 +639,7 @@ impl Mux { self.panes .borrow_mut() - .insert(pane.pane_id(), Rc::clone(pane)); + .insert(pane.pane_id(), Arc::clone(pane)); let pane_id = pane.pane_id(); if let Some(reader) = pane.reader()? { let banner = self.banner.borrow().clone(); @@ -857,11 +857,11 @@ impl Mux { self.is_workspace_empty(&workspace) } - pub fn iter_panes(&self) -> Vec> { + pub fn iter_panes(&self) -> Vec> { self.panes .borrow() .iter() - .map(|(_, v)| Rc::clone(v)) + .map(|(_, v)| Arc::clone(v)) .collect() } @@ -965,7 +965,7 @@ impl Mux { fn resolve_cwd( &self, command_dir: Option, - pane: Option>, + pane: Option>, ) -> Option { command_dir.or_else(|| { match pane { @@ -1000,7 +1000,7 @@ impl Mux { request: SplitRequest, source: SplitSource, domain: config::keyassignment::SpawnTabDomain, - ) -> anyhow::Result<(Rc, TerminalSize)> { + ) -> anyhow::Result<(Arc, TerminalSize)> { let (_pane_domain_id, window_id, tab_id) = self .resolve_pane_id(pane_id) .ok_or_else(|| anyhow!("pane_id {} invalid", pane_id))?; @@ -1024,7 +1024,7 @@ impl Mux { command_dir, } => SplitSource::Spawn { command, - command_dir: self.resolve_cwd(command_dir, Some(Rc::clone(¤t_pane))), + command_dir: self.resolve_cwd(command_dir, Some(Arc::clone(¤t_pane))), }, other => other, }; @@ -1105,7 +1105,7 @@ impl Mux { size: TerminalSize, current_pane_id: Option, workspace_for_new_window: String, - ) -> anyhow::Result<(Rc, Rc, WindowId)> { + ) -> anyhow::Result<(Rc, Arc, WindowId)> { let domain = self .resolve_spawn_tab_domain(current_pane_id, &domain) .context("resolve_spawn_tab_domain")?; diff --git a/mux/src/localpane.rs b/mux/src/localpane.rs index 9fdda817a..90f360644 100644 --- a/mux/src/localpane.rs +++ b/mux/src/localpane.rs @@ -10,12 +10,12 @@ use anyhow::Error; use async_trait::async_trait; use config::keyassignment::ScrollbackEraseMode; use config::{configuration, ExitBehavior}; +use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; use portable_pty::{Child, ChildKiller, ExitStatus, MasterPty, PtySize}; use procinfo::LocalProcessInfo; use rangeset::RangeSet; use smol::channel::{bounded, Receiver, TryRecvError}; use std::borrow::Cow; -use std::cell::{RefCell, RefMut}; use std::collections::{BTreeMap, HashMap, HashSet}; use std::convert::TryInto; use std::io::{Result as IoResult, Write}; @@ -39,7 +39,7 @@ enum ProcessState { Running { child_waiter: Receiver>, pid: Option, - signaller: Box, + signaller: Box, // Whether we've explicitly killed the child killed: bool, }, @@ -57,13 +57,13 @@ struct CachedProcInfo { pub struct LocalPane { pane_id: PaneId, - terminal: RefCell, - process: RefCell, - pty: RefCell>, - writer: RefCell>, + terminal: Mutex, + process: Mutex, + pty: Mutex>, + writer: Mutex>, domain_id: DomainId, - tmux_domain: RefCell>>, - proc_list: RefCell>, + tmux_domain: Mutex>>, + proc_list: Mutex>, command_description: String, } @@ -78,7 +78,7 @@ impl Pane for LocalPane { let mut map: BTreeMap = BTreeMap::new(); #[cfg(unix)] - if let Some(tio) = self.pty.borrow().get_termios() { + if let Some(tio) = self.pty.lock().get_termios() { use nix::sys::termios::LocalFlags; // Detect whether we might be in password input mode. // If local echo is disabled and canonical input mode @@ -96,19 +96,19 @@ impl Pane for LocalPane { } fn get_cursor_position(&self) -> StableCursorPosition { - let mut cursor = terminal_get_cursor_position(&mut self.terminal.borrow_mut()); - if self.tmux_domain.borrow().is_some() { + let mut cursor = terminal_get_cursor_position(&mut self.terminal.lock()); + if self.tmux_domain.lock().is_some() { cursor.visibility = termwiz::surface::CursorVisibility::Hidden; } cursor } fn get_keyboard_encoding(&self) -> KeyboardEncoding { - self.terminal.borrow().get_keyboard_encoding() + self.terminal.lock().get_keyboard_encoding() } fn get_current_seqno(&self) -> SequenceNo { - self.terminal.borrow().current_seqno() + self.terminal.lock().current_seqno() } fn get_changed_since( @@ -116,7 +116,7 @@ impl Pane for LocalPane { lines: Range, seqno: SequenceNo, ) -> RangeSet { - terminal_get_dirty_lines(&mut self.terminal.borrow_mut(), lines, seqno) + terminal_get_dirty_lines(&mut self.terminal.lock(), lines, seqno) } fn for_each_logical_line_in_stable_range_mut( @@ -125,14 +125,14 @@ impl Pane for LocalPane { for_line: &mut dyn ForEachPaneLogicalLine, ) { terminal_for_each_logical_line_in_stable_range_mut( - &mut self.terminal.borrow_mut(), + &mut self.terminal.lock(), lines, for_line, ); } fn with_lines_mut(&self, lines: Range, with_lines: &mut dyn WithPaneLines) { - terminal_with_lines_mut(&mut self.terminal.borrow_mut(), lines, with_lines) + terminal_with_lines_mut(&mut self.terminal.lock(), lines, with_lines) } fn get_lines(&self, lines: Range) -> (StableRowIndex, Vec) { @@ -144,15 +144,15 @@ impl Pane for LocalPane { } fn get_dimensions(&self) -> RenderableDimensions { - terminal_get_dimensions(&mut self.terminal.borrow_mut()) + terminal_get_dimensions(&mut self.terminal.lock()) } fn copy_user_vars(&self) -> HashMap { - self.terminal.borrow().user_vars().clone() + self.terminal.lock().user_vars().clone() } fn kill(&self) { - let mut proc = self.process.borrow_mut(); + let mut proc = self.process.lock(); log::debug!( "killing process in pane {}, state is {:?}", self.pane_id, @@ -173,7 +173,7 @@ impl Pane for LocalPane { } fn is_dead(&self) -> bool { - let mut proc = self.process.borrow_mut(); + let mut proc = self.process.lock(); let mut notify = None; const EXIT_BEHAVIOR: &str = "This message is shown because \ @@ -255,79 +255,82 @@ impl Pane for LocalPane { } fn set_clipboard(&self, clipboard: &Arc) { - self.terminal.borrow_mut().set_clipboard(clipboard); + self.terminal.lock().set_clipboard(clipboard); } fn set_download_handler(&self, handler: &Arc) { - self.terminal.borrow_mut().set_download_handler(handler); + self.terminal.lock().set_download_handler(handler); } fn set_config(&self, config: Arc) { - self.terminal.borrow_mut().set_config(config); + self.terminal.lock().set_config(config); } fn get_config(&self) -> Option> { - Some(self.terminal.borrow().get_config()) + Some(self.terminal.lock().get_config()) } fn perform_actions(&self, actions: Vec) { - self.terminal.borrow_mut().perform_actions(actions) + self.terminal.lock().perform_actions(actions) } fn mouse_event(&self, event: MouseEvent) -> Result<(), Error> { Mux::get().unwrap().record_input_for_current_identity(); - self.terminal.borrow_mut().mouse_event(event) + self.terminal.lock().mouse_event(event) } fn key_down(&self, key: KeyCode, mods: KeyModifiers) -> Result<(), Error> { Mux::get().unwrap().record_input_for_current_identity(); - if self.tmux_domain.borrow().is_some() { + if self.tmux_domain.lock().is_some() { log::error!("key: {:?}", key); if key == KeyCode::Char('q') { - self.terminal.borrow_mut().send_paste("detach\n")?; + self.terminal.lock().send_paste("detach\n")?; } return Ok(()); } else { - self.terminal.borrow_mut().key_down(key, mods) + self.terminal.lock().key_down(key, mods) } } fn key_up(&self, key: KeyCode, mods: KeyModifiers) -> Result<(), Error> { Mux::get().unwrap().record_input_for_current_identity(); - self.terminal.borrow_mut().key_up(key, mods) + self.terminal.lock().key_up(key, mods) } fn resize(&self, size: TerminalSize) -> Result<(), Error> { - self.pty.borrow_mut().resize(PtySize { + self.pty.lock().resize(PtySize { rows: size.rows.try_into()?, cols: size.cols.try_into()?, pixel_width: size.pixel_width.try_into()?, pixel_height: size.pixel_height.try_into()?, })?; - self.terminal.borrow_mut().resize(size); + self.terminal.lock().resize(size); Ok(()) } - fn writer(&self) -> RefMut { + fn writer(&self) -> MappedMutexGuard { Mux::get().unwrap().record_input_for_current_identity(); - self.writer.borrow_mut() + MutexGuard::map(self.writer.lock(), |writer| { + let w: &mut dyn std::io::Write = writer; + w + }) } fn reader(&self) -> anyhow::Result>> { - Ok(Some(self.pty.borrow_mut().try_clone_reader()?)) + Ok(Some(self.pty.lock().try_clone_reader()?)) } fn send_paste(&self, text: &str) -> Result<(), Error> { Mux::get().unwrap().record_input_for_current_identity(); - if self.tmux_domain.borrow().is_some() { + if self.tmux_domain.lock().is_some() { Ok(()) } else { - self.terminal.borrow_mut().send_paste(text) + self.terminal.lock().send_paste(text) } } fn get_title(&self) -> String { - let title = self.terminal.borrow_mut().get_title().to_string(); + let title = self.terminal.lock().get_title().to_string(); // If the title is the default pane title, then try to spice // things up a bit by returning the process basename instead if title == "wezterm" { @@ -343,7 +346,7 @@ impl Pane for LocalPane { } fn palette(&self) -> ColorPalette { - self.terminal.borrow().palette() + self.terminal.lock().palette() } fn domain_id(&self) -> DomainId { @@ -353,41 +356,41 @@ impl Pane for LocalPane { fn erase_scrollback(&self, erase_mode: ScrollbackEraseMode) { match erase_mode { ScrollbackEraseMode::ScrollbackOnly => { - self.terminal.borrow_mut().erase_scrollback(); + self.terminal.lock().erase_scrollback(); } ScrollbackEraseMode::ScrollbackAndViewport => { - self.terminal.borrow_mut().erase_scrollback_and_viewport(); + self.terminal.lock().erase_scrollback_and_viewport(); } } } fn focus_changed(&self, focused: bool) { - self.terminal.borrow_mut().focus_changed(focused); + self.terminal.lock().focus_changed(focused); } fn has_unseen_output(&self) -> bool { - self.terminal.borrow().has_unseen_output() + self.terminal.lock().has_unseen_output() } fn is_mouse_grabbed(&self) -> bool { - if self.tmux_domain.borrow().is_some() { + if self.tmux_domain.lock().is_some() { false } else { - self.terminal.borrow().is_mouse_grabbed() + self.terminal.lock().is_mouse_grabbed() } } fn is_alt_screen_active(&self) -> bool { - if self.tmux_domain.borrow().is_some() { + if self.tmux_domain.lock().is_some() { false } else { - self.terminal.borrow().is_alt_screen_active() + self.terminal.lock().is_alt_screen_active() } } fn get_current_working_dir(&self) -> Option { self.terminal - .borrow() + .lock() .get_current_dir() .cloned() .or_else(|| self.divine_current_working_dir()) @@ -395,7 +398,7 @@ impl Pane for LocalPane { fn get_foreground_process_info(&self) -> Option { #[cfg(unix)] - if let Some(pid) = self.pty.borrow().process_group_leader() { + if let Some(pid) = self.pty.lock().process_group_leader() { return LocalProcessInfo::with_root_pid(pid as u32); } @@ -404,7 +407,7 @@ impl Pane for LocalPane { fn get_foreground_process_name(&self) -> Option { #[cfg(unix)] - if let Some(pid) = self.pty.borrow().process_group_leader() { + if let Some(pid) = self.pty.lock().process_group_leader() { if let Some(path) = LocalProcessInfo::executable_path(pid as u32) { return Some(path.to_string_lossy().to_string()); } @@ -478,7 +481,7 @@ impl Pane for LocalPane { // If the process is dead but exit_behavior is holding the // window, we don't need to prompt to confirm closing. // That is detectable as no longer having a process group leader. - if self.pty.borrow().process_group_leader().is_none() { + if self.pty.lock().process_group_leader().is_none() { return true; } } @@ -488,7 +491,7 @@ impl Pane for LocalPane { } fn get_semantic_zones(&self) -> anyhow::Result> { - let mut term = self.terminal.borrow_mut(); + let mut term = self.terminal.lock(); term.get_semantic_zones() } @@ -498,7 +501,7 @@ impl Pane for LocalPane { range: Range, limit: Option, ) -> anyhow::Result> { - let term = self.terminal.borrow(); + let term = self.terminal.lock(); let screen = term.screen(); enum CompiledPattern { @@ -713,9 +716,7 @@ impl wezterm_term::DeviceControlHandler for LocalPaneDCSHandler { if let Some(pane) = mux.get_pane(self.pane_id) { let pane = pane.downcast_ref::().unwrap(); - pane.tmux_domain - .borrow_mut() - .replace(Arc::clone(&tmux_domain)); + pane.tmux_domain.lock().replace(Arc::clone(&tmux_domain)); emit_output_for_pane( self.pane_id, @@ -737,7 +738,7 @@ impl wezterm_term::DeviceControlHandler for LocalPaneDCSHandler { let mux = Mux::get().expect("to be called on main thread"); if let Some(pane) = mux.get_pane(self.pane_id) { let pane = pane.downcast_ref::().unwrap(); - pane.tmux_domain.borrow_mut().take(); + pane.tmux_domain.lock().take(); } mux.domain_was_detached(tmux.domain_id); } @@ -808,7 +809,7 @@ fn split_child( mut process: Box, ) -> ( Receiver>, - Box, + Box, Option, ) { let pid = process.process_id(); @@ -834,8 +835,8 @@ impl LocalPane { pane_id: PaneId, mut terminal: Terminal, process: Box, - pty: Box, - writer: Box, + pty: Box, + writer: Box, domain_id: DomainId, command_description: String, ) -> Self { @@ -849,25 +850,25 @@ impl LocalPane { Self { pane_id, - terminal: RefCell::new(terminal), - process: RefCell::new(ProcessState::Running { + terminal: Mutex::new(terminal), + process: Mutex::new(ProcessState::Running { child_waiter: process, pid, signaller, killed: false, }), - pty: RefCell::new(pty), - writer: RefCell::new(writer), + pty: Mutex::new(pty), + writer: Mutex::new(writer), domain_id, - tmux_domain: RefCell::new(None), - proc_list: RefCell::new(None), + tmux_domain: Mutex::new(None), + proc_list: Mutex::new(None), command_description, } } fn divine_current_working_dir(&self) -> Option { #[cfg(unix)] - if let Some(pid) = self.pty.borrow().process_group_leader() { + if let Some(pid) = self.pty.lock().process_group_leader() { if let Some(path) = LocalProcessInfo::current_working_dir(pid as u32) { return Url::parse(&format!("file://localhost{}", path.display())).ok(); } @@ -885,9 +886,9 @@ impl LocalPane { None } - fn divine_process_list(&self, force_refresh: bool) -> Option> { - if let ProcessState::Running { pid: Some(pid), .. } = &*self.process.borrow() { - let mut proc_list = self.proc_list.borrow_mut(); + fn divine_process_list(&self, force_refresh: bool) -> Option> { + if let ProcessState::Running { pid: Some(pid), .. } = &*self.process.lock() { + let mut proc_list = self.proc_list.lock(); let expired = force_refresh || proc_list @@ -934,7 +935,7 @@ impl LocalPane { log::trace!("CachedProcInfo updated"); } - return Some(RefMut::map(proc_list, |info| info.as_mut().unwrap())); + return Some(MutexGuard::map(proc_list, |info| info.as_mut().unwrap())); } None } @@ -953,7 +954,7 @@ impl Drop for LocalPane { fn drop(&mut self) { // Avoid lingering zombies if we can, but don't block forever. // - if let ProcessState::Running { signaller, .. } = &mut *self.process.borrow_mut() { + if let ProcessState::Running { signaller, .. } = &mut *self.process.lock() { let _ = signaller.kill(); } } diff --git a/mux/src/pane.rs b/mux/src/pane.rs index 242111969..739e6c00a 100644 --- a/mux/src/pane.rs +++ b/mux/src/pane.rs @@ -4,12 +4,12 @@ use crate::Mux; use async_trait::async_trait; use config::keyassignment::{KeyAssignment, ScrollbackEraseMode}; use downcast_rs::{impl_downcast, Downcast}; +use parking_lot::{MappedMutexGuard, Mutex}; use rangeset::RangeSet; use serde::{Deserialize, Serialize}; -use std::cell::RefMut; use std::collections::HashMap; use std::ops::Range; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use termwiz::hyperlink::Rule; use termwiz::input::KeyboardEncoding; use termwiz::surface::{Line, SequenceNo}; @@ -107,7 +107,7 @@ struct Paste { } fn paste_next_chunk(paste: &Arc>) { - let mut locked = paste.lock().unwrap(); + let mut locked = paste.lock(); let mux = Mux::get().unwrap(); let pane = mux.get_pane(locked.pane_id).unwrap(); @@ -186,7 +186,7 @@ impl LogicalLine { /// A Pane represents a view on a terminal #[async_trait(?Send)] -pub trait Pane: Downcast { +pub trait Pane: Downcast + Send + Sync { fn pane_id(&self) -> PaneId; /// Returns the 0-based cursor position relative to the top left of @@ -256,7 +256,7 @@ pub trait Pane: Downcast { fn get_title(&self) -> String; fn send_paste(&self, text: &str) -> anyhow::Result<()>; fn reader(&self) -> anyhow::Result>>; - fn writer(&self) -> RefMut; + fn writer(&self) -> MappedMutexGuard; fn resize(&self, size: TerminalSize) -> anyhow::Result<()>; /// Called as a hint that the pane is being resized as part of /// a zoom-to-fill-all-the-tab-space operation. @@ -562,12 +562,12 @@ pub fn impl_get_lines_via_with_lines( mod test { use super::*; use k9::snapshot; + use parking_lot::{MappedMutexGuard, Mutex}; use std::borrow::Cow; - use std::cell::RefCell; use termwiz::surface::SEQ_ZERO; struct FakePane { - lines: RefCell>, + lines: Mutex>, } impl Pane for FakePane { @@ -596,7 +596,7 @@ mod test { with_lines: &mut dyn WithPaneLines, ) { let mut line_refs = vec![]; - let mut lines = self.lines.borrow_mut(); + let mut lines = self.lines.lock(); for line in lines .iter_mut() .skip(stable_range.start as usize) @@ -624,7 +624,7 @@ mod test { ( first, self.lines - .borrow() + .lock() .iter() .skip(lines.start as usize) .take((lines.end - lines.start) as usize) @@ -645,7 +645,7 @@ mod test { fn reader(&self) -> anyhow::Result>> { Ok(None) } - fn writer(&self) -> RefMut { + fn writer(&self) -> MappedMutexGuard { unimplemented!() } fn resize(&self, _: TerminalSize) -> anyhow::Result<()> { @@ -739,7 +739,7 @@ mod test { ); let pane = FakePane { - lines: RefCell::new(physical_lines), + lines: Mutex::new(physical_lines), }; let logical = pane.get_logical_lines(0..30); diff --git a/mux/src/ssh.rs b/mux/src/ssh.rs index dac597038..51a0d052a 100644 --- a/mux/src/ssh.rs +++ b/mux/src/ssh.rs @@ -13,7 +13,6 @@ use smol::channel::{bounded, Receiver as AsyncReceiver}; use std::cell::RefCell; use std::collections::{HashMap, VecDeque}; use std::io::{BufWriter, Read, Write}; -use std::rc::Rc; use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; @@ -560,12 +559,12 @@ impl Domain for RemoteSshDomain { size: TerminalSize, command: Option, command_dir: Option, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let pane_id = alloc_pane_id(); let (command_line, env) = self.build_command(pane_id, command, command_dir)?; - let pty: Box; + let pty: Box; let child: Box; let writer: BoxedWriter; @@ -677,7 +676,7 @@ impl Domain for RemoteSshDomain { Box::new(writer.clone()), ); - let pane: Rc = Rc::new(LocalPane::new( + let pane: Arc = Arc::new(LocalPane::new( pane_id, terminal, child, diff --git a/mux/src/tab.rs b/mux/src/tab.rs index ee216be87..16a77aa35 100644 --- a/mux/src/tab.rs +++ b/mux/src/tab.rs @@ -10,12 +10,12 @@ use serde::{Deserialize, Serialize}; use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::convert::TryInto; -use std::rc::Rc; +use std::sync::Arc; use url::Url; use wezterm_term::{StableRowIndex, TerminalSize}; -pub type Tree = bintree::Tree, SplitDirectionAndSize>; -pub type Cursor = bintree::Cursor, SplitDirectionAndSize>; +pub type Tree = bintree::Tree, SplitDirectionAndSize>; +pub type Cursor = bintree::Cursor, SplitDirectionAndSize>; static TAB_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0); pub type TabId = usize; @@ -43,7 +43,7 @@ pub struct Tab { pane: RefCell>, size: RefCell, active: RefCell, - zoomed: RefCell>>, + zoomed: RefCell>>, title: RefCell, recency: RefCell, } @@ -69,7 +69,7 @@ pub struct PositionedPane { pub height: usize, pub pixel_height: usize, /// The pane instance - pub pane: Rc, + pub pane: Arc, } impl std::fmt::Debug for PositionedPane { @@ -199,7 +199,7 @@ pub struct PositionedSplit { pub size: usize, } -fn is_pane(pane: &Rc, other: &Option<&Rc>) -> bool { +fn is_pane(pane: &Arc, other: &Option<&Arc>) -> bool { if let Some(other) = other { other.pane_id() == pane.pane_id() } else { @@ -211,8 +211,8 @@ fn pane_tree( tree: &Tree, tab_id: TabId, window_id: WindowId, - active: Option<&Rc>, - zoomed: Option<&Rc>, + active: Option<&Arc>, + zoomed: Option<&Arc>, workspace: &str, left_col: usize, top_row: usize, @@ -278,12 +278,12 @@ fn pane_tree( fn build_from_pane_tree( tree: bintree::Tree, - active: &mut Option>, - zoomed: &mut Option>, + active: &mut Option>, + zoomed: &mut Option>, make_pane: &mut F, ) -> Tree where - F: FnMut(PaneEntry) -> Rc, + F: FnMut(PaneEntry) -> Arc, { match tree { bintree::Tree::Empty => Tree::Empty, @@ -297,10 +297,10 @@ where let is_active_pane = entry.is_active_pane; let pane = make_pane(entry); if is_zoomed_pane { - zoomed.replace(Rc::clone(&pane)); + zoomed.replace(Arc::clone(&pane)); } if is_active_pane { - active.replace(Rc::clone(&pane)); + active.replace(Arc::clone(&pane)); } Tree::Leaf(pane) } @@ -533,7 +533,7 @@ impl Tab { /// a new pane, otherwise the pane won't poll/update in the GUI. pub fn sync_with_pane_tree(&self, size: TerminalSize, root: PaneNode, mut make_pane: F) where - F: FnMut(PaneEntry) -> Rc, + F: FnMut(PaneEntry) -> Arc, { let mut active = None; let mut zoomed = None; @@ -781,7 +781,7 @@ impl Tab { pixel_width: size.pixel_width.into(), height: size.rows.into(), pixel_height: size.pixel_height.into(), - pane: Rc::clone(zoomed), + pane: Arc::clone(zoomed), }); return panes; } @@ -813,7 +813,7 @@ impl Tab { } } - let pane = Rc::clone(cursor.leaf_mut().unwrap()); + let pane = Arc::clone(cursor.leaf_mut().unwrap()); let dims = parent_size.unwrap_or_else(|| *self.size.borrow()); panes.push(PositionedPane { @@ -1366,7 +1366,7 @@ impl Tab { /// Remove pane from tab. /// The pane is still live in the mux; the intent is for the pane to /// be added to a different tab. - pub fn remove_pane(&self, pane_id: PaneId) -> Option> { + pub fn remove_pane(&self, pane_id: PaneId) -> Option> { let panes = self.remove_pane_if(|_, pane| pane.pane_id() == pane_id, false); for pane in panes { return Some(pane); @@ -1374,9 +1374,9 @@ impl Tab { None } - fn remove_pane_if(&self, f: F, kill: bool) -> Vec> + fn remove_pane_if(&self, f: F, kill: bool) -> Vec> where - F: Fn(usize, &Rc) -> bool, + F: Fn(usize, &Arc) -> bool, { let mut dead_panes = vec![]; let zoomed_pane = self.zoomed.borrow().as_ref().map(|p| p.pane_id()); @@ -1403,7 +1403,7 @@ impl Tab { }; if cursor.is_leaf() { - let pane = Rc::clone(cursor.leaf_mut().unwrap()); + let pane = Arc::clone(cursor.leaf_mut().unwrap()); if f(pane_index, &pane) { removed_indices.push(pane_index); if Some(pane.pane_id()) == zoomed_pane { @@ -1506,15 +1506,15 @@ impl Tab { dead_count == panes.len() } - pub fn get_active_pane(&self) -> Option> { + pub fn get_active_pane(&self) -> Option> { if let Some(zoomed) = self.zoomed.borrow().as_ref() { - return Some(Rc::clone(zoomed)); + return Some(Arc::clone(zoomed)); } self.iter_panes_ignoring_zoom() .iter() .nth(*self.active.borrow()) - .map(|p| Rc::clone(&p.pane)) + .map(|p| Arc::clone(&p.pane)) } #[allow(unused)] @@ -1522,7 +1522,7 @@ impl Tab { *self.active.borrow() } - pub fn set_active_pane(&self, pane: &Rc) { + pub fn set_active_pane(&self, pane: &Arc) { if let Some(item) = self .iter_panes_ignoring_zoom() .iter() @@ -1535,7 +1535,7 @@ impl Tab { } } - fn advise_focus_change(&self, prior: Option>) { + fn advise_focus_change(&self, prior: Option>) { let current = self.get_active_pane(); match (prior, current) { (Some(prior), Some(current)) if prior.pane_id() != current.pane_id() => { @@ -1564,8 +1564,8 @@ impl Tab { /// Assigns the root pane. /// This is suitable when creating a new tab and then assigning /// the initial pane - pub fn assign_pane(&self, pane: &Rc) { - match Tree::new().cursor().assign_top(Rc::clone(pane)) { + pub fn assign_pane(&self, pane: &Arc) { + match Tree::new().cursor().assign_top(Arc::clone(pane)) { Ok(c) => *self.pane.borrow_mut() = Some(c.tree()), Err(_) => panic!("tried to assign root pane to non-empty tree"), } @@ -1731,7 +1731,7 @@ impl Tab { &self, pane_index: usize, request: SplitRequest, - pane: Rc, + pane: Arc, ) -> anyhow::Result { if self.zoomed.borrow().is_some() { anyhow::bail!("cannot split while zoomed"); @@ -1786,9 +1786,9 @@ impl Tab { if request.top_level && !cursor.is_leaf() { let result = if request.target_is_second { - cursor.split_node_and_insert_right(Rc::clone(&pane)) + cursor.split_node_and_insert_right(Arc::clone(&pane)) } else { - cursor.split_node_and_insert_left(Rc::clone(&pane)) + cursor.split_node_and_insert_left(Arc::clone(&pane)) }; cursor = match result { Ok(c) => { @@ -1820,7 +1820,7 @@ impl Tab { } }; - let existing_pane = Rc::clone(cursor.leaf_mut().unwrap()); + let existing_pane = Arc::clone(cursor.leaf_mut().unwrap()); let (pane1, pane2) = if request.target_is_second { (existing_pane, pane) @@ -1965,6 +1965,7 @@ impl Into for SerdeUrl { mod test { use super::*; use crate::renderable::*; + use parking_lot::{MappedMutexGuard, Mutex}; use rangeset::RangeSet; use std::ops::Range; use termwiz::surface::SequenceNo; @@ -1974,14 +1975,14 @@ mod test { struct FakePane { id: PaneId, - size: RefCell, + size: Mutex, } impl FakePane { - fn new(id: PaneId, size: TerminalSize) -> Rc { - Rc::new(Self { + fn new(id: PaneId, size: TerminalSize) -> Arc { + Arc::new(Self { id, - size: RefCell::new(size), + size: Mutex::new(size), }) } } @@ -2044,11 +2045,11 @@ mod test { fn reader(&self) -> anyhow::Result>> { Ok(None) } - fn writer(&self) -> RefMut { + fn writer(&self) -> MappedMutexGuard { unimplemented!() } fn resize(&self, size: TerminalSize) -> anyhow::Result<()> { - *self.size.borrow_mut() = size; + *self.size.lock() = size; Ok(()) } diff --git a/mux/src/termwiztermtab.rs b/mux/src/termwiztermtab.rs index 32ac5659d..df7255511 100644 --- a/mux/src/termwiztermtab.rs +++ b/mux/src/termwiztermtab.rs @@ -16,9 +16,9 @@ use async_trait::async_trait; use config::keyassignment::ScrollbackEraseMode; use crossbeam::channel::{unbounded as channel, Receiver, Sender}; use filedescriptor::{FileDescriptor, Pipe}; +use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; use portable_pty::*; use rangeset::RangeSet; -use std::cell::{RefCell, RefMut}; use std::io::{BufWriter, Write}; use std::ops::Range; use std::rc::Rc; @@ -53,7 +53,7 @@ impl Domain for TermWizTerminalDomain { _size: TerminalSize, _command: Option, _command_dir: Option, - ) -> anyhow::Result> { + ) -> anyhow::Result> { bail!("cannot spawn panes in a TermWizTerminalPane"); } @@ -84,10 +84,10 @@ impl Domain for TermWizTerminalDomain { pub struct TermWizTerminalPane { pane_id: PaneId, domain_id: DomainId, - terminal: RefCell, + terminal: Mutex, input_tx: Sender, - dead: RefCell, - writer: RefCell>, + dead: Mutex, + writer: Mutex>, render_rx: FileDescriptor, } @@ -101,7 +101,7 @@ impl TermWizTerminalPane { ) -> Self { let pane_id = alloc_pane_id(); - let terminal = RefCell::new(wezterm_term::Terminal::new( + let terminal = Mutex::new(wezterm_term::Terminal::new( size, term_config.unwrap_or_else(|| Arc::new(config::TermConfig::new())), "WezTerm", @@ -113,10 +113,10 @@ impl TermWizTerminalPane { pane_id, domain_id, terminal, - writer: RefCell::new(Vec::new()), + writer: Mutex::new(Vec::new()), render_rx, input_tx, - dead: RefCell::new(false), + dead: Mutex::new(false), } } } @@ -127,11 +127,11 @@ impl Pane for TermWizTerminalPane { } fn get_cursor_position(&self) -> StableCursorPosition { - terminal_get_cursor_position(&mut self.terminal.borrow_mut()) + terminal_get_cursor_position(&mut self.terminal.lock()) } fn get_current_seqno(&self) -> SequenceNo { - self.terminal.borrow().current_seqno() + self.terminal.lock().current_seqno() } fn get_changed_since( @@ -139,7 +139,7 @@ impl Pane for TermWizTerminalPane { lines: Range, seqno: SequenceNo, ) -> RangeSet { - terminal_get_dirty_lines(&mut self.terminal.borrow_mut(), lines, seqno) + terminal_get_dirty_lines(&mut self.terminal.lock(), lines, seqno) } fn for_each_logical_line_in_stable_range_mut( @@ -148,7 +148,7 @@ impl Pane for TermWizTerminalPane { for_line: &mut dyn ForEachPaneLogicalLine, ) { terminal_for_each_logical_line_in_stable_range_mut( - &mut self.terminal.borrow_mut(), + &mut self.terminal.lock(), lines, for_line, ); @@ -159,19 +159,19 @@ impl Pane for TermWizTerminalPane { } fn with_lines_mut(&self, lines: Range, with_lines: &mut dyn WithPaneLines) { - terminal_with_lines_mut(&mut self.terminal.borrow_mut(), lines, with_lines) + terminal_with_lines_mut(&mut self.terminal.lock(), lines, with_lines) } fn get_lines(&self, lines: Range) -> (StableRowIndex, Vec) { - terminal_get_lines(&mut self.terminal.borrow_mut(), lines) + terminal_get_lines(&mut self.terminal.lock(), lines) } fn get_dimensions(&self) -> RenderableDimensions { - terminal_get_dimensions(&mut self.terminal.borrow_mut()) + terminal_get_dimensions(&mut self.terminal.lock()) } fn get_title(&self) -> String { - self.terminal.borrow_mut().get_title().to_string() + self.terminal.lock().get_title().to_string() } fn can_close_without_prompting(&self, _reason: CloseReason) -> bool { @@ -188,8 +188,11 @@ impl Pane for TermWizTerminalPane { Ok(Some(Box::new(self.render_rx.try_clone()?))) } - fn writer(&self) -> RefMut { - self.writer.borrow_mut() + fn writer(&self) -> MappedMutexGuard { + MutexGuard::map(self.writer.lock(), |writer| { + let w: &mut dyn std::io::Write = writer; + w + }) } fn resize(&self, size: TerminalSize) -> anyhow::Result<()> { @@ -198,7 +201,7 @@ impl Pane for TermWizTerminalPane { cols: size.cols as usize, })?; - self.terminal.borrow_mut().resize(size); + self.terminal.lock().resize(size); Ok(()) } @@ -206,7 +209,7 @@ impl Pane for TermWizTerminalPane { fn key_down(&self, key: KeyCode, modifiers: KeyModifiers) -> anyhow::Result<()> { let event = InputEvent::Key(KeyEvent { key, modifiers }); if let Err(e) = self.input_tx.send(event) { - *self.dead.borrow_mut() = true; + *self.dead.lock() = true; return Err(e.into()); } Ok(()) @@ -236,34 +239,34 @@ impl Pane for TermWizTerminalPane { modifiers: event.modifiers, }); if let Err(e) = self.input_tx.send(event) { - *self.dead.borrow_mut() = true; + *self.dead.lock() = true; return Err(e.into()); } Ok(()) } fn set_config(&self, config: Arc) { - self.terminal.borrow_mut().set_config(config); + self.terminal.lock().set_config(config); } fn get_config(&self) -> Option> { - Some(self.terminal.borrow().get_config()) + Some(self.terminal.lock().get_config()) } fn perform_actions(&self, actions: Vec) { - self.terminal.borrow_mut().perform_actions(actions) + self.terminal.lock().perform_actions(actions) } fn kill(&self) { - *self.dead.borrow_mut() = true; + *self.dead.lock() = true; } fn is_dead(&self) -> bool { - *self.dead.borrow() + *self.dead.lock() } fn palette(&self) -> ColorPalette { - self.terminal.borrow().palette() + self.terminal.lock().palette() } fn domain_id(&self) -> DomainId { @@ -271,24 +274,24 @@ impl Pane for TermWizTerminalPane { } fn is_mouse_grabbed(&self) -> bool { - self.terminal.borrow().is_mouse_grabbed() + self.terminal.lock().is_mouse_grabbed() } fn is_alt_screen_active(&self) -> bool { - self.terminal.borrow().is_alt_screen_active() + self.terminal.lock().is_alt_screen_active() } fn get_current_working_dir(&self) -> Option { - self.terminal.borrow().get_current_dir().cloned() + self.terminal.lock().get_current_dir().cloned() } fn erase_scrollback(&self, erase_mode: ScrollbackEraseMode) { match erase_mode { ScrollbackEraseMode::ScrollbackOnly => { - self.terminal.borrow_mut().erase_scrollback(); + self.terminal.lock().erase_scrollback(); } ScrollbackEraseMode::ScrollbackAndViewport => { - self.terminal.borrow_mut().erase_scrollback_and_viewport(); + self.terminal.lock().erase_scrollback_and_viewport(); } } } @@ -435,7 +438,7 @@ impl termwiz::terminal::Terminal for TermWizTerminal { pub fn allocate( size: TerminalSize, config: Arc, -) -> (TermWizTerminal, Rc) { +) -> (TermWizTerminal, Arc) { let render_pipe = Pipe::new().expect("Pipe creation not to fail"); let (input_tx, input_rx) = channel(); @@ -461,7 +464,7 @@ pub fn allocate( let pane = TermWizTerminalPane::new(domain_id, size, input_tx, render_pipe.read, Some(config)); // Add the tab to the mux so that the output is processed - let pane: Rc = Rc::new(pane); + let pane: Arc = Arc::new(pane); let mux = Mux::get().unwrap(); mux.add_pane(&pane).expect("to be able to add pane to mux"); @@ -530,7 +533,7 @@ pub async fn run< let pane = TermWizTerminalPane::new(domain.domain_id(), size, input_tx, render_rx, term_config); - let pane: Rc = Rc::new(pane); + let pane: Arc = Arc::new(pane); let tab = Rc::new(Tab::new(&size)); tab.assign_pane(&pane); diff --git a/mux/src/tmux.rs b/mux/src/tmux.rs index 01d457833..a758da6c7 100644 --- a/mux/src/tmux.rs +++ b/mux/src/tmux.rs @@ -5,12 +5,11 @@ use crate::tmux_commands::{ListAllPanes, TmuxCommand}; use crate::{Mux, MuxWindowBuilder}; use async_trait::async_trait; use filedescriptor::FileDescriptor; +use parking_lot::{Condvar, Mutex}; use portable_pty::CommandBuilder; -use std::cell::RefCell; use std::collections::{HashMap, HashSet, VecDeque}; use std::io::Write; -use std::rc::Rc; -use std::sync::{Arc, Condvar, Mutex}; +use std::sync::Arc; use termwiz::tmux_cc::*; use wezterm_term::TerminalSize; @@ -55,12 +54,12 @@ pub(crate) type TmuxCmdQueue = VecDeque>; pub(crate) struct TmuxDomainState { pub pane_id: PaneId, // ID of the original pane pub domain_id: DomainId, // ID of TmuxDomain - state: RefCell, + state: Mutex, pub cmd_queue: Arc>, - pub gui_window: RefCell>, - pub gui_tabs: RefCell>, - pub remote_panes: RefCell>, - pub tmux_session: RefCell>, + pub gui_window: Mutex>, + pub gui_tabs: Mutex>, + pub remote_panes: Mutex>, + pub tmux_session: Mutex>, } pub struct TmuxDomain { @@ -70,18 +69,18 @@ pub struct TmuxDomain { impl TmuxDomainState { pub fn advance(&self, events: Box>) { for event in events.iter() { - let state = *self.state.borrow(); + let state = *self.state.lock(); log::info!("tmux: {:?} in state {:?}", event, state); match event { Event::Guarded(response) => match state { State::WaitForInitialGuard => { - *self.state.borrow_mut() = State::Idle; + *self.state.lock() = State::Idle; } State::WaitingForResponse => { - let mut cmd_queue = self.cmd_queue.as_ref().lock().unwrap(); + let mut cmd_queue = self.cmd_queue.as_ref().lock(); let cmd = cmd_queue.pop_front().unwrap(); let domain_id = self.domain_id; - *self.state.borrow_mut() = State::Idle; + *self.state.lock() = State::Idle; let resp = response.clone(); promise::spawn::spawn(async move { if let Err(err) = cmd.process_result(domain_id, &resp) { @@ -93,9 +92,9 @@ impl TmuxDomainState { State::Idle => {} }, Event::Output { pane, text } => { - let pane_map = self.remote_panes.borrow_mut(); + let pane_map = self.remote_panes.lock(); if let Some(ref_pane) = pane_map.get(pane) { - let mut tmux_pane = ref_pane.lock().unwrap(); + let mut tmux_pane = ref_pane.lock(); if let Err(err) = tmux_pane.output_write.write_all(text.as_bytes()) { log::error!("Failed to write tmux data to output: {:#}", err); } @@ -107,15 +106,15 @@ impl TmuxDomainState { self.create_gui_window(); } Event::SessionChanged { session, name: _ } => { - *self.tmux_session.borrow_mut() = Some(*session); + *self.tmux_session.lock() = Some(*session); log::info!("tmux session changed:{}", session); } Event::Exit { reason: _ } => { - let mut pane_map = self.remote_panes.borrow_mut(); + let mut pane_map = self.remote_panes.lock(); for (_, v) in pane_map.iter_mut() { - let remote_pane = v.lock().unwrap(); + let remote_pane = v.lock(); let (lock, condvar) = &*remote_pane.active_lock; - let mut released = lock.lock().unwrap(); + let mut released = lock.lock(); *released = true; condvar.notify_all(); } @@ -125,8 +124,8 @@ impl TmuxDomainState { } // send pending commands to tmux - let cmd_queue = self.cmd_queue.as_ref().lock().unwrap(); - if *self.state.borrow() == State::Idle && !cmd_queue.is_empty() { + let cmd_queue = self.cmd_queue.as_ref().lock(); + if *self.state.lock() == State::Idle && !cmd_queue.is_empty() { TmuxDomainState::schedule_send_next_command(self.domain_id); } } @@ -134,10 +133,10 @@ impl TmuxDomainState { /// send next command at the front of cmd_queue. /// must be called inside main thread fn send_next_command(&self) { - if *self.state.borrow() != State::Idle { + if *self.state.lock() != State::Idle { return; } - let cmd_queue = self.cmd_queue.as_ref().lock().unwrap(); + let cmd_queue = self.cmd_queue.as_ref().lock(); if let Some(first) = cmd_queue.front() { let cmd = first.get_command(); log::info!("sending cmd {:?}", cmd); @@ -146,7 +145,7 @@ impl TmuxDomainState { let mut writer = pane.writer(); let _ = write!(writer, "{}", cmd); } - *self.state.borrow_mut() = State::WaitingForResponse; + *self.state.lock() = State::WaitingForResponse; } } @@ -165,12 +164,12 @@ impl TmuxDomainState { /// create a standalone window for tmux tabs pub fn create_gui_window(&self) { - if self.gui_window.borrow().is_none() { + if self.gui_window.lock().is_none() { let mux = Mux::get().expect("should be call at main thread"); let window_builder = mux.new_empty_window(None /* TODO: pass session here */); log::info!("Tmux create window id {}", window_builder.window_id); { - let mut window_id = self.gui_window.borrow_mut(); + let mut window_id = self.gui_window.lock(); *window_id = Some(window_builder); // keep the builder so it won't be purged } }; @@ -180,19 +179,18 @@ impl TmuxDomainState { impl TmuxDomain { pub fn new(pane_id: PaneId) -> Self { let domain_id = alloc_domain_id(); - // let parser = RefCell::new(Parser::new()); let mut cmd_queue = VecDeque::>::new(); cmd_queue.push_back(Box::new(ListAllPanes)); let inner = Arc::new(TmuxDomainState { domain_id, pane_id, // parser, - state: RefCell::new(State::WaitForInitialGuard), + state: Mutex::new(State::WaitForInitialGuard), cmd_queue: Arc::new(Mutex::new(cmd_queue)), - gui_window: RefCell::new(None), - gui_tabs: RefCell::new(Vec::default()), - remote_panes: RefCell::new(HashMap::default()), - tmux_session: RefCell::new(None), + gui_window: Mutex::new(None), + gui_tabs: Mutex::new(Vec::default()), + remote_panes: Mutex::new(HashMap::default()), + tmux_session: Mutex::new(None), }); Self { inner } @@ -210,7 +208,7 @@ impl Domain for TmuxDomain { _size: TerminalSize, _command: Option, _command_dir: Option, - ) -> anyhow::Result> { + ) -> anyhow::Result> { anyhow::bail!("Spawn_pane not yet implemented for TmuxDomain"); } diff --git a/mux/src/tmux_commands.rs b/mux/src/tmux_commands.rs index f81c595b3..3d4c862ea 100644 --- a/mux/src/tmux_commands.rs +++ b/mux/src/tmux_commands.rs @@ -6,12 +6,13 @@ use crate::tmux::{TmuxDomain, TmuxDomainState, TmuxRemotePane, TmuxTab}; use crate::tmux_pty::{TmuxChild, TmuxPty}; use crate::{Mux, Pane}; use anyhow::{anyhow, Context}; +use parking_lot::{Condvar, Mutex}; use portable_pty::{MasterPty, PtySize}; use std::collections::HashSet; use std::fmt::{Debug, Write}; use std::io::Write as _; use std::rc::Rc; -use std::sync::{Arc, Condvar, Mutex}; +use std::sync::Arc; use termwiz::tmux_cc::*; use wezterm_term::TerminalSize; @@ -37,7 +38,7 @@ pub(crate) struct PaneItem { impl TmuxDomainState { /// check if a PaneItem received from ListAllPanes has been attached fn check_pane_attached(&self, target: &PaneItem) -> bool { - let pane_list = self.gui_tabs.borrow(); + let pane_list = self.gui_tabs.lock(); let local_tab = match pane_list .iter() .find(|&x| x.tmux_window_id == target.window_id) @@ -60,7 +61,7 @@ impl TmuxDomainState { /// after we create a tab for a remote pane, save its ID into the /// TmuxPane-TmuxPane tree, so we can ref it later. fn add_attached_pane(&self, target: &PaneItem, tab_id: &TabId) -> anyhow::Result<()> { - let mut pane_list = self.gui_tabs.borrow_mut(); + let mut pane_list = self.gui_tabs.lock(); let local_tab = match pane_list .iter_mut() .find(|x| x.tmux_window_id == target.window_id) @@ -92,7 +93,7 @@ impl TmuxDomainState { // 2) create pane if not exist // 3) fetch scroll buffer if new created // 4) update pane state if exist - let current_session = self.tmux_session.borrow().unwrap_or(0); + let current_session = self.tmux_session.lock().unwrap_or(0); for pane in panes.iter() { if pane.session_id != current_session || self.check_pane_attached(&pane) { continue; @@ -118,7 +119,7 @@ impl TmuxDomainState { })); { - let mut pane_map = self.remote_panes.borrow_mut(); + let mut pane_map = self.remote_panes.lock(); pane_map.insert(pane.pane_id, ref_pane.clone()); } @@ -150,7 +151,7 @@ impl TmuxDomainState { Box::new(writer.clone()), ); - let local_pane: Rc = Rc::new(LocalPane::new( + let local_pane: Arc = Arc::new(LocalPane::new( local_pane_id, terminal, Box::new(child), @@ -164,7 +165,7 @@ impl TmuxDomainState { tab.assign_pane(&local_pane); self.create_gui_window(); - let mut gui_window = self.gui_window.borrow_mut(); + let mut gui_window = self.gui_window.lock(); let gui_window_id = match gui_window.as_mut() { Some(x) => x, None => { @@ -178,7 +179,6 @@ impl TmuxDomainState { self.cmd_queue .lock() - .unwrap() .push_back(Box::new(CapturePane(pane.pane_id))); TmuxDomainState::schedule_send_next_command(self.domain_id); @@ -314,9 +314,9 @@ impl TmuxCommand for CapturePane { // capturep contents returned from guarded lines which always contain a tailing '\n' let unescaped = &unescaped[0..unescaped.len().saturating_sub(1)].replace("\n", "\r\n"); - let pane_map = tmux_domain.inner.remote_panes.borrow(); + let pane_map = tmux_domain.inner.remote_panes.lock(); if let Some(pane) = pane_map.get(&self.0) { - let mut pane = pane.lock().expect("Grant lock of tmux cmd queue failed"); + let mut pane = pane.lock(); pane.output_write .write_all(unescaped.as_bytes()) .context("writing capture pane result to output")?; diff --git a/mux/src/tmux_pty.rs b/mux/src/tmux_pty.rs index c8076db0a..98662d740 100644 --- a/mux/src/tmux_pty.rs +++ b/mux/src/tmux_pty.rs @@ -2,9 +2,10 @@ use crate::tmux::{RefTmuxRemotePane, TmuxCmdQueue, TmuxDomainState}; use crate::tmux_commands::{Resize, SendKeys}; use crate::DomainId; use filedescriptor::FileDescriptor; +use parking_lot::{Condvar, Mutex}; use portable_pty::{Child, ChildKiller, ExitStatus, MasterPty}; use std::io::{Read, Write}; -use std::sync::{Arc, Condvar, Mutex}; +use std::sync::Arc; /// A local tmux pane(tab) based on a tmux pty #[derive(Debug)] @@ -24,11 +25,11 @@ struct TmuxPtyWriter { impl Write for TmuxPtyWriter { fn write(&mut self, buf: &[u8]) -> std::io::Result { let pane_id = { - let pane_lock = self.master_pane.lock().unwrap(); + let pane_lock = self.master_pane.lock(); pane_lock.pane_id }; log::trace!("pane:{}, content:{:?}", &pane_id, buf); - let mut cmd_queue = self.cmd_queue.lock().unwrap(); + let mut cmd_queue = self.cmd_queue.lock(); cmd_queue.push_back(Box::new(SendKeys { pane: pane_id, keys: buf.to_vec(), @@ -45,11 +46,11 @@ impl Write for TmuxPtyWriter { impl Write for TmuxPty { fn write(&mut self, buf: &[u8]) -> std::io::Result { let pane_id = { - let pane_lock = self.master_pane.lock().unwrap(); + let pane_lock = self.master_pane.lock(); pane_lock.pane_id }; log::trace!("pane:{}, content:{:?}", &pane_id, buf); - let mut cmd_queue = self.cmd_queue.lock().unwrap(); + let mut cmd_queue = self.cmd_queue.lock(); cmd_queue.push_back(Box::new(SendKeys { pane: pane_id, keys: buf.to_vec(), @@ -74,10 +75,10 @@ impl Child for TmuxChild { } fn wait(&mut self) -> std::io::Result { - let (lock, var) = &*self.active_lock; - let mut released = lock.lock().unwrap(); + let &(ref lock, ref var) = &*self.active_lock; + let mut released = lock.lock(); while !*released { - released = var.wait(released).unwrap(); + var.wait(&mut released); } return Ok(ExitStatus::with_exit_code(0)); } @@ -123,14 +124,14 @@ impl ChildKiller for TmuxChild { impl MasterPty for TmuxPty { fn resize(&self, size: portable_pty::PtySize) -> Result<(), anyhow::Error> { - let mut cmd_queue = self.cmd_queue.lock().unwrap(); + let mut cmd_queue = self.cmd_queue.lock(); cmd_queue.push_back(Box::new(Resize { size })); TmuxDomainState::schedule_send_next_command(self.domain_id); Ok(()) } fn get_size(&self) -> Result { - let pane = self.master_pane.lock().unwrap(); + let pane = self.master_pane.lock(); Ok(portable_pty::PtySize { rows: pane.pane_height as u16, cols: pane.pane_width as u16, diff --git a/term/src/config.rs b/term/src/config.rs index df20accc7..4519b0edd 100644 --- a/term/src/config.rs +++ b/term/src/config.rs @@ -131,7 +131,7 @@ impl Default for NewlineCanon { /// The configuration can be changed at runtime; provided that the implementation /// increments the generation counter appropriately, the changes will be detected /// and applied at the next appropriate opportunity. -pub trait TerminalConfiguration: std::fmt::Debug { +pub trait TerminalConfiguration: std::fmt::Debug + Send + Sync { /// Returns a generation counter for the active /// configuration. If the implementation may be /// changed at runtime, it must increment the generation diff --git a/term/src/terminal.rs b/term/src/terminal.rs index a9f550bb6..c7f1ebb52 100644 --- a/term/src/terminal.rs +++ b/term/src/terminal.rs @@ -10,7 +10,7 @@ pub enum ClipboardSelection { PrimarySelection, } -pub trait Clipboard { +pub trait Clipboard: Send + Sync { fn set_contents( &self, selection: ClipboardSelection, @@ -28,7 +28,7 @@ impl Clipboard for Box { } } -pub trait DeviceControlHandler { +pub trait DeviceControlHandler: Send + Sync { fn handle_device_control(&mut self, _control: termwiz::escape::DeviceControlMode); } @@ -61,11 +61,11 @@ pub enum Alert { OutputSinceFocusLost, } -pub trait AlertHandler { +pub trait AlertHandler: Send + Sync { fn alert(&mut self, alert: Alert); } -pub trait DownloadHandler { +pub trait DownloadHandler: Send + Sync { fn save_to_downloads(&self, name: Option, data: Vec); } @@ -132,7 +132,7 @@ impl Terminal { /// are answerback responses to a number of escape sequences. pub fn new( size: TerminalSize, - config: Arc, + config: Arc, term_program: &str, term_version: &str, // writing to the writer sends data to input of the pty diff --git a/term/src/terminalstate/keyboard.rs b/term/src/terminalstate/keyboard.rs index 07befa95d..340eedfe7 100644 --- a/term/src/terminalstate/keyboard.rs +++ b/term/src/terminalstate/keyboard.rs @@ -1,5 +1,6 @@ use crate::input::*; use crate::TerminalState; +use std::io::Write; use termwiz::input::{KeyCodeEncodeModes, KeyboardEncoding}; impl TerminalState { diff --git a/term/src/terminalstate/kitty.rs b/term/src/terminalstate/kitty.rs index 2ba7002be..7c5f150cd 100644 --- a/term/src/terminalstate/kitty.rs +++ b/term/src/terminalstate/kitty.rs @@ -6,6 +6,7 @@ use ::image::{ }; use anyhow::Context; use std::collections::{HashMap, HashSet}; +use std::io::Write; use std::sync::Arc; use std::time::Duration; use termwiz::escape::apc::{ diff --git a/term/src/terminalstate/mod.rs b/term/src/terminalstate/mod.rs index faea667bd..475ef2288 100644 --- a/term/src/terminalstate/mod.rs +++ b/term/src/terminalstate/mod.rs @@ -7,6 +7,7 @@ use crate::config::{BidiMode, NewlineCanon}; use log::debug; use num_traits::ToPrimitive; use std::collections::HashMap; +use std::io::{BufWriter, Write}; use std::sync::mpsc::{channel, Sender}; use std::sync::Arc; use terminfo::{Database, Value}; @@ -350,7 +351,7 @@ pub struct TerminalState { term_program: String, term_version: String, - writer: Box, + writer: BufWriter, image_cache: lru::LruCache<[u8; 32], Arc>, sixel_scrolls_right: bool, @@ -498,7 +499,7 @@ impl TerminalState { term_version: &str, writer: Box, ) -> TerminalState { - let writer = Box::new(ThreadedWriter::new(writer)); + let writer = BufWriter::new(ThreadedWriter::new(writer)); let seqno = 1; let screen = ScreenOrAlt::new(size, &config, seqno, config.bidi_mode()); @@ -559,7 +560,7 @@ impl TerminalState { current_dir: None, term_program: term_program.to_string(), term_version: term_version.to_string(), - writer: Box::new(std::io::BufWriter::new(writer)), + writer, image_cache: lru::LruCache::new(16), user_vars: HashMap::new(), kitty_img: Default::default(), diff --git a/term/src/terminalstate/mouse.rs b/term/src/terminalstate/mouse.rs index 0a079efa3..52efd9dd0 100644 --- a/term/src/terminalstate/mouse.rs +++ b/term/src/terminalstate/mouse.rs @@ -2,6 +2,7 @@ use crate::input::*; use crate::terminalstate::MouseEncoding; use crate::TerminalState; use anyhow::bail; +use std::io::Write; impl TerminalState { /// Encode a coordinate value using X10 encoding or Utf8 encoding. diff --git a/term/src/terminalstate/performer.rs b/term/src/terminalstate/performer.rs index 229359a57..19847d0d4 100644 --- a/term/src/terminalstate/performer.rs +++ b/term/src/terminalstate/performer.rs @@ -8,6 +8,7 @@ use log::{debug, error}; use num_traits::FromPrimitive; use ordered_float::NotNan; use std::fmt::Write; +use std::io::Write as _; use std::ops::{Deref, DerefMut}; use termwiz::cell::{grapheme_column_width, Cell, CellAttributes, SemanticType}; use termwiz::escape::csi::{ diff --git a/term/src/test/mod.rs b/term/src/test/mod.rs index 56b441440..1624c1efe 100644 --- a/term/src/test/mod.rs +++ b/term/src/test/mod.rs @@ -9,21 +9,20 @@ mod csi; // mod selection; FIXME: port to render layer use crate::color::ColorPalette; use k9::assert_equal as assert_eq; -use std::cell::RefCell; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use termwiz::escape::csi::{Edit, EraseInDisplay, EraseInLine}; use termwiz::escape::{OneBased, OperatingSystemCommand, CSI}; use termwiz::surface::{CursorShape, CursorVisibility, SequenceNo, SEQ_ZERO}; #[derive(Debug)] struct LocalClip { - clip: RefCell>, + clip: Mutex>, } impl LocalClip { fn new() -> Self { Self { - clip: RefCell::new(None), + clip: Mutex::new(None), } } } @@ -34,7 +33,7 @@ impl Clipboard for LocalClip { _selection: ClipboardSelection, clip: Option, ) -> anyhow::Result<()> { - *self.clip.borrow_mut() = clip; + *self.clip.lock().unwrap() = clip; Ok(()) } } diff --git a/wezterm-client/Cargo.toml b/wezterm-client/Cargo.toml index 3619b44c2..68df7e327 100644 --- a/wezterm-client/Cargo.toml +++ b/wezterm-client/Cargo.toml @@ -27,6 +27,7 @@ mux = { path = "../mux" } # https://github.com/sfackler/rust-openssl/pull/1578 # https://github.com/wez/libssh-rs/blob/main/libssh-rs-sys/Cargo.toml openssl = "=0.10.38" +parking_lot = "0.12" portable-pty = { path = "../pty", features = ["serde_support"]} promise = { path = "../promise" } rangeset = { path = "../rangeset" } diff --git a/wezterm-client/src/domain.rs b/wezterm-client/src/domain.rs index 542da0542..9eabea353 100644 --- a/wezterm-client/src/domain.rs +++ b/wezterm-client/src/domain.rs @@ -460,7 +460,7 @@ impl ClientDomain { // removed it from the mux. Let's add it back, but // with a new id. inner.remove_old_pane_mapping(entry.pane_id); - let pane: Rc = Rc::new(ClientPane::new( + let pane: Arc = Arc::new(ClientPane::new( &inner, entry.tab_id, entry.pane_id, @@ -472,7 +472,7 @@ impl ClientDomain { } } } else { - let pane: Rc = Rc::new(ClientPane::new( + let pane: Arc = Arc::new(ClientPane::new( &inner, entry.tab_id, entry.pane_id, @@ -592,7 +592,7 @@ impl Domain for ClientDomain { _size: TerminalSize, _command: Option, _command_dir: Option, - ) -> anyhow::Result> { + ) -> anyhow::Result> { anyhow::bail!("spawn_pane not implemented for ClientDomain") } @@ -623,7 +623,7 @@ impl Domain for ClientDomain { inner.record_remote_to_local_window_mapping(result.window_id, window); - let pane: Rc = Rc::new(ClientPane::new( + let pane: Arc = Arc::new(ClientPane::new( &inner, result.tab_id, result.pane_id, @@ -648,7 +648,7 @@ impl Domain for ClientDomain { tab_id: TabId, pane_id: PaneId, split_request: SplitRequest, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let inner = self .inner() .ok_or_else(|| anyhow!("domain is not attached"))?; @@ -685,7 +685,7 @@ impl Domain for ClientDomain { }) .await?; - let pane: Rc = Rc::new(ClientPane::new( + let pane: Arc = Arc::new(ClientPane::new( &inner, result.tab_id, result.pane_id, @@ -702,7 +702,7 @@ impl Domain for ClientDomain { None => anyhow::bail!("invalid pane id {}", pane_id), }; - tab.split_and_insert(pane_index, split_request, Rc::clone(&pane)) + tab.split_and_insert(pane_index, split_request, Arc::clone(&pane)) .ok(); mux.add_pane(&pane)?; diff --git a/wezterm-client/src/pane/clientpane.rs b/wezterm-client/src/pane/clientpane.rs index 7e0b49e26..a110e8529 100644 --- a/wezterm-client/src/pane/clientpane.rs +++ b/wezterm-client/src/pane/clientpane.rs @@ -13,12 +13,12 @@ use mux::pane::{ use mux::renderable::{RenderableDimensions, StableCursorPosition}; use mux::tab::TabId; use mux::{Mux, MuxNotification}; +use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; use rangeset::RangeSet; use ratelim::RateLimiter; -use std::cell::{RefCell, RefMut}; +use std::cell::RefCell; use std::collections::{BTreeMap, HashMap}; use std::ops::Range; -use std::rc::Rc; use std::sync::Arc; use termwiz::input::KeyEvent; use termwiz::surface::SequenceNo; @@ -34,14 +34,14 @@ pub struct ClientPane { local_pane_id: PaneId, pub remote_pane_id: PaneId, pub remote_tab_id: TabId, - pub renderable: RefCell, - palette: RefCell, - writer: RefCell, - mouse: Rc>, - clipboard: RefCell>>, - mouse_grabbed: RefCell, - ignore_next_kill: RefCell, - user_vars: RefCell>, + pub renderable: Mutex, + palette: Mutex, + writer: Mutex, + mouse: Arc>, + clipboard: Mutex>>, + mouse_grabbed: Mutex, + ignore_next_kill: Mutex, + user_vars: Mutex>, } impl ClientPane { @@ -58,7 +58,7 @@ impl ClientPane { remote_pane_id, }; - let mouse = Rc::new(RefCell::new(MouseState::new( + let mouse = Arc::new(Mutex::new(MouseState::new( remote_pane_id, client.client.clone(), ))); @@ -96,27 +96,27 @@ impl ClientPane { remote_pane_id, local_pane_id, remote_tab_id, - renderable: RefCell::new(render), - writer: RefCell::new(writer), - palette: RefCell::new(palette), - clipboard: RefCell::new(None), - mouse_grabbed: RefCell::new(false), - ignore_next_kill: RefCell::new(false), - user_vars: RefCell::new(HashMap::new()), + renderable: Mutex::new(render), + writer: Mutex::new(writer), + palette: Mutex::new(palette), + clipboard: Mutex::new(None), + mouse_grabbed: Mutex::new(false), + ignore_next_kill: Mutex::new(false), + user_vars: Mutex::new(HashMap::new()), } } pub async fn process_unilateral(&self, pdu: Pdu) -> anyhow::Result<()> { match pdu { Pdu::GetPaneRenderChangesResponse(mut delta) => { - *self.mouse_grabbed.borrow_mut() = delta.mouse_grabbed; + *self.mouse_grabbed.lock() = delta.mouse_grabbed; let bonus_lines = std::mem::take(&mut delta.bonus_lines); - let client = { Arc::clone(&self.renderable.borrow().inner.borrow().client) }; + let client = { Arc::clone(&self.renderable.lock().inner.borrow().client) }; let bonus_lines = hydrate_lines(client, delta.pane_id, bonus_lines).await; self.renderable - .borrow() + .lock() .inner .borrow_mut() .apply_changes_to_surface(delta, bonus_lines); @@ -125,7 +125,7 @@ impl ClientPane { clipboard, selection, .. - }) => match self.clipboard.borrow().as_ref() { + }) => match self.clipboard.lock().as_ref() { Some(clip) => { log::debug!( "Pdu::SetClipboard pane={} remote={} {:?} {:?}", @@ -141,7 +141,7 @@ impl ClientPane { } }, Pdu::SetPalette(SetPalette { palette, .. }) => { - *self.palette.borrow_mut() = palette; + *self.palette.lock() = palette; let mux = Mux::get().unwrap(); mux.notify(MuxNotification::Alert { pane_id: self.local_pane_id, @@ -152,9 +152,7 @@ impl ClientPane { let mux = Mux::get().unwrap(); match &alert { Alert::SetUserVar { name, value } => { - self.user_vars - .borrow_mut() - .insert(name.clone(), value.clone()); + self.user_vars.lock().insert(name.clone(), value.clone()); } _ => {} } @@ -165,7 +163,7 @@ impl ClientPane { } Pdu::PaneRemoved(PaneRemoved { pane_id }) => { log::trace!("remote pane {} has been removed", pane_id); - self.renderable.borrow().inner.borrow_mut().dead = true; + self.renderable.lock().inner.borrow_mut().dead = true; let mux = Mux::get().unwrap(); mux.prune_dead_windows(); @@ -188,7 +186,7 @@ impl ClientPane { /// from where they left off. /// It isn't perfect. pub fn ignore_next_kill(&self) { - *self.ignore_next_kill.borrow_mut() = true; + *self.ignore_next_kill.lock() = true; } } @@ -199,7 +197,7 @@ impl Pane for ClientPane { } fn get_metadata(&self) -> Value { - let renderable = self.renderable.borrow(); + let renderable = self.renderable.lock(); let inner = renderable.inner.borrow(); let mut map: BTreeMap = BTreeMap::new(); @@ -216,11 +214,11 @@ impl Pane for ClientPane { } fn get_cursor_position(&self) -> StableCursorPosition { - self.renderable.borrow().get_cursor_position() + self.renderable.lock().get_cursor_position() } fn get_dimensions(&self) -> RenderableDimensions { - self.renderable.borrow().get_dimensions() + self.renderable.lock().get_dimensions() } fn with_lines_mut(&self, lines: Range, with_lines: &mut dyn WithPaneLines) { @@ -236,7 +234,7 @@ impl Pane for ClientPane { } fn get_lines(&self, lines: Range) -> (StableRowIndex, Vec) { - self.renderable.borrow().get_lines(lines) + self.renderable.lock().get_lines(lines) } fn get_logical_lines(&self, lines: Range) -> Vec { @@ -244,7 +242,7 @@ impl Pane for ClientPane { } fn get_current_seqno(&self) -> SequenceNo { - self.renderable.borrow().get_current_seqno() + self.renderable.lock().get_current_seqno() } fn get_changed_since( @@ -252,15 +250,15 @@ impl Pane for ClientPane { lines: Range, seqno: SequenceNo, ) -> RangeSet { - self.renderable.borrow().get_changed_since(lines, seqno) + self.renderable.lock().get_changed_since(lines, seqno) } fn set_clipboard(&self, clipboard: &Arc) { - self.clipboard.borrow_mut().replace(Arc::clone(clipboard)); + self.clipboard.lock().replace(Arc::clone(clipboard)); } fn get_title(&self) -> String { - let renderable = self.renderable.borrow(); + let renderable = self.renderable.lock(); let inner = renderable.inner.borrow(); inner.title.clone() } @@ -269,7 +267,7 @@ impl Pane for ClientPane { let client = Arc::clone(&self.client); let remote_pane_id = self.remote_pane_id; self.renderable - .borrow() + .lock() .inner .borrow_mut() .predict_from_paste(text); @@ -285,11 +283,7 @@ impl Pane for ClientPane { .await }) .detach(); - self.renderable - .borrow() - .inner - .borrow_mut() - .update_last_send(); + self.renderable.lock().inner.borrow_mut().update_last_send(); Ok(()) } @@ -297,12 +291,15 @@ impl Pane for ClientPane { Ok(None) } - fn writer(&self) -> RefMut { - self.writer.borrow_mut() + fn writer(&self) -> MappedMutexGuard { + MutexGuard::map(self.writer.lock(), |writer| { + let w: &mut dyn std::io::Write = writer; + w + }) } fn set_zoomed(&self, zoomed: bool) { - let render = self.renderable.borrow(); + let render = self.renderable.lock(); let mut inner = render.inner.borrow_mut(); let client = Arc::clone(&self.client); let remote_pane_id = self.remote_pane_id; @@ -324,7 +321,7 @@ impl Pane for ClientPane { } fn resize(&self, size: TerminalSize) -> anyhow::Result<()> { - let render = self.renderable.borrow(); + let render = self.renderable.lock(); let mut inner = render.inner.borrow_mut(); let cols = size.cols as usize; @@ -381,7 +378,7 @@ impl Pane for ClientPane { fn key_down(&self, key: KeyCode, mods: KeyModifiers) -> anyhow::Result<()> { let input_serial; { - let renderable = self.renderable.borrow(); + let renderable = self.renderable.lock(); let mut inner = renderable.inner.borrow_mut(); inner.input_serial = InputSerial::now(); input_serial = inner.input_serial; @@ -403,11 +400,7 @@ impl Pane for ClientPane { .await }) .detach(); - self.renderable - .borrow() - .inner - .borrow_mut() - .update_last_send(); + self.renderable.lock().inner.borrow_mut().update_last_send(); Ok(()) } @@ -417,7 +410,7 @@ impl Pane for ClientPane { } fn kill(&self) { - let mut ignore = self.ignore_next_kill.borrow_mut(); + let mut ignore = self.ignore_next_kill.lock(); if *ignore { *ignore = false; return; @@ -482,27 +475,23 @@ impl Pane for ClientPane { // status, but killing the pane prevents the server // side from sending us further data. // - self.renderable.borrow().inner.borrow_mut().dead = true; + self.renderable.lock().inner.borrow_mut().dead = true; } fn mouse_event(&self, event: MouseEvent) -> anyhow::Result<()> { - self.mouse.borrow_mut().append(event); - if MouseState::next(Rc::clone(&self.mouse)) { - self.renderable - .borrow() - .inner - .borrow_mut() - .update_last_send(); + self.mouse.lock().append(event); + if MouseState::next(Arc::clone(&self.mouse)) { + self.renderable.lock().inner.borrow_mut().update_last_send(); } Ok(()) } fn is_dead(&self) -> bool { - self.renderable.borrow().inner.borrow().dead + self.renderable.lock().inner.borrow().dead } fn palette(&self) -> ColorPalette { - self.palette.borrow().clone() + self.palette.lock().clone() } fn domain_id(&self) -> DomainId { @@ -510,7 +499,7 @@ impl Pane for ClientPane { } fn is_mouse_grabbed(&self) -> bool { - *self.mouse_grabbed.borrow() + *self.mouse_grabbed.lock() } fn is_alt_screen_active(&self) -> bool { @@ -519,7 +508,7 @@ impl Pane for ClientPane { } fn get_current_working_dir(&self) -> Option { - self.renderable.borrow().inner.borrow().working_dir.clone() + self.renderable.lock().inner.borrow().working_dir.clone() } fn focus_changed(&self, focused: bool) { @@ -555,7 +544,7 @@ impl Pane for ClientPane { } fn copy_user_vars(&self) -> HashMap { - self.user_vars.borrow().clone() + self.user_vars.lock().clone() } } diff --git a/wezterm-client/src/pane/mousestate.rs b/wezterm-client/src/pane/mousestate.rs index e8c5f8648..e4190f071 100644 --- a/wezterm-client/src/pane/mousestate.rs +++ b/wezterm-client/src/pane/mousestate.rs @@ -1,10 +1,10 @@ use crate::client::Client; use codec::*; use mux::tab::TabId; -use std::cell::RefCell; +use parking_lot::Mutex; use std::collections::VecDeque; -use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; use wezterm_term::{MouseButton, MouseEvent, MouseEventKind}; pub struct MouseState { @@ -64,12 +64,12 @@ impl MouseState { } } - pub fn next(state: Rc>) -> bool { - let mut mouse = state.borrow_mut(); + pub fn next(state: Arc>) -> bool { + let mut mouse = state.lock(); if let Some(event) = mouse.pop() { let client = mouse.client.clone(); - let state = Rc::clone(&state); + let state = Arc::clone(&state); mouse.pending.store(true, Ordering::SeqCst); let remote_pane_id = mouse.remote_pane_id; @@ -82,11 +82,11 @@ impl MouseState { .await .ok(); - let mouse = state.borrow_mut(); + let mouse = state.lock(); mouse.pending.store(false, Ordering::SeqCst); drop(mouse); - Self::next(Rc::clone(&state)); + Self::next(Arc::clone(&state)); Ok::<(), anyhow::Error>(()) }) .detach(); diff --git a/wezterm-client/src/pane/renderable.rs b/wezterm-client/src/pane/renderable.rs index abedbac66..9099d2d60 100644 --- a/wezterm-client/src/pane/renderable.rs +++ b/wezterm-client/src/pane/renderable.rs @@ -540,7 +540,7 @@ impl RenderableInner { .get_pane(local_pane_id) .ok_or_else(|| anyhow!("no such tab {}", local_pane_id))?; if let Some(client_tab) = pane.downcast_ref::() { - let renderable = client_tab.renderable.borrow_mut(); + let renderable = client_tab.renderable.lock(); let mut inner = renderable.inner.borrow_mut(); match result { @@ -621,7 +621,7 @@ impl RenderableInner { .get_pane(local_pane_id) .ok_or_else(|| anyhow!("no such tab {}", local_pane_id))?; if let Some(client_tab) = tab.downcast_ref::() { - let renderable = client_tab.renderable.borrow_mut(); + let renderable = client_tab.renderable.lock(); let mut inner = renderable.inner.borrow_mut(); inner.dead = !alive; diff --git a/wezterm-gui/Cargo.toml b/wezterm-gui/Cargo.toml index 3285acc3a..da164ae9d 100644 --- a/wezterm-gui/Cargo.toml +++ b/wezterm-gui/Cargo.toml @@ -67,6 +67,7 @@ mux = { path = "../mux" } mux-lua = { path = "../lua-api-crates/mux" } open = "3.0" ordered-float = "3.0" +parking_lot = "0.12" portable-pty = { path = "../pty", features = ["serde_support"]} promise = { path = "../promise" } pulldown-cmark = "0.9" diff --git a/wezterm-gui/src/overlay/copy.rs b/wezterm-gui/src/overlay/copy.rs index 43ed3371f..ad856d4f4 100644 --- a/wezterm-gui/src/overlay/copy.rs +++ b/wezterm-gui/src/overlay/copy.rs @@ -12,12 +12,11 @@ use mux::pane::{ use mux::renderable::*; use mux::tab::TabId; use ordered_float::NotNan; +use parking_lot::{MappedMutexGuard, Mutex}; use rangeset::RangeSet; -use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::ops::Range; -use std::rc::Rc; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::time::Duration; use termwiz::cell::{Cell, CellAttributes}; use termwiz::color::AnsiColor; @@ -38,8 +37,8 @@ lazy_static::lazy_static! { const SEARCH_CHUNK_SIZE: StableRowIndex = 1000; pub struct CopyOverlay { - delegate: Rc, - render: RefCell, + delegate: Arc, + render: Mutex, } #[derive(Copy, Clone, Debug)] @@ -57,7 +56,7 @@ struct Jump { struct CopyRenderable { cursor: StableCursorPosition, - delegate: Rc, + delegate: Arc, start: Option, selection_mode: SelectionMode, viewport: Option, @@ -109,9 +108,9 @@ pub struct CopyModeParams { impl CopyOverlay { pub fn with_pane( term_window: &TermWindow, - pane: &Rc, + pane: &Arc, params: CopyModeParams, - ) -> anyhow::Result> { + ) -> anyhow::Result> { let mut cursor = pane.get_cursor_position(); cursor.shape = termwiz::surface::CursorShape::SteadyBlock; cursor.visibility = CursorVisibility::Visible; @@ -129,7 +128,7 @@ impl CopyOverlay { let mut render = CopyRenderable { cursor, window, - delegate: Rc::clone(pane), + delegate: Arc::clone(pane), start: None, viewport: term_window.get_viewport(pane.pane_id()), results: vec![], @@ -143,7 +142,6 @@ impl CopyOverlay { pattern: if params.pattern.is_empty() { SAVED_PATTERN .lock() - .unwrap() .get(&tab_id) .map(|p| p.clone()) .unwrap_or(params.pattern) @@ -163,14 +161,14 @@ impl CopyOverlay { render.dirty_results.add(search_row); render.update_search(); - Ok(Rc::new(CopyOverlay { - delegate: Rc::clone(pane), - render: RefCell::new(render), + Ok(Arc::new(CopyOverlay { + delegate: Arc::clone(pane), + render: Mutex::new(render), })) } pub fn get_params(&self) -> CopyModeParams { - let render = self.render.borrow(); + let render = self.render.lock(); CopyModeParams { pattern: render.pattern.clone(), editing_search: render.editing_search, @@ -178,7 +176,7 @@ impl CopyOverlay { } pub fn apply_params(&self, params: CopyModeParams) { - let mut render = self.render.borrow_mut(); + let mut render = self.render.lock(); render.editing_search = params.editing_search; if render.pattern != params.pattern { render.pattern = params.pattern; @@ -189,7 +187,7 @@ impl CopyOverlay { } pub fn viewport_changed(&self, viewport: Option) { - let mut render = self.render.borrow_mut(); + let mut render = self.render.lock(); if render.viewport != viewport { if let Some(last) = render.last_bar_pos.take() { render.dirty_results.add(last); @@ -271,7 +269,7 @@ impl CopyRenderable { let state = term_window.pane_state(pane_id); if let Some(overlay) = state.overlay.as_ref() { if let Some(copy_overlay) = overlay.pane.downcast_ref::() { - let mut r = copy_overlay.render.borrow_mut(); + let mut r = copy_overlay.render.lock(); if cookie == r.typing_cookie { r.update_search(); } @@ -297,7 +295,6 @@ impl CopyRenderable { SAVED_PATTERN .lock() - .unwrap() .insert(self.tab_id, self.pattern.clone()); let bar_pos = self.compute_search_row(); @@ -305,7 +302,7 @@ impl CopyRenderable { self.last_result_seqno = self.delegate.get_current_seqno(); if !self.pattern.is_empty() { - let pane: Rc = self.delegate.clone(); + let pane: Arc = self.delegate.clone(); let window = self.window.clone(); let pattern = self.pattern.clone(); let dims = pane.get_dimensions(); @@ -330,7 +327,7 @@ impl CopyRenderable { let state = term_window.pane_state(pane_id); if let Some(overlay) = state.overlay.as_ref() { if let Some(copy_overlay) = overlay.pane.downcast_ref::() { - let mut r = copy_overlay.render.borrow_mut(); + let mut r = copy_overlay.render.lock(); r.processed_search_chunk(pattern, results.take().unwrap(), range); } } @@ -375,7 +372,7 @@ impl CopyRenderable { } // Search next chunk - let pane: Rc = self.delegate.clone(); + let pane: Arc = self.delegate.clone(); let window = self.window.clone(); let end = range.start; let range = end @@ -397,7 +394,7 @@ impl CopyRenderable { let state = term_window.pane_state(pane_id); if let Some(overlay) = state.overlay.as_ref() { if let Some(copy_overlay) = overlay.pane.downcast_ref::() { - let mut r = copy_overlay.render.borrow_mut(); + let mut r = copy_overlay.render.lock(); r.processed_search_chunk(pattern, results.take().unwrap(), range); } } @@ -1025,7 +1022,7 @@ impl Pane for CopyOverlay { fn send_paste(&self, text: &str) -> anyhow::Result<()> { // paste into the search bar - let mut r = self.render.borrow_mut(); + let mut r = self.render.lock(); r.pattern.push_str(text); r.schedule_update_search(); Ok(()) @@ -1035,7 +1032,7 @@ impl Pane for CopyOverlay { Ok(None) } - fn writer(&self) -> RefMut { + fn writer(&self) -> MappedMutexGuard { self.delegate.writer() } @@ -1048,7 +1045,7 @@ impl Pane for CopyOverlay { } fn key_down(&self, key: KeyCode, mods: KeyModifiers) -> anyhow::Result<()> { - let mut render = self.render.borrow_mut(); + let mut render = self.render.lock(); if let Some(jump) = render.pending_jump.take() { match (key, mods) { (KeyCode::Char(c), KeyModifiers::NONE) @@ -1093,7 +1090,7 @@ impl Pane for CopyOverlay { fn perform_assignment(&self, assignment: &KeyAssignment) -> PerformAssignmentResult { use CopyModeAssignment::*; - let mut render = self.render.borrow_mut(); + let mut render = self.render.lock(); if render.pending_jump.is_some() { // Block key assignments until key_down is called // and resolves the next state @@ -1190,7 +1187,7 @@ impl Pane for CopyOverlay { } fn get_cursor_position(&self) -> StableCursorPosition { - let renderer = self.render.borrow(); + let renderer = self.render.lock(); if renderer.editing_search { // place in the search box StableCursorPosition { @@ -1232,8 +1229,8 @@ impl Pane for CopyOverlay { fn with_lines_mut(&self, lines: Range, with_lines: &mut dyn WithPaneLines) { // Take care to access self.delegate methods here before we get into // calling into its own with_lines_mut to avoid a runtime - // borrow erro! - let mut renderer = self.render.borrow_mut(); + // lock erro! + let mut renderer = self.render.lock(); if self.delegate.get_current_seqno() > renderer.last_result_seqno { renderer.update_search(); } @@ -1351,7 +1348,7 @@ impl Pane for CopyOverlay { } fn get_lines(&self, lines: Range) -> (StableRowIndex, Vec) { - let mut renderer = self.render.borrow_mut(); + let mut renderer = self.render.lock(); if self.delegate.get_current_seqno() > renderer.last_result_seqno { renderer.update_search(); } diff --git a/wezterm-gui/src/overlay/mod.rs b/wezterm-gui/src/overlay/mod.rs index dbffda54f..43af18432 100644 --- a/wezterm-gui/src/overlay/mod.rs +++ b/wezterm-gui/src/overlay/mod.rs @@ -26,7 +26,7 @@ pub fn start_overlay( tab: &Rc, func: F, ) -> ( - Rc, + Arc, Pin>>>, ) where @@ -54,10 +54,10 @@ where pub fn start_overlay_pane( term_window: &TermWindow, - pane: &Rc, + pane: &Arc, func: F, ) -> ( - Rc, + Arc, Pin>>>, ) where diff --git a/wezterm-gui/src/overlay/quickselect.rs b/wezterm-gui/src/overlay/quickselect.rs index 291468dbd..7cee55c13 100644 --- a/wezterm-gui/src/overlay/quickselect.rs +++ b/wezterm-gui/src/overlay/quickselect.rs @@ -7,11 +7,10 @@ use mux::pane::{ ForEachPaneLogicalLine, LogicalLine, Pane, PaneId, Pattern, SearchResult, WithPaneLines, }; use mux::renderable::*; +use parking_lot::{MappedMutexGuard, Mutex}; use rangeset::RangeSet; -use std::cell::{RefCell, RefMut}; use std::collections::HashMap; use std::ops::Range; -use std::rc::Rc; use std::sync::Arc; use termwiz::cell::{Cell, CellAttributes}; use termwiz::color::AnsiColor; @@ -148,8 +147,8 @@ mod alphabet_test { } pub struct QuickSelectOverlay { - renderer: RefCell, - delegate: Rc, + renderer: Mutex, + delegate: Arc, } #[derive(Debug)] @@ -159,7 +158,7 @@ struct MatchResult { } struct QuickSelectRenderable { - delegate: Rc, + delegate: Arc, /// The text that the user entered pattern: Pattern, /// The most recently queried set of matches @@ -186,9 +185,9 @@ struct QuickSelectRenderable { impl QuickSelectOverlay { pub fn with_pane( term_window: &TermWindow, - pane: &Rc, + pane: &Arc, args: &QuickSelectArguments, - ) -> Rc { + ) -> Arc { let viewport = term_window.get_viewport(pane.pane_id()); let dims = pane.get_dimensions(); @@ -228,7 +227,7 @@ impl QuickSelectOverlay { let window = term_window.window.clone().unwrap(); let mut renderer = QuickSelectRenderable { - delegate: Rc::clone(pane), + delegate: Arc::clone(pane), pattern, selection: "".to_string(), results: vec![], @@ -249,14 +248,14 @@ impl QuickSelectOverlay { renderer.dirty_results.add(search_row); renderer.update_search(true); - Rc::new(QuickSelectOverlay { - renderer: RefCell::new(renderer), - delegate: Rc::clone(pane), + Arc::new(QuickSelectOverlay { + renderer: Mutex::new(renderer), + delegate: Arc::clone(pane), }) } pub fn viewport_changed(&self, viewport: Option) { - let mut render = self.renderer.borrow_mut(); + let mut render = self.renderer.lock(); if render.viewport != viewport { if let Some(last) = render.last_bar_pos.take() { render.dirty_results.add(last); @@ -287,7 +286,7 @@ impl Pane for QuickSelectOverlay { Ok(None) } - fn writer(&self) -> RefMut { + fn writer(&self) -> MappedMutexGuard { self.delegate.writer() } @@ -301,12 +300,12 @@ impl Pane for QuickSelectOverlay { fn key_down(&self, key: KeyCode, mods: KeyModifiers) -> anyhow::Result<()> { match (key, mods) { - (KeyCode::Escape, KeyModifiers::NONE) => self.renderer.borrow().close(), + (KeyCode::Escape, KeyModifiers::NONE) => self.renderer.lock().close(), (KeyCode::UpArrow, KeyModifiers::NONE) | (KeyCode::Enter, KeyModifiers::NONE) | (KeyCode::Char('p'), KeyModifiers::CTRL) => { // Move to prior match - let mut r = self.renderer.borrow_mut(); + let mut r = self.renderer.lock(); if let Some(cur) = r.result_pos.as_ref() { let prior = if *cur > 0 { cur - 1 @@ -320,7 +319,7 @@ impl Pane for QuickSelectOverlay { // Skip this page of matches and move up to the first match from // the prior page. let dims = self.delegate.get_dimensions(); - let mut r = self.renderer.borrow_mut(); + let mut r = self.renderer.lock(); if let Some(cur) = r.result_pos { let top = r.viewport.unwrap_or(dims.physical_top); let prior = top - dims.viewport_rows as isize; @@ -339,7 +338,7 @@ impl Pane for QuickSelectOverlay { // Skip this page of matches and move down to the first match from // the next page. let dims = self.delegate.get_dimensions(); - let mut r = self.renderer.borrow_mut(); + let mut r = self.renderer.lock(); if let Some(cur) = r.result_pos { let top = r.viewport.unwrap_or(dims.physical_top); let bottom = top + dims.viewport_rows as isize; @@ -353,7 +352,7 @@ impl Pane for QuickSelectOverlay { } (KeyCode::DownArrow, KeyModifiers::NONE) | (KeyCode::Char('n'), KeyModifiers::CTRL) => { // Move to next match - let mut r = self.renderer.borrow_mut(); + let mut r = self.renderer.lock(); if let Some(cur) = r.result_pos.as_ref() { let next = if *cur + 1 >= r.results.len() { 0 @@ -365,7 +364,7 @@ impl Pane for QuickSelectOverlay { } (KeyCode::Char(c), KeyModifiers::NONE) | (KeyCode::Char(c), KeyModifiers::SHIFT) => { // Type to add to the selection - let mut r = self.renderer.borrow_mut(); + let mut r = self.renderer.lock(); r.selection.push(c); let lowered = r.selection.to_lowercase(); let paste = lowered != r.selection; @@ -376,12 +375,12 @@ impl Pane for QuickSelectOverlay { } (KeyCode::Backspace, KeyModifiers::NONE) => { // Backspace to edit the selection - let mut r = self.renderer.borrow_mut(); + let mut r = self.renderer.lock(); r.selection.pop(); } (KeyCode::Char('u'), KeyModifiers::CTRL) => { // CTRL-u to clear the selection - let mut r = self.renderer.borrow_mut(); + let mut r = self.renderer.lock(); r.selection.clear(); } _ => {} @@ -431,7 +430,7 @@ impl Pane for QuickSelectOverlay { fn get_cursor_position(&self) -> StableCursorPosition { // move to the search box - let renderer = self.renderer.borrow(); + let renderer = self.renderer.lock(); StableCursorPosition { x: 8 + wezterm_term::unicode_column_width(&renderer.selection, None), y: renderer.compute_search_row(), @@ -450,7 +449,7 @@ impl Pane for QuickSelectOverlay { seqno: SequenceNo, ) -> RangeSet { let mut dirty = self.delegate.get_changed_since(lines.clone(), seqno); - dirty.add_set(&self.renderer.borrow().dirty_results); + dirty.add_set(&self.renderer.lock().dirty_results); dirty.intersection_with_range(lines) } @@ -468,7 +467,7 @@ impl Pane for QuickSelectOverlay { } fn with_lines_mut(&self, lines: Range, with_lines: &mut dyn WithPaneLines) { - let mut renderer = self.renderer.borrow_mut(); + let mut renderer = self.renderer.lock(); // Take care to access self.delegate methods here before we get into // calling into its own with_lines_mut to avoid a runtime // borrow erro! @@ -579,7 +578,7 @@ impl Pane for QuickSelectOverlay { } fn get_lines(&self, lines: Range) -> (StableRowIndex, Vec) { - let mut renderer = self.renderer.borrow_mut(); + let mut renderer = self.renderer.lock(); renderer.check_for_resize(); let dims = self.get_dimensions(); @@ -791,7 +790,7 @@ impl QuickSelectRenderable { self.dirty_results.add(bar_pos); if !self.pattern.is_empty() { - let pane: Rc = self.delegate.clone(); + let pane: Arc = self.delegate.clone(); let window = self.window.clone(); let pattern = self.pattern.clone(); let scope = self.args.scope_lines; @@ -814,7 +813,7 @@ impl QuickSelectRenderable { if let Some(search_overlay) = overlay.pane.downcast_ref::() { - let mut r = search_overlay.renderer.borrow_mut(); + let mut r = search_overlay.renderer.lock(); r.results = results.take().unwrap(); r.recompute_results(); let num_results = r.results.len(); diff --git a/wezterm-gui/src/termwindow/clipboard.rs b/wezterm-gui/src/termwindow/clipboard.rs index ac69ab7bb..54e25dddf 100644 --- a/wezterm-gui/src/termwindow/clipboard.rs +++ b/wezterm-gui/src/termwindow/clipboard.rs @@ -3,7 +3,7 @@ use crate::TermWindow; use config::keyassignment::{ClipboardCopyDestination, ClipboardPasteSource}; use mux::pane::Pane; use mux::Mux; -use std::rc::Rc; +use std::sync::Arc; use window::{Clipboard, WindowOps}; impl TermWindow { @@ -23,7 +23,7 @@ impl TermWindow { } } - pub fn paste_from_clipboard(&mut self, pane: &Rc, clipboard: ClipboardPasteSource) { + pub fn paste_from_clipboard(&mut self, pane: &Arc, clipboard: ClipboardPasteSource) { let pane_id = pane.pane_id(); log::trace!( "paste_from_clipboard in pane {} {:?}", diff --git a/wezterm-gui/src/termwindow/keyevent.rs b/wezterm-gui/src/termwindow/keyevent.rs index 702c024ef..c17f3e9d4 100644 --- a/wezterm-gui/src/termwindow/keyevent.rs +++ b/wezterm-gui/src/termwindow/keyevent.rs @@ -4,7 +4,7 @@ use anyhow::Context; use config::keyassignment::{KeyAssignment, KeyTableEntry}; use mux::pane::{Pane, PerformAssignmentResult}; use smol::Timer; -use std::rc::Rc; +use std::sync::Arc; use std::time::{Duration, Instant}; use termwiz::input::KeyboardEncoding; @@ -218,7 +218,7 @@ enum OnlyKeyBindings { } impl super::TermWindow { - fn encode_win32_input(&self, pane: &Rc, key: &KeyEvent) -> Option { + fn encode_win32_input(&self, pane: &Arc, key: &KeyEvent) -> Option { if !self.config.allow_win32_input_mode || pane.get_keyboard_encoding() != KeyboardEncoding::Win32 { @@ -229,7 +229,7 @@ impl super::TermWindow { fn lookup_key( &mut self, - pane: &Rc, + pane: &Arc, keycode: &KeyCode, mods: Modifiers, only_key_bindings: OnlyKeyBindings, @@ -257,7 +257,7 @@ impl super::TermWindow { fn process_key( &mut self, - pane: &Rc, + pane: &Arc, context: &dyn WindowOps, keycode: &KeyCode, raw_modifiers: Modifiers, diff --git a/wezterm-gui/src/termwindow/mod.rs b/wezterm-gui/src/termwindow/mod.rs index 44955c018..9463024fa 100644 --- a/wezterm-gui/src/termwindow/mod.rs +++ b/wezterm-gui/src/termwindow/mod.rs @@ -176,7 +176,7 @@ pub struct SemanticZoneCache { } pub struct OverlayState { - pub pane: Rc, + pub pane: Arc, key_table_state: KeyTableState, } @@ -1466,7 +1466,7 @@ impl TermWindow { } } - fn check_for_dirty_lines_and_invalidate_selection(&mut self, pane: &Rc) { + fn check_for_dirty_lines_and_invalidate_selection(&mut self, pane: &Arc) { let dims = pane.get_dimensions(); let viewport = self .get_viewport(pane.pane_id()) @@ -2095,7 +2095,7 @@ impl TermWindow { } /// Returns the Prompt semantic zones - fn get_semantic_prompt_zones(&mut self, pane: &Rc) -> &[StableRowIndex] { + fn get_semantic_prompt_zones(&mut self, pane: &Arc) -> &[StableRowIndex] { let mut cache = self .semantic_zones .entry(pane.pane_id()) @@ -2222,7 +2222,7 @@ impl TermWindow { pub fn perform_key_assignment( &mut self, - pane: &Rc, + pane: &Arc, assignment: &KeyAssignment, ) -> anyhow::Result { use KeyAssignment::*; @@ -2764,7 +2764,7 @@ impl TermWindow { Ok(PerformAssignmentResult::Handled) } - fn do_open_link_at_mouse_cursor(&self, pane: &Rc) { + fn do_open_link_at_mouse_cursor(&self, pane: &Arc) { // They clicked on a link, so let's open it! // We need to ensure that we spawn the `open` call outside of the context // of our window loop; on Windows it can cause a panic due to @@ -2967,22 +2967,22 @@ impl TermWindow { self.window.as_ref().unwrap().invalidate(); } - fn maybe_scroll_to_bottom_for_input(&mut self, pane: &Rc) { + fn maybe_scroll_to_bottom_for_input(&mut self, pane: &Arc) { if self.config.scroll_to_bottom_on_input { self.scroll_to_bottom(pane); } } - fn scroll_to_top(&mut self, pane: &Rc) { + fn scroll_to_top(&mut self, pane: &Arc) { let dims = pane.get_dimensions(); self.set_viewport(pane.pane_id(), Some(dims.scrollback_top), dims); } - fn scroll_to_bottom(&mut self, pane: &Rc) { + fn scroll_to_bottom(&mut self, pane: &Arc) { self.pane_state(pane.pane_id()).viewport = None; } - fn get_active_pane_no_overlay(&self) -> Option> { + fn get_active_pane_no_overlay(&self) -> Option> { let mux = Mux::get().unwrap(); mux.get_active_tab_for_window(self.mux_window_id) .and_then(|tab| tab.get_active_pane()) @@ -2994,7 +2994,7 @@ impl TermWindow { /// then that will be returned instead. Otherwise, if the pane has /// an active overlay (such as search or copy mode) then that will /// be returned. - pub fn get_active_pane_or_overlay(&self) -> Option> { + pub fn get_active_pane_or_overlay(&self) -> Option> { let mux = Mux::get().unwrap(); let tab = match mux.get_active_tab_for_window(self.mux_window_id) { Some(tab) => tab, @@ -3116,7 +3116,7 @@ impl TermWindow { let mut panes = tab.iter_panes(); for p in &mut panes { if let Some(overlay) = self.pane_state(p.pane.pane_id()).overlay.as_ref() { - p.pane = Rc::clone(&overlay.pane); + p.pane = Arc::clone(&overlay.pane); } } panes @@ -3177,7 +3177,7 @@ impl TermWindow { window.notify(TermWindowNotif::CancelOverlayForPane(pane_id)); } - pub fn assign_overlay_for_pane(&mut self, pane_id: PaneId, pane: Rc) { + pub fn assign_overlay_for_pane(&mut self, pane_id: PaneId, pane: Arc) { self.cancel_overlay_for_pane(pane_id); self.pane_state(pane_id).overlay.replace(OverlayState { pane, @@ -3186,7 +3186,7 @@ impl TermWindow { self.update_title(); } - pub fn assign_overlay(&mut self, tab_id: TabId, overlay: Rc) { + pub fn assign_overlay(&mut self, tab_id: TabId, overlay: Arc) { self.cancel_overlay_for_tab(tab_id, None); self.tab_state(tab_id).overlay.replace(OverlayState { pane: overlay, @@ -3195,7 +3195,7 @@ impl TermWindow { self.update_title(); } - fn resolve_search_pattern(&self, pattern: Pattern, pane: &Rc) -> MuxPattern { + fn resolve_search_pattern(&self, pattern: Pattern, pane: &Arc) -> MuxPattern { match pattern { Pattern::CaseSensitiveString(s) => MuxPattern::CaseSensitiveString(s), Pattern::CaseInSensitiveString(s) => MuxPattern::CaseInSensitiveString(s), diff --git a/wezterm-gui/src/termwindow/mouseevent.rs b/wezterm-gui/src/termwindow/mouseevent.rs index ccdbbfda1..2225f08e5 100644 --- a/wezterm-gui/src/termwindow/mouseevent.rs +++ b/wezterm-gui/src/termwindow/mouseevent.rs @@ -12,7 +12,6 @@ use mux::tab::SplitDirection; use mux::Mux; use std::convert::TryInto; use std::ops::Sub; -use std::rc::Rc; use std::sync::Arc; use std::time::Duration; use termwiz::hyperlink::Hyperlink; @@ -347,7 +346,7 @@ impl super::TermWindow { fn mouse_event_ui_item( &mut self, item: UIItem, - pane: Rc, + pane: Arc, _y: i64, event: MouseEvent, context: &dyn WindowOps, @@ -453,7 +452,7 @@ impl super::TermWindow { pub fn mouse_event_above_scroll_thumb( &mut self, _item: UIItem, - pane: Rc, + pane: Arc, event: MouseEvent, context: &dyn WindowOps, ) { @@ -478,7 +477,7 @@ impl super::TermWindow { pub fn mouse_event_below_scroll_thumb( &mut self, _item: UIItem, - pane: Rc, + pane: Arc, event: MouseEvent, context: &dyn WindowOps, ) { @@ -503,7 +502,7 @@ impl super::TermWindow { pub fn mouse_event_scroll_thumb( &mut self, item: UIItem, - _pane: Rc, + _pane: Arc, event: MouseEvent, context: &dyn WindowOps, ) { @@ -534,7 +533,7 @@ impl super::TermWindow { fn mouse_event_terminal( &mut self, - mut pane: Rc, + mut pane: Arc, position: ClickPosition, event: MouseEvent, context: &dyn WindowOps, @@ -569,7 +568,7 @@ impl super::TermWindow { mux.get_active_tab_for_window(self.mux_window_id) .map(|tab| tab.set_active_idx(pos.index)); - pane = Rc::clone(&pos.pane); + pane = Arc::clone(&pos.pane); is_click_to_focus_pane = true; } WMEK::Move => { @@ -578,7 +577,7 @@ impl super::TermWindow { mux.get_active_tab_for_window(self.mux_window_id) .map(|tab| tab.set_active_idx(pos.index)); - pane = Rc::clone(&pos.pane); + pane = Arc::clone(&pos.pane); context.invalidate(); } } @@ -586,7 +585,7 @@ impl super::TermWindow { WMEK::VertWheel(_) => { // Let wheel events route to the hovered pane, // even if it doesn't have focus - pane = Rc::clone(&pos.pane); + pane = Arc::clone(&pos.pane); context.invalidate(); } } diff --git a/wezterm-gui/src/termwindow/render.rs b/wezterm-gui/src/termwindow/render.rs index c31677d5f..3357e2281 100644 --- a/wezterm-gui/src/termwindow/render.rs +++ b/wezterm-gui/src/termwindow/render.rs @@ -244,7 +244,7 @@ pub struct RenderScreenLineOpenGLParams<'a> { pub palette: &'a ColorPalette, pub dims: &'a RenderableDimensions, pub config: &'a ConfigHandle, - pub pane: Option<&'a Rc>, + pub pane: Option<&'a Arc>, pub white_space: TextureRect, pub filled_box: TextureRect, @@ -299,7 +299,7 @@ pub struct ComputeCellFgBgParams<'a> { pub cursor_bg: LinearRgba, pub cursor_is_default_color: bool, pub cursor_border_color: LinearRgba, - pub pane: Option<&'a Rc>, + pub pane: Option<&'a Arc>, } #[derive(Debug)] @@ -461,7 +461,7 @@ impl super::TermWindow { fn get_intensity_if_bell_target_ringing( &self, - pane: &Rc, + pane: &Arc, config: &ConfigHandle, target: VisualBellTarget, ) -> Option { @@ -2183,7 +2183,7 @@ impl super::TermWindow { &mut self, layers: &mut TripleLayerQuadAllocator, split: &PositionedSplit, - pane: &Rc, + pane: &Arc, ) -> anyhow::Result<()> { let palette = pane.palette(); let foreground = palette.split.to_linear(); diff --git a/wezterm-gui/src/termwindow/selection.rs b/wezterm-gui/src/termwindow/selection.rs index 29988cba3..734dc8759 100644 --- a/wezterm-gui/src/termwindow/selection.rs +++ b/wezterm-gui/src/termwindow/selection.rs @@ -2,7 +2,7 @@ use crate::selection::{Selection, SelectionCoordinate, SelectionMode, SelectionR use ::window::WindowOps; use mux::pane::{Pane, PaneId}; use std::cell::RefMut; -use std::rc::Rc; +use std::sync::Arc; use termwiz::surface::Line; use wezterm_term::StableRowIndex; @@ -12,7 +12,7 @@ impl super::TermWindow { } /// Returns the selection region as a series of Line - pub fn selection_lines(&self, pane: &Rc) -> Vec { + pub fn selection_lines(&self, pane: &Arc) -> Vec { let mut result = vec![]; let rectangular = self.selection(pane.pane_id()).rectangular; @@ -63,7 +63,7 @@ impl super::TermWindow { } /// Returns the selection text only - pub fn selection_text(&self, pane: &Rc) -> String { + pub fn selection_text(&self, pane: &Arc) -> String { let mut s = String::new(); let rectangular = self.selection(pane.pane_id()).rectangular; if let Some(sel) = self @@ -109,14 +109,14 @@ impl super::TermWindow { s } - pub fn clear_selection(&mut self, pane: &Rc) { + pub fn clear_selection(&mut self, pane: &Arc) { let mut selection = self.selection(pane.pane_id()); selection.clear(); selection.seqno = pane.get_current_seqno(); self.window.as_ref().unwrap().invalidate(); } - pub fn extend_selection_at_mouse_cursor(&mut self, mode: SelectionMode, pane: &Rc) { + pub fn extend_selection_at_mouse_cursor(&mut self, mode: SelectionMode, pane: &Arc) { self.selection(pane.pane_id()).seqno = pane.get_current_seqno(); let (position, y) = match self.pane_state(pane.pane_id()).mouse_terminal_coords { Some(coords) => coords, @@ -240,7 +240,7 @@ impl super::TermWindow { self.window.as_ref().unwrap().invalidate(); } - pub fn select_text_at_mouse_cursor(&mut self, mode: SelectionMode, pane: &Rc) { + pub fn select_text_at_mouse_cursor(&mut self, mode: SelectionMode, pane: &Arc) { let (x, y) = match self.pane_state(pane.pane_id()).mouse_terminal_coords { Some(coords) => (coords.0.column, coords.1), None => return, diff --git a/wezterm-mux-server-impl/src/sessionhandler.rs b/wezterm-mux-server-impl/src/sessionhandler.rs index d09ed2ba4..57c8cf279 100644 --- a/wezterm-mux-server-impl/src/sessionhandler.rs +++ b/wezterm-mux-server-impl/src/sessionhandler.rs @@ -9,7 +9,6 @@ use mux::tab::TabId; use mux::Mux; use promise::spawn::spawn_into_main_thread; use std::collections::HashMap; -use std::rc::Rc; use std::sync::{Arc, Mutex}; use std::time::Instant; use termwiz::surface::SequenceNo; @@ -51,7 +50,7 @@ pub(crate) struct PerPane { impl PerPane { fn compute_changes( &mut self, - pane: &Rc, + pane: &Arc, force_with_input_serial: Option, ) -> Option { let mut changed = false; @@ -139,7 +138,7 @@ impl PerPane { } fn maybe_push_pane_changes( - pane: &Rc, + pane: &Arc, sender: PduSender, per_pane: Arc>, ) -> anyhow::Result<()> {