1
1
mirror of https://github.com/wez/wezterm.git synced 2025-01-03 11:11:43 +03:00

clipboard: restructure how we capture OSC 52

Previously, we'd create a clipboard handler associated with a GUI window
and take care to pass that down to the underlying Pane whenever we
spawned a new pane.

For the mux server, instead of being associated with a GUI window, the
clipboard was a special RemoteClipboard that would send a PDU through
to the client that spawned the window.

The bug here was that when that client went away, the clipboard for
that window was broken.

If the mux server was the built-in mux in a gui process this could
leave a tab without working OSC 52 clipboard support.

This commit restructures things so that the Mux is responsible for
assigning a clipboard handler that rephrases the clipboard event
as a MuxNotification.

Both the GUI frontend and the mux server dispatcher already listen
for mux notifications and translate those events into appropriate
operations on the system clipboard or Pdus to send to the client(s).

refs: #1790
This commit is contained in:
Wez Furlong 2022-03-31 09:51:06 -07:00
parent 34090580a0
commit 210999b915
10 changed files with 106 additions and 169 deletions

View File

@ -405,7 +405,7 @@ macro_rules! pdu {
/// The overall version of the codec. /// The overall version of the codec.
/// This must be bumped when backwards incompatible changes /// This must be bumped when backwards incompatible changes
/// are made to the types and protocol. /// are made to the types and protocol.
pub const CODEC_VERSION: usize = 20; pub const CODEC_VERSION: usize = 21;
// Defines the Pdu enum. // Defines the Pdu enum.
// Each struct has an explicit identifying number. // Each struct has an explicit identifying number.

View File

@ -40,6 +40,7 @@ As features stabilize some brief notes about them will accumulate here.
* `CloseCurrentPane{confirm=false}` would leave behind a phantom tab/pane when used with the multiplexer. [#1277](https://github.com/wez/wezterm/issues/1277) * `CloseCurrentPane{confirm=false}` would leave behind a phantom tab/pane when used with the multiplexer. [#1277](https://github.com/wez/wezterm/issues/1277)
* `CloseCurrentPane{confirm=true}` artifacts when used with the multiplexer. [#783](https://github.com/wez/wezterm/issues/783) * `CloseCurrentPane{confirm=true}` artifacts when used with the multiplexer. [#783](https://github.com/wez/wezterm/issues/783)
* Scrollbar thumb could jump around/move out of bounds. Thanks to [@davidrios](https://github.com/davidrios)! [#1525](https://github.com/wez/wezterm/issues/1525) * Scrollbar thumb could jump around/move out of bounds. Thanks to [@davidrios](https://github.com/davidrios)! [#1525](https://github.com/wez/wezterm/issues/1525)
* OSC 52 could stop working for tabs/panes spawned into the GUI via the CLI. [#1790](https://github.com/wez/wezterm/issues/1790)
### 20220319-142410-0fcdea07 ### 20220319-142410-0fcdea07

View File

@ -24,6 +24,7 @@ use std::time::Instant;
use termwiz::escape::csi::{DecPrivateMode, DecPrivateModeCode, Device, Mode}; use termwiz::escape::csi::{DecPrivateMode, DecPrivateModeCode, Device, Mode};
use termwiz::escape::{Action, CSI}; use termwiz::escape::{Action, CSI};
use thiserror::*; use thiserror::*;
use wezterm_term::{Clipboard, ClipboardSelection};
#[cfg(windows)] #[cfg(windows)]
use winapi::um::winsock2::{SOL_SOCKET, SO_RCVBUF, SO_SNDBUF}; use winapi::um::winsock2::{SOL_SOCKET, SO_RCVBUF, SO_SNDBUF};
@ -61,6 +62,11 @@ pub enum MuxNotification {
alert: wezterm_term::Alert, alert: wezterm_term::Alert,
}, },
Empty, Empty,
AssignClipboard {
pane_id: PaneId,
selection: ClipboardSelection,
clipboard: Option<String>,
},
} }
static SUB_ID: AtomicUsize = AtomicUsize::new(0); static SUB_ID: AtomicUsize = AtomicUsize::new(0);
@ -566,6 +572,11 @@ impl Mux {
return Ok(()); return Ok(());
} }
let clipboard: Arc<dyn Clipboard> = Arc::new(MuxClipboard {
pane_id: pane.pane_id(),
});
pane.set_clipboard(&clipboard);
self.panes self.panes
.borrow_mut() .borrow_mut()
.insert(pane.pane_id(), Rc::clone(pane)); .insert(pane.pane_id(), Rc::clone(pane));
@ -1067,3 +1078,24 @@ pub(crate) fn pty_size_to_terminal_size(size: portable_pty::PtySize) -> wezterm_
pixel_height: size.pixel_height as usize, pixel_height: size.pixel_height as usize,
} }
} }
struct MuxClipboard {
pane_id: PaneId,
}
impl Clipboard for MuxClipboard {
fn set_contents(
&self,
selection: ClipboardSelection,
clipboard: Option<String>,
) -> anyhow::Result<()> {
let mux =
Mux::get().ok_or_else(|| anyhow::anyhow!("MuxClipboard::set_contents: no Mux?"))?;
mux.notify(MuxNotification::AssignClipboard {
pane_id: self.pane_id,
selection,
clipboard,
});
Ok(())
}
}

View File

@ -1,8 +1,6 @@
use crate::pane::CloseReason; use crate::pane::CloseReason;
use crate::{Mux, MuxNotification, Tab, TabId}; use crate::{Mux, MuxNotification, Tab, TabId};
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use wezterm_term::Clipboard;
static WIN_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0); static WIN_ID: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::AtomicUsize::new(0);
pub type WindowId = usize; pub type WindowId = usize;
@ -12,7 +10,6 @@ pub struct Window {
tabs: Vec<Rc<Tab>>, tabs: Vec<Rc<Tab>>,
active: usize, active: usize,
last_active: Option<TabId>, last_active: Option<TabId>,
clipboard: Option<Arc<dyn Clipboard>>,
workspace: String, workspace: String,
} }
@ -23,7 +20,6 @@ impl Window {
tabs: vec![], tabs: vec![],
active: 0, active: 0,
last_active: None, last_active: None,
clipboard: None,
workspace: workspace.unwrap_or_else(|| { workspace: workspace.unwrap_or_else(|| {
Mux::get() Mux::get()
.expect("Window::new to be called on mux thread") .expect("Window::new to be called on mux thread")
@ -46,10 +42,6 @@ impl Window {
} }
} }
pub fn set_clipboard(&mut self, clipboard: &Arc<dyn Clipboard>) {
self.clipboard.replace(Arc::clone(clipboard));
}
pub fn window_id(&self) -> WindowId { pub fn window_id(&self) -> WindowId {
self.id self.id
} }
@ -60,14 +52,6 @@ impl Window {
} }
} }
fn assign_clipboard_to_tab(&self, tab: &Rc<Tab>) {
if let Some(clip) = self.clipboard.as_ref() {
if let Some(pane) = tab.get_active_pane() {
pane.set_clipboard(clip);
}
}
}
fn invalidate(&self) { fn invalidate(&self) {
let mux = Mux::get().unwrap(); let mux = Mux::get().unwrap();
mux.notify(MuxNotification::WindowInvalidated(self.id)); mux.notify(MuxNotification::WindowInvalidated(self.id));
@ -75,14 +59,12 @@ impl Window {
pub fn insert(&mut self, index: usize, tab: &Rc<Tab>) { pub fn insert(&mut self, index: usize, tab: &Rc<Tab>) {
self.check_that_tab_isnt_already_in_window(tab); self.check_that_tab_isnt_already_in_window(tab);
self.assign_clipboard_to_tab(tab);
self.tabs.insert(index, Rc::clone(tab)); self.tabs.insert(index, Rc::clone(tab));
self.invalidate(); self.invalidate();
} }
pub fn push(&mut self, tab: &Rc<Tab>) { pub fn push(&mut self, tab: &Rc<Tab>) {
self.check_that_tab_isnt_already_in_window(tab); self.check_that_tab_isnt_already_in_window(tab);
self.assign_clipboard_to_tab(tab);
self.tabs.push(Rc::clone(tab)); self.tabs.push(Rc::clone(tab));
self.invalidate(); self.invalidate();
} }

View File

@ -10,7 +10,7 @@ use std::cell::RefCell;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use wezterm_term::Alert; use wezterm_term::{Alert, ClipboardSelection};
use wezterm_toast_notification::*; use wezterm_toast_notification::*;
pub struct GuiFrontEnd { pub struct GuiFrontEnd {
@ -41,7 +41,7 @@ impl GuiFrontEnd {
}); });
let fe = Rc::downgrade(&front_end); let fe = Rc::downgrade(&front_end);
mux.subscribe(move |n| { mux.subscribe(move |n| {
if let Some(_fe) = fe.upgrade() { if let Some(fe) = fe.upgrade() {
match n { match n {
MuxNotification::WindowWorkspaceChanged(_) MuxNotification::WindowWorkspaceChanged(_)
| MuxNotification::ActiveWorkspaceChanged(_) => {} | MuxNotification::ActiveWorkspaceChanged(_) => {}
@ -94,6 +94,31 @@ impl GuiFrontEnd {
Connection::get().unwrap().terminate_message_loop(); Connection::get().unwrap().terminate_message_loop();
} }
} }
MuxNotification::AssignClipboard {
pane_id,
selection,
clipboard,
} => {
log::trace!(
"set clipboard in pane {} {:?} {:?}",
pane_id,
selection,
clipboard
);
if let Some(window) = fe.known_windows.borrow().keys().next() {
window.set_clipboard(
match selection {
ClipboardSelection::Clipboard => Clipboard::Clipboard,
ClipboardSelection::PrimarySelection => {
Clipboard::PrimarySelection
}
},
clipboard.unwrap_or_else(String::new),
);
} else {
log::error!("Cannot assign clipboard as there are no windows");
}
}
} }
true true
} else { } else {

View File

@ -6,50 +6,20 @@ use mux::window::WindowId as MuxWindowId;
use mux::Mux; use mux::Mux;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use wezterm_term::ClipboardSelection; use window::{Clipboard, WindowOps};
use window::{Clipboard, Window, WindowOps};
/// ClipboardHelper bridges between the window crate clipboard
/// manipulation and the term crate clipboard interface
#[derive(Clone)]
pub struct ClipboardHelper {
pub window: Window,
}
impl wezterm_term::Clipboard for ClipboardHelper {
fn set_contents(
&self,
selection: ClipboardSelection,
data: Option<String>,
) -> anyhow::Result<()> {
self.window.set_clipboard(
match selection {
ClipboardSelection::Clipboard => Clipboard::Clipboard,
ClipboardSelection::PrimarySelection => Clipboard::PrimarySelection,
},
data.unwrap_or_else(String::new),
);
Ok(())
}
}
impl TermWindow { impl TermWindow {
pub fn setup_clipboard(window: &Window, mux_window_id: MuxWindowId) -> anyhow::Result<()> { pub fn setup_clipboard(mux_window_id: MuxWindowId) -> anyhow::Result<()> {
let clipboard: Arc<dyn wezterm_term::Clipboard> = Arc::new(ClipboardHelper {
window: window.clone(),
});
let downloader: Arc<dyn wezterm_term::DownloadHandler> = let downloader: Arc<dyn wezterm_term::DownloadHandler> =
Arc::new(crate::download::Downloader::new()); Arc::new(crate::download::Downloader::new());
let mux = Mux::get().unwrap(); let mux = Mux::get().unwrap();
let mut mux_window = mux let mux_window = mux
.get_window_mut(mux_window_id) .get_window(mux_window_id)
.ok_or_else(|| anyhow::anyhow!("mux doesn't know about window yet!?"))?; .ok_or_else(|| anyhow::anyhow!("mux doesn't know about window yet!?"))?;
mux_window.set_clipboard(&clipboard);
for tab in mux_window.iter() { for tab in mux_window.iter() {
for pos in tab.iter_panes() { for pos in tab.iter_panes() {
pos.pane.set_clipboard(&clipboard);
pos.pane.set_download_handler(&downloader); pos.pane.set_download_handler(&downloader);
} }
} }
@ -75,6 +45,11 @@ impl TermWindow {
pub fn paste_from_clipboard(&mut self, pane: &Rc<dyn Pane>, clipboard: ClipboardPasteSource) { pub fn paste_from_clipboard(&mut self, pane: &Rc<dyn Pane>, clipboard: ClipboardPasteSource) {
let pane_id = pane.pane_id(); let pane_id = pane.pane_id();
log::trace!(
"paste_from_clipboard in pane {} {:?}",
pane.pane_id(),
clipboard
);
let window = self.window.as_ref().unwrap().clone(); let window = self.window.as_ref().unwrap().clone();
let clipboard = match clipboard { let clipboard = match clipboard {
ClipboardPasteSource::Clipboard => Clipboard::Clipboard, ClipboardPasteSource::Clipboard => Clipboard::Clipboard,

View File

@ -60,7 +60,6 @@ mod render;
pub mod resize; pub mod resize;
mod selection; mod selection;
pub mod spawn; pub mod spawn;
use clipboard::ClipboardHelper;
use prevcursor::PrevCursorPos; use prevcursor::PrevCursorPos;
use spawn::SpawnWhere; use spawn::SpawnWhere;
@ -798,7 +797,7 @@ impl TermWindow {
tw.borrow_mut().window.replace(window.clone()); tw.borrow_mut().window.replace(window.clone());
Self::apply_icon(&window)?; Self::apply_icon(&window)?;
Self::setup_clipboard(&window, mux_window_id)?; Self::setup_clipboard(mux_window_id)?;
let config_subscription = config::subscribe_to_config_reload({ let config_subscription = config::subscribe_to_config_reload({
let window = window.clone(); let window = window.clone();
@ -1029,6 +1028,9 @@ impl TermWindow {
MuxNotification::WindowRemoved(_window_id) => { MuxNotification::WindowRemoved(_window_id) => {
// Handled by frontend // Handled by frontend
} }
MuxNotification::AssignClipboard { .. } => {
// Handled by frontend
}
MuxNotification::PaneAdded(_) MuxNotification::PaneAdded(_)
| MuxNotification::PaneRemoved(_) | MuxNotification::PaneRemoved(_)
| MuxNotification::WindowWorkspaceChanged(_) | MuxNotification::WindowWorkspaceChanged(_)
@ -1153,12 +1155,6 @@ impl TermWindow {
for tab in mux_window.iter() { for tab in mux_window.iter() {
for pos in tab.iter_panes() { for pos in tab.iter_panes() {
if pos.pane.pane_id() == pane_id { if pos.pane.pane_id() == pane_id {
let clipboard: Arc<dyn wezterm_term::Clipboard> =
Arc::new(ClipboardHelper {
window: window.clone(),
});
pos.pane.set_clipboard(&clipboard);
let downloader: Arc<dyn wezterm_term::DownloadHandler> = let downloader: Arc<dyn wezterm_term::DownloadHandler> =
Arc::new(crate::download::Downloader::new()); Arc::new(crate::download::Downloader::new());
pos.pane.set_download_handler(&downloader); pos.pane.set_download_handler(&downloader);
@ -1186,6 +1182,7 @@ impl TermWindow {
| Alert::PaletteChanged { .. }, | Alert::PaletteChanged { .. },
.. ..
} }
| MuxNotification::AssignClipboard { .. }
| MuxNotification::PaneRemoved(_) | MuxNotification::PaneRemoved(_)
| MuxNotification::WindowCreated(_) | MuxNotification::WindowCreated(_)
| MuxNotification::ActiveWorkspaceChanged(_) | MuxNotification::ActiveWorkspaceChanged(_)
@ -2252,9 +2249,6 @@ impl TermWindow {
let size = self.terminal_size; let size = self.terminal_size;
let term_config = Arc::new(TermConfig::with_config(self.config.clone())); let term_config = Arc::new(TermConfig::with_config(self.config.clone()));
let src_window_id = self.mux_window_id; let src_window_id = self.mux_window_id;
let clipboard = ClipboardHelper {
window: self.window.as_ref().unwrap().clone(),
};
promise::spawn::spawn(async move { promise::spawn::spawn(async move {
if let Err(err) = Self::spawn_command_internal( if let Err(err) = Self::spawn_command_internal(
@ -2262,7 +2256,6 @@ impl TermWindow {
SpawnWhere::NewWindow, SpawnWhere::NewWindow,
size, size,
src_window_id, src_window_id,
clipboard,
term_config, term_config,
) )
.await .await

View File

@ -1,4 +1,4 @@
use crate::termwindow::{ClipboardHelper, MuxWindowId}; use crate::termwindow::MuxWindowId;
use anyhow::{anyhow, bail, Context}; use anyhow::{anyhow, bail, Context};
use config::keyassignment::{SpawnCommand, SpawnTabDomain}; use config::keyassignment::{SpawnCommand, SpawnTabDomain};
use config::TermConfig; use config::TermConfig;
@ -24,16 +24,7 @@ impl super::TermWindow {
}; };
let term_config = Arc::new(TermConfig::with_config(self.config.clone())); let term_config = Arc::new(TermConfig::with_config(self.config.clone()));
Self::spawn_command_impl( Self::spawn_command_impl(spawn, spawn_where, size, self.mux_window_id, term_config)
spawn,
spawn_where,
size,
self.mux_window_id,
ClipboardHelper {
window: self.window.as_ref().unwrap().clone(),
},
term_config,
)
} }
fn spawn_command_impl( fn spawn_command_impl(
@ -41,21 +32,14 @@ impl super::TermWindow {
spawn_where: SpawnWhere, spawn_where: SpawnWhere,
size: PtySize, size: PtySize,
src_window_id: MuxWindowId, src_window_id: MuxWindowId,
clipboard: ClipboardHelper,
term_config: Arc<TermConfig>, term_config: Arc<TermConfig>,
) { ) {
let spawn = spawn.clone(); let spawn = spawn.clone();
promise::spawn::spawn(async move { promise::spawn::spawn(async move {
if let Err(err) = Self::spawn_command_internal( if let Err(err) =
spawn, Self::spawn_command_internal(spawn, spawn_where, size, src_window_id, term_config)
spawn_where, .await
size,
src_window_id,
clipboard,
term_config,
)
.await
{ {
log::error!("Failed to spawn: {:#}", err); log::error!("Failed to spawn: {:#}", err);
} }
@ -68,7 +52,6 @@ impl super::TermWindow {
spawn_where: SpawnWhere, spawn_where: SpawnWhere,
size: PtySize, size: PtySize,
src_window_id: MuxWindowId, src_window_id: MuxWindowId,
clipboard: ClipboardHelper,
term_config: Arc<TermConfig>, term_config: Arc<TermConfig>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let mux = Mux::get().unwrap(); let mux = Mux::get().unwrap();
@ -104,7 +87,6 @@ impl super::TermWindow {
None None
}; };
let clipboard: Arc<dyn wezterm_term::Clipboard> = Arc::new(clipboard);
let downloader: Arc<dyn wezterm_term::DownloadHandler> = let downloader: Arc<dyn wezterm_term::DownloadHandler> =
Arc::new(crate::download::Downloader::new()); Arc::new(crate::download::Downloader::new());
let workspace = mux.active_workspace().clone(); let workspace = mux.active_workspace().clone();
@ -129,7 +111,6 @@ impl super::TermWindow {
.await .await
.context("split_pane")?; .context("split_pane")?;
pane.set_config(term_config); pane.set_config(term_config);
pane.set_clipboard(&clipboard);
pane.set_download_handler(&downloader); pane.set_download_handler(&downloader);
} else { } else {
bail!("there is no active tab while splitting pane!?"); bail!("there is no active tab while splitting pane!?");
@ -157,7 +138,6 @@ impl super::TermWindow {
// the new window being created. // the new window being created.
if window_id == src_window_id { if window_id == src_window_id {
pane.set_config(term_config); pane.set_config(term_config);
pane.set_clipboard(&clipboard);
pane.set_download_handler(&downloader); pane.set_download_handler(&downloader);
} }
} }

View File

@ -96,6 +96,20 @@ where
} }
handler.schedule_pane_push(pane_id); handler.schedule_pane_push(pane_id);
} }
Ok(Item::Notif(MuxNotification::AssignClipboard {
pane_id,
selection,
clipboard,
})) => {
Pdu::SetClipboard(codec::SetClipboard {
pane_id,
clipboard,
selection,
})
.encode_async(&mut stream, 0)
.await?;
stream.flush().await.context("flushing PDU to client")?;
}
Ok(Item::Notif(MuxNotification::WindowRemoved(_window_id))) => {} Ok(Item::Notif(MuxNotification::WindowRemoved(_window_id))) => {}
Ok(Item::Notif(MuxNotification::WindowCreated(_window_id))) => {} Ok(Item::Notif(MuxNotification::WindowCreated(_window_id))) => {}
Ok(Item::Notif(MuxNotification::WindowInvalidated(_window_id))) => {} Ok(Item::Notif(MuxNotification::WindowInvalidated(_window_id))) => {}

View File

@ -13,7 +13,7 @@ use std::sync::{Arc, Mutex};
use std::time::Instant; use std::time::Instant;
use termwiz::surface::SequenceNo; use termwiz::surface::SequenceNo;
use url::Url; use url::Url;
use wezterm_term::terminal::{Alert, Clipboard, ClipboardSelection}; use wezterm_term::terminal::Alert;
use wezterm_term::StableRowIndex; use wezterm_term::StableRowIndex;
#[derive(Clone)] #[derive(Clone)]
@ -204,17 +204,6 @@ impl Drop for SessionHandler {
impl SessionHandler { impl SessionHandler {
pub fn new(to_write_tx: PduSender) -> Self { pub fn new(to_write_tx: PduSender) -> Self {
// Fixup the clipboard on the empty initial pane that is
// spawned into the mux
let mux = Mux::get().unwrap();
for pane in mux.iter_panes() {
let clip: Arc<dyn Clipboard> = Arc::new(RemoteClipboard {
pane_id: pane.pane_id(),
sender: to_write_tx.clone(),
});
pane.set_clipboard(&clip);
}
Self { Self {
to_write_tx, to_write_tx,
per_pane: HashMap::new(), per_pane: HashMap::new(),
@ -537,19 +526,17 @@ impl SessionHandler {
} }
Pdu::SpawnV2(spawn) => { Pdu::SpawnV2(spawn) => {
let sender = self.to_write_tx.clone();
let client_id = self.client_id.clone(); let client_id = self.client_id.clone();
spawn_into_main_thread(async move { spawn_into_main_thread(async move {
schedule_domain_spawn_v2(spawn, sender, send_response, client_id); schedule_domain_spawn_v2(spawn, send_response, client_id);
}) })
.detach(); .detach();
} }
Pdu::SplitPane(split) => { Pdu::SplitPane(split) => {
let sender = self.to_write_tx.clone();
let client_id = self.client_id.clone(); let client_id = self.client_id.clone();
spawn_into_main_thread(async move { spawn_into_main_thread(async move {
schedule_split_pane(split, sender, send_response, client_id); schedule_split_pane(split, send_response, client_id);
}) })
.detach(); .detach();
} }
@ -707,60 +694,24 @@ impl SessionHandler {
// analysis and allow things to compile. // analysis and allow things to compile.
fn schedule_domain_spawn_v2<SND>( fn schedule_domain_spawn_v2<SND>(
spawn: SpawnV2, spawn: SpawnV2,
sender: PduSender,
send_response: SND, send_response: SND,
client_id: Option<Arc<ClientId>>, client_id: Option<Arc<ClientId>>,
) where ) where
SND: Fn(anyhow::Result<Pdu>) + 'static, SND: Fn(anyhow::Result<Pdu>) + 'static,
{ {
promise::spawn::spawn( promise::spawn::spawn(async move { send_response(domain_spawn_v2(spawn, client_id).await) })
async move { send_response(domain_spawn_v2(spawn, sender, client_id).await) },
)
.detach();
}
fn schedule_split_pane<SND>(
split: SplitPane,
sender: PduSender,
send_response: SND,
client_id: Option<Arc<ClientId>>,
) where
SND: Fn(anyhow::Result<Pdu>) + 'static,
{
promise::spawn::spawn(async move { send_response(split_pane(split, sender, client_id).await) })
.detach(); .detach();
} }
struct RemoteClipboard { fn schedule_split_pane<SND>(split: SplitPane, send_response: SND, client_id: Option<Arc<ClientId>>)
sender: PduSender, where
pane_id: PaneId, SND: Fn(anyhow::Result<Pdu>) + 'static,
{
promise::spawn::spawn(async move { send_response(split_pane(split, client_id).await) })
.detach();
} }
impl Clipboard for RemoteClipboard { async fn split_pane(split: SplitPane, client_id: Option<Arc<ClientId>>) -> anyhow::Result<Pdu> {
fn set_contents(
&self,
selection: ClipboardSelection,
clipboard: Option<String>,
) -> anyhow::Result<()> {
self.sender
.send(DecodedPdu {
serial: 0,
pdu: Pdu::SetClipboard(SetClipboard {
pane_id: self.pane_id,
clipboard,
selection,
}),
})
.context("RemoteClipboard::set_contents send failed")?;
Ok(())
}
}
async fn split_pane(
split: SplitPane,
sender: PduSender,
client_id: Option<Arc<ClientId>>,
) -> anyhow::Result<Pdu> {
let mux = Mux::get().unwrap(); let mux = Mux::get().unwrap();
let _identity = mux.with_identity(client_id); let _identity = mux.with_identity(client_id);
@ -778,12 +729,6 @@ async fn split_pane(
) )
.await?; .await?;
let clip: Arc<dyn Clipboard> = Arc::new(RemoteClipboard {
pane_id: pane.pane_id(),
sender,
});
pane.set_clipboard(&clip);
Ok::<Pdu, anyhow::Error>(Pdu::SpawnResponse(SpawnResponse { Ok::<Pdu, anyhow::Error>(Pdu::SpawnResponse(SpawnResponse {
pane_id: pane.pane_id(), pane_id: pane.pane_id(),
tab_id: tab_id, tab_id: tab_id,
@ -792,11 +737,7 @@ async fn split_pane(
})) }))
} }
async fn domain_spawn_v2( async fn domain_spawn_v2(spawn: SpawnV2, client_id: Option<Arc<ClientId>>) -> anyhow::Result<Pdu> {
spawn: SpawnV2,
sender: PduSender,
client_id: Option<Arc<ClientId>>,
) -> anyhow::Result<Pdu> {
let mux = Mux::get().unwrap(); let mux = Mux::get().unwrap();
let _identity = mux.with_identity(client_id); let _identity = mux.with_identity(client_id);
@ -812,12 +753,6 @@ async fn domain_spawn_v2(
) )
.await?; .await?;
let clip: Arc<dyn Clipboard> = Arc::new(RemoteClipboard {
pane_id: pane.pane_id(),
sender,
});
pane.set_clipboard(&clip);
Ok::<Pdu, anyhow::Error>(Pdu::SpawnResponse(SpawnResponse { Ok::<Pdu, anyhow::Error>(Pdu::SpawnResponse(SpawnResponse {
pane_id: pane.pane_id(), pane_id: pane.pane_id(),
tab_id: tab.tab_id(), tab_id: tab.tab_id(),