diff --git a/src/frontend/guicommon/host.rs b/src/frontend/guicommon/host.rs index 7f60648be..b3c6bb3c3 100644 --- a/src/frontend/guicommon/host.rs +++ b/src/frontend/guicommon/host.rs @@ -3,7 +3,7 @@ use crate::mux::tab::Tab; use clipboard::{ClipboardContext, ClipboardProvider}; use failure::Error; use std::ops::{Deref, DerefMut}; -use std::rc::Rc; +use std::sync::Arc; use term::{KeyCode, KeyModifiers}; use termwiz::hyperlink::Hyperlink; @@ -188,7 +188,7 @@ impl<'a, H: HostHelper> term::TerminalHost for TabHost<'a, H> { &mut self.writer } - fn click_link(&mut self, link: &Rc) { + fn click_link(&mut self, link: &Arc) { match open::that(link.uri()) { Ok(_) => {} Err(err) => eprintln!("failed to open {}: {:?}", link.uri(), err), diff --git a/src/main.rs b/src/main.rs index ea4342dc3..3b3a81d78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -153,9 +153,17 @@ fn main() -> Result<(), Error> { } SubCommand::Cli(_) => { use crate::server::client::Client; + use crate::server::codec::*; let mut client = Client::new(&config)?; eprintln!("ping: {:?}", client.ping()?); - eprintln!("tabs: {:?}", client.list_tabs()?); + let tabs = client.list_tabs()?; + for (tab_id, title) in tabs.tabs.iter() { + eprintln!("tab {}: {}", tab_id, title); + let data = client.get_coarse_tab_renderable_data(GetCoarseTabRenderableData { + tab_id: *tab_id, + })?; + eprintln!("coarse: {:?}", data); + } Ok(()) } } diff --git a/src/mux/mod.rs b/src/mux/mod.rs index e4822c36f..5a67e86e2 100644 --- a/src/mux/mod.rs +++ b/src/mux/mod.rs @@ -74,7 +74,7 @@ impl<'a> TerminalHost for Host<'a> { &mut self.writer } - fn click_link(&mut self, link: &Rc) { + fn click_link(&mut self, link: &Arc) { match open::that(link.uri()) { Ok(_) => {} Err(err) => eprintln!("failed to open {}: {:?}", link.uri(), err), diff --git a/src/mux/renderable.rs b/src/mux/renderable.rs index 66925c3ed..ef83e9f58 100644 --- a/src/mux/renderable.rs +++ b/src/mux/renderable.rs @@ -1,5 +1,5 @@ use std::ops::Range; -use std::rc::Rc; +use std::sync::Arc; use term::{CursorPosition, Line, Terminal, TerminalState}; use termwiz::hyperlink::Hyperlink; @@ -26,7 +26,7 @@ pub trait Renderable { fn clean_dirty_lines(&mut self); /// Returns the currently highlighted hyperlink - fn current_highlight(&self) -> Option>; + fn current_highlight(&self) -> Option>; /// Returns physical, non-scrollback (rows, cols) for the /// terminal screen @@ -50,7 +50,7 @@ impl Renderable for Terminal { TerminalState::make_all_lines_dirty(self) } - fn current_highlight(&self) -> Option> { + fn current_highlight(&self) -> Option> { TerminalState::current_highlight(self) } diff --git a/src/server/client.rs b/src/server/client.rs index ff3023858..b83dc652f 100644 --- a/src/server/client.rs +++ b/src/server/client.rs @@ -64,4 +64,9 @@ impl Client { rpc!(ping, Ping = (), Pong); rpc!(list_tabs, ListTabs = (), ListTabsResponse); + rpc!( + get_coarse_tab_renderable_data, + GetCoarseTabRenderableData, + GetCoarseTabRenderableDataResponse + ); } diff --git a/src/server/codec.rs b/src/server/codec.rs index 2581806fc..d372a7392 100644 --- a/src/server/codec.rs +++ b/src/server/codec.rs @@ -15,7 +15,7 @@ use bincode; use failure::Error; use serde_derive::*; use std::collections::HashMap; -use std::rc::Rc; +use std::sync::Arc; use term::{CursorPosition, Line}; use termwiz::hyperlink::Hyperlink; use varu64; @@ -137,6 +137,8 @@ pdu! { Pong: 2, ListTabs: 3, ListTabsResponse: 4, + GetCoarseTabRenderableData: 5, + GetCoarseTabRenderableDataResponse: 6, } #[derive(Deserialize, Serialize, PartialEq, Debug)] @@ -174,7 +176,7 @@ pub struct GetCoarseTabRenderableDataResponse { pub cursor_position: CursorPosition, pub physical_rows: usize, pub physical_cols: usize, - pub current_highlight: Option>, + pub current_highlight: Option>, pub dirty_lines: Vec, } diff --git a/src/server/listener.rs b/src/server/listener.rs index e6c4f3d81..8e742c3c2 100644 --- a/src/server/listener.rs +++ b/src/server/listener.rs @@ -71,8 +71,43 @@ impl ClientSession { .wait()?; Pdu::ListTabsResponse(result).encode(&mut self.stream, decoded.serial)?; } + Pdu::GetCoarseTabRenderableData(GetCoarseTabRenderableData { tab_id }) => { + let result = Future::with_executor(self.executor.clone_executor(), move || { + let mux = Mux::get().unwrap(); + let tab = mux + .get_tab(tab_id) + .ok_or_else(|| format_err!("no such tab {}", tab_id))?; + let renderable = tab.renderer(); + let dirty_lines = renderable + .get_dirty_lines() + .iter() + .map(|(line_idx, line, sel)| DirtyLine { + line_idx: *line_idx, + line: (*line).clone(), + selection_col_from: sel.start, + selection_col_to: sel.end, + }) + .collect(); - Pdu::Pong { .. } | Pdu::ListTabsResponse { .. } | Pdu::Invalid { .. } => {} + let (physical_rows, physical_cols) = renderable.physical_dimensions(); + + Ok(GetCoarseTabRenderableDataResponse { + dirty_lines, + current_highlight: renderable.current_highlight(), + cursor_position: renderable.get_cursor_position(), + physical_rows, + physical_cols, + }) + }) + .wait()?; + Pdu::GetCoarseTabRenderableDataResponse(result) + .encode(&mut self.stream, decoded.serial)?; + } + + Pdu::Pong { .. } + | Pdu::ListTabsResponse { .. } + | Pdu::GetCoarseTabRenderableDataResponse { .. } + | Pdu::Invalid { .. } => {} } } } diff --git a/term/src/lib.rs b/term/src/lib.rs index 369ababff..7c514d064 100644 --- a/term/src/lib.rs +++ b/term/src/lib.rs @@ -7,7 +7,6 @@ use serde_derive::*; use failure::Error; use std::ops::{Deref, DerefMut, Range}; -use std::rc::Rc; use std::str; #[macro_use] diff --git a/term/src/terminal.rs b/term/src/terminal.rs index d60f87f76..4a85b19b3 100644 --- a/term/src/terminal.rs +++ b/term/src/terminal.rs @@ -1,4 +1,5 @@ use super::*; +use std::sync::Arc; use termwiz::escape::parser::Parser; use termwiz::hyperlink::Rule as HyperlinkRule; @@ -20,7 +21,7 @@ pub trait TerminalHost { fn set_title(&mut self, title: &str); /// Called when a URL is clicked - fn click_link(&mut self, link: &Rc); + fn click_link(&mut self, link: &Arc); /// Switch to a specific tab fn activate_tab(&mut self, _tab: usize) {} diff --git a/term/src/terminalstate.rs b/term/src/terminalstate.rs index bff273694..81a57a4a2 100644 --- a/term/src/terminalstate.rs +++ b/term/src/terminalstate.rs @@ -5,6 +5,7 @@ use super::*; use image::{self, GenericImage}; use ordered_float::NotNaN; use std::fmt::Write; +use std::sync::Arc; use termwiz::escape::csi::{ Cursor, DecPrivateMode, DecPrivateModeCode, Device, Edit, EraseInDisplay, EraseInLine, Mode, Sgr, @@ -154,7 +155,7 @@ pub struct TerminalState { /// Which hyperlink is considered to be highlighted, because the /// mouse_position is over a cell with a Hyperlink attribute. - current_highlight: Option>, + current_highlight: Option>, /// Keeps track of double and triple clicks last_mouse_click: Option, @@ -342,7 +343,7 @@ impl TerminalState { &mut self, x: usize, y: ScrollbackOrVisibleRowIndex, - ) -> Option> { + ) -> Option> { let rules = &self.hyperlink_rules; let idx = self.screen.scrollback_or_visible_row(y); @@ -1003,7 +1004,7 @@ impl TerminalState { } /// Returns the currently highlighted hyperlink - pub fn current_highlight(&self) -> Option> { + pub fn current_highlight(&self) -> Option> { self.current_highlight.as_ref().cloned() } @@ -1139,7 +1140,7 @@ impl TerminalState { fn set_hyperlink(&mut self, link: Option) { self.pen.hyperlink = match link { - Some(hyperlink) => Some(Rc::new(hyperlink)), + Some(hyperlink) => Some(Arc::new(hyperlink)), None => None, } } @@ -1228,7 +1229,7 @@ impl TerminalState { }; */ - let image_data = Rc::new(ImageData::with_raw_data(image.data)); + let image_data = Arc::new(ImageData::with_raw_data(image.data)); let mut ypos = NotNaN::new(0.0).unwrap(); let cursor_x = self.cursor.x; diff --git a/termwiz/src/cell.rs b/termwiz/src/cell.rs index a9de752ed..0388ab8a2 100644 --- a/termwiz/src/cell.rs +++ b/termwiz/src/cell.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use smallvec::SmallVec; use std; use std::mem; -use std::rc::Rc; +use std::sync::Arc; use unicode_width::UnicodeWidthStr; /// Holds the attributes for a cell. @@ -22,7 +22,7 @@ pub struct CellAttributes { /// The background color pub background: ColorAttribute, /// The hyperlink content, if any - pub hyperlink: Option>, + pub hyperlink: Option>, /// The image data, if any pub image: Option>, } @@ -159,7 +159,7 @@ impl CellAttributes { self } - pub fn set_hyperlink(&mut self, link: Option>) -> &mut Self { + pub fn set_hyperlink(&mut self, link: Option>) -> &mut Self { self.hyperlink = link; self } @@ -309,7 +309,7 @@ pub enum AttributeChange { Invisible(bool), Foreground(ColorAttribute), Background(ColorAttribute), - Hyperlink(Option>), + Hyperlink(Option>), } #[cfg(test)] diff --git a/termwiz/src/hyperlink.rs b/termwiz/src/hyperlink.rs index 829e8e85a..4902134be 100644 --- a/termwiz/src/hyperlink.rs +++ b/termwiz/src/hyperlink.rs @@ -11,7 +11,7 @@ use serde_derive::*; use std::collections::HashMap; use std::fmt::{Display, Error as FmtError, Formatter}; use std::ops::Range; -use std::rc::Rc; +use std::sync::Arc; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Hyperlink { @@ -157,7 +157,7 @@ pub struct RuleMatch { pub range: Range, /// Holds the created Hyperlink object that should be associated /// the cells that correspond to the span. - pub link: Rc, + pub link: Arc, } /// An internal intermediate match result @@ -220,7 +220,7 @@ impl Rule { .into_iter() .map(|m| { let url = m.expand(); - let link = Rc::new(Hyperlink::new_implicit(url)); + let link = Arc::new(Hyperlink::new_implicit(url)); RuleMatch { link, range: m.range(), @@ -245,7 +245,7 @@ mod test { Rule::match_hyperlinks(" http://example.com", &rules), vec![RuleMatch { range: 2..20, - link: Rc::new(Hyperlink::new_implicit("http://example.com")), + link: Arc::new(Hyperlink::new_implicit("http://example.com")), }] ); @@ -255,11 +255,11 @@ mod test { // Longest match first RuleMatch { range: 18..34, - link: Rc::new(Hyperlink::new_implicit("mailto:woot@example.com")), + link: Arc::new(Hyperlink::new_implicit("mailto:woot@example.com")), }, RuleMatch { range: 2..17, - link: Rc::new(Hyperlink::new_implicit("mailto:foo@example.com")), + link: Arc::new(Hyperlink::new_implicit("mailto:foo@example.com")), }, ] ); diff --git a/termwiz/src/image.rs b/termwiz/src/image.rs index b1729ba20..adedf279d 100644 --- a/termwiz/src/image.rs +++ b/termwiz/src/image.rs @@ -14,7 +14,7 @@ use ordered_float::NotNaN; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_derive::*; -use std::rc::Rc; +use std::sync::Arc; fn deserialize_notnan<'de, D>(deserializer: D) -> Result, D::Error> where @@ -71,14 +71,14 @@ pub struct ImageCell { /// Texture coordinates for the bottom right of this cell. bottom_right: TextureCoordinate, /// References the underlying image data - data: Rc, + data: Arc, } impl ImageCell { pub fn new( top_left: TextureCoordinate, bottom_right: TextureCoordinate, - data: Rc, + data: Arc, ) -> Self { Self { top_left, diff --git a/termwiz/src/surface/change.rs b/termwiz/src/surface/change.rs index 315db7193..50ccceebb 100644 --- a/termwiz/src/surface/change.rs +++ b/termwiz/src/surface/change.rs @@ -2,7 +2,7 @@ use crate::cell::{AttributeChange, CellAttributes}; use crate::color::ColorAttribute; pub use crate::image::{ImageData, TextureCoordinate}; use crate::surface::{CursorShape, Position}; -use std::rc::Rc; +use std::sync::Arc; /// `Change` describes an update operation to be applied to a `Surface`. /// Changes to the active attributes (color, style), moving the cursor @@ -103,5 +103,5 @@ pub struct Image { /// Texture coordinates for the bottom right of this image block. pub bottom_right: TextureCoordinate, /// the image data - pub image: Rc, + pub image: Arc, } diff --git a/termwiz/src/surface/line.rs b/termwiz/src/surface/line.rs index 89cc19780..2fffd7bd2 100644 --- a/termwiz/src/surface/line.rs +++ b/termwiz/src/surface/line.rs @@ -4,7 +4,7 @@ use crate::hyperlink::Rule; use crate::range::in_range; use crate::surface::Change; use std::ops::Range; -use std::rc::Rc; +use std::sync::Arc; use unicode_segmentation::UnicodeSegmentation; bitflags! { @@ -155,7 +155,7 @@ impl Line { let attrs = self.cells[cell_idx] .attrs() .clone() - .set_hyperlink(Some(Rc::clone(&m.link))) + .set_hyperlink(Some(Arc::clone(&m.link))) .clone(); let cell = Cell::new_grapheme(self.cells[cell_idx].str(), attrs); self.cells[cell_idx] = cell; diff --git a/termwiz/src/surface/mod.rs b/termwiz/src/surface/mod.rs index 1c82af659..5323c9165 100644 --- a/termwiz/src/surface/mod.rs +++ b/termwiz/src/surface/mod.rs @@ -770,7 +770,7 @@ mod test { use crate::cell::Intensity; use crate::color::AnsiColor; use crate::image::ImageData; - use std::rc::Rc; + use std::sync::Arc; // The \x20's look a little awkward, but we can't use a plain // space in the first chararcter of a multi-line continuation; @@ -1432,7 +1432,7 @@ mod test { #[test] fn images() { // a dummy image blob with nonsense content - let data = Rc::new(ImageData::with_raw_data(vec![])); + let data = Arc::new(ImageData::with_raw_data(vec![])); let mut s = Surface::new(2, 2); s.add_change(Change::Image(Image { top_left: TextureCoordinate::new_f32(0.0, 0.0),