diff --git a/src/config/mod.rs b/src/config/mod.rs index 0801769a6..84daaa29c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -26,6 +26,7 @@ mod daemon; mod font; mod keys; mod ssh; +mod terminal; mod tls; mod unix; pub use color::*; @@ -33,6 +34,7 @@ pub use daemon::*; pub use font::*; pub use keys::*; pub use ssh::*; +pub use terminal::*; pub use tls::*; pub use unix::*; @@ -214,7 +216,8 @@ pub struct Config { pub colors: Option, /// How many lines of scrollback you want to retain - pub scrollback_lines: Option, + #[serde(default = "default_scrollback_lines")] + pub scrollback_lines: usize, /// If no `prog` is specified on the command line, use this /// instead of running the user's shell. @@ -459,6 +462,10 @@ fn default_swap_backspace_and_delete() -> bool { cfg!(target_os = "macos") } +fn default_scrollback_lines() -> usize { + 3500 +} + fn default_hyperlink_rules() -> Vec { vec![ // URL with a protocol diff --git a/src/config/terminal.rs b/src/config/terminal.rs new file mode 100644 index 000000000..cc7881f09 --- /dev/null +++ b/src/config/terminal.rs @@ -0,0 +1,12 @@ +//! Bridge our gui config into the terminal crate configuration + +use crate::config::configuration; + +#[derive(Debug)] +pub struct TermConfig; + +impl term::TerminalConfiguration for TermConfig { + fn scrollback_size(&self) -> usize { + configuration().scrollback_lines + } +} diff --git a/src/mux/domain.rs b/src/mux/domain.rs index 786bd1033..6e0196685 100644 --- a/src/mux/domain.rs +++ b/src/mux/domain.rs @@ -100,8 +100,8 @@ impl Domain for LocalDomain { size.cols as usize, size.pixel_width as usize, size.pixel_height as usize, - config.scrollback_lines.unwrap_or(3500), config.hyperlink_rules.clone(), + std::sync::Arc::new(crate::config::TermConfig {}), ); let mux = Mux::get().unwrap(); diff --git a/src/ssh.rs b/src/ssh.rs index 01a2f9422..a38fabb94 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -352,8 +352,8 @@ impl Domain for RemoteSshDomain { size.cols as usize, size.pixel_width as usize, size.pixel_height as usize, - config.scrollback_lines.unwrap_or(3500), config.hyperlink_rules.clone(), + std::sync::Arc::new(crate::config::TermConfig {}), ); let mux = Mux::get().unwrap(); diff --git a/term/src/config.rs b/term/src/config.rs new file mode 100644 index 000000000..075a29409 --- /dev/null +++ b/term/src/config.rs @@ -0,0 +1,26 @@ +pub trait TerminalConfiguration: std::fmt::Debug { + fn scrollback_size(&self) -> usize { + 3500 + } + + // TODO: expose is_double_click_word in config file + fn is_double_click_word(&self, s: &str) -> bool { + if s.len() > 1 { + true + } else if s.len() == 1 { + match s.chars().nth(0).unwrap() { + ' ' | '\t' | '\n' | '{' | '[' | '}' | ']' | '(' | ')' | '"' | '\'' => false, + _ => true, + } + } else { + false + } + } + + // TODO: expose scroll_to_bottom_on_key_input in config file + fn scroll_to_bottom_on_key_input(&self) -> bool { + true + } + + // fn hyperlink_rules(&self) -> &Vec; +} diff --git a/term/src/lib.rs b/term/src/lib.rs index f7528d328..a7cd2bf92 100644 --- a/term/src/lib.rs +++ b/term/src/lib.rs @@ -5,6 +5,9 @@ use failure::Error; use std::ops::{Deref, DerefMut, Range}; use std::str; +pub mod config; +pub use config::TerminalConfiguration; + pub mod input; pub use crate::input::*; diff --git a/term/src/screen.rs b/term/src/screen.rs index 2f7ce8f67..96385b0f6 100644 --- a/term/src/screen.rs +++ b/term/src/screen.rs @@ -1,6 +1,7 @@ use super::*; use log::debug; use std::collections::VecDeque; +use std::sync::Arc; /// Holds the model of a screen. This can either be the primary screen /// which includes lines of scrollback text, or the alternate screen @@ -18,8 +19,9 @@ pub struct Screen { /// would otherwise have exceeded the line capacity pub lines: VecDeque, - /// Maximum number of lines of scrollback - pub scrollback_size: usize, + /// config so we can access Maximum number of lines of scrollback + config: Arc, + allow_scrollback: bool, /// Physical, visible height of the screen (not including scrollback) pub physical_rows: usize, @@ -27,33 +29,52 @@ pub struct Screen { pub physical_cols: usize, } +fn scrollback_size(config: &Arc, allow_scrollback: bool) -> usize { + if allow_scrollback { + config.scrollback_size() + } else { + 0 + } +} + impl Screen { /// Create a new Screen with the specified dimensions. /// The Cells in the viewable portion of the screen are set to the /// default cell attributes. - pub fn new(physical_rows: usize, physical_cols: usize, scrollback_size: usize) -> Screen { + pub fn new( + physical_rows: usize, + physical_cols: usize, + config: &Arc, + allow_scrollback: bool, + ) -> Screen { let physical_rows = physical_rows.max(1); let physical_cols = physical_cols.max(1); - let mut lines = VecDeque::with_capacity(physical_rows + scrollback_size); + let mut lines = + VecDeque::with_capacity(physical_rows + scrollback_size(config, allow_scrollback)); for _ in 0..physical_rows { lines.push_back(Line::with_width(physical_cols)); } Screen { lines, - scrollback_size, + config: Arc::clone(config), + allow_scrollback, physical_rows, physical_cols, } } + fn scrollback_size(&self) -> usize { + scrollback_size(&self.config, self.allow_scrollback) + } + /// Resize the physical, viewable portion of the screen pub fn resize(&mut self, physical_rows: usize, physical_cols: usize) { let physical_rows = physical_rows.max(1); let physical_cols = physical_cols.max(1); - let capacity = physical_rows + self.scrollback_size; + let capacity = physical_rows + self.scrollback_size(); let current_capacity = self.lines.capacity(); if capacity > current_capacity { self.lines.reserve(capacity - current_capacity); @@ -209,7 +230,7 @@ impl Screen { // Remove the scrolled lines num_rows } else { - let max_allowed = self.physical_rows + self.scrollback_size; + let max_allowed = self.physical_rows + self.scrollback_size(); if self.lines.len() + num_rows >= max_allowed { (self.lines.len() + num_rows) - max_allowed } else { diff --git a/term/src/terminal.rs b/term/src/terminal.rs index c0bfd07c4..c9a3c7843 100644 --- a/term/src/terminal.rs +++ b/term/src/terminal.rs @@ -72,8 +72,8 @@ impl Terminal { physical_cols: usize, pixel_width: usize, pixel_height: usize, - scrollback_size: usize, hyperlink_rules: Vec, + config: Arc, ) -> Terminal { Terminal { state: TerminalState::new( @@ -81,8 +81,8 @@ impl Terminal { physical_cols, pixel_height, pixel_width, - scrollback_size, hyperlink_rules, + config, ), parser: Parser::new(), } diff --git a/term/src/terminalstate.rs b/term/src/terminalstate.rs index 8b550f013..4cde3782d 100644 --- a/term/src/terminalstate.rs +++ b/term/src/terminalstate.rs @@ -100,9 +100,13 @@ impl DerefMut for ScreenOrAlt { } impl ScreenOrAlt { - pub fn new(physical_rows: usize, physical_cols: usize, scrollback_size: usize) -> Self { - let screen = Screen::new(physical_rows, physical_cols, scrollback_size); - let alt_screen = Screen::new(physical_rows, physical_cols, 0); + pub fn new( + physical_rows: usize, + physical_cols: usize, + config: &Arc, + ) -> Self { + let screen = Screen::new(physical_rows, physical_cols, config, true); + let alt_screen = Screen::new(physical_rows, physical_cols, config, false); Self { screen, @@ -140,6 +144,8 @@ impl ScreenOrAlt { } pub struct TerminalState { + config: Arc, + screen: ScreenOrAlt, /// The current set of attributes in effect for the next /// attempt to print to the display @@ -203,6 +209,7 @@ pub struct TerminalState { tabs: TabStop, + /// FIXME: replace hyperlink_rules with config access hyperlink_rules: Vec, /// The terminal title string @@ -213,20 +220,6 @@ pub struct TerminalState { pixel_height: usize, } -fn is_double_click_word(s: &str) -> bool { - // TODO: add configuration for this - if s.len() > 1 { - true - } else if s.len() == 1 { - match s.chars().nth(0).unwrap() { - ' ' | '\t' | '\n' | '{' | '[' | '}' | ']' | '(' | ')' | '"' | '\'' => false, - _ => true, - } - } else { - false - } -} - fn encode_modifiers(mods: KeyModifiers) -> u8 { let mut number = 0; if mods.contains(KeyModifiers::SHIFT) { @@ -267,12 +260,13 @@ impl TerminalState { physical_cols: usize, pixel_width: usize, pixel_height: usize, - scrollback_size: usize, hyperlink_rules: Vec, + config: Arc, ) -> TerminalState { - let screen = ScreenOrAlt::new(physical_rows, physical_cols, scrollback_size); + let screen = ScreenOrAlt::new(physical_rows, physical_cols, &config); TerminalState { + config, screen, pen: CellAttributes::default(), cursor: CursorPosition::default(), @@ -483,7 +477,7 @@ impl TerminalState { - self.viewport_offset as ScrollbackOrVisibleRowIndex; let idx = self.screen().scrollback_or_visible_row(y); let selection_range = match self.screen().lines[idx] - .compute_double_click_range(event.x, is_double_click_word) + .compute_double_click_range(event.x, |s| self.config.is_double_click_word(s)) { DoubleClickRange::Range(click_range) => SelectionRange { start: SelectionCoordinate { @@ -508,7 +502,7 @@ impl TerminalState { for y_cont in idx + 1..self.screen().lines.len() { match self.screen().lines[y_cont] - .compute_double_click_range(0, is_double_click_word) + .compute_double_click_range(0, |s| self.config.is_double_click_word(s)) { DoubleClickRange::Range(range_end) => { if range_end.end > range_end.start { @@ -1089,8 +1083,10 @@ impl TerminalState { writer.write_all(to_send.as_bytes())?; // Reset the viewport if we sent data to the parser - if !to_send.is_empty() && self.viewport_offset != 0 { - // TODO: some folks like to configure this behavior. + if !to_send.is_empty() + && self.viewport_offset != 0 + && self.config.scroll_to_bottom_on_key_input() + { self.set_scroll_viewport(0); } diff --git a/term/src/test/mod.rs b/term/src/test/mod.rs index d72453534..bfff2e955 100644 --- a/term/src/test/mod.rs +++ b/term/src/test/mod.rs @@ -86,6 +86,16 @@ struct TestTerm { host: TestHost, } +#[derive(Debug)] +struct TestTermConfig { + scrollback: usize, +} +impl TerminalConfiguration for TestTermConfig { + fn scrollback_size(&self) -> usize { + self.scrollback + } +} + impl TestTerm { fn new(height: usize, width: usize, scrollback: usize) -> Self { Self { @@ -94,8 +104,8 @@ impl TestTerm { width, height * 16, width * 8, - scrollback, Vec::new(), + Arc::new(TestTermConfig { scrollback }), ), host: TestHost::new(), } diff --git a/termwiz/src/surface/line.rs b/termwiz/src/surface/line.rs index c314bdd57..c07d72988 100644 --- a/termwiz/src/surface/line.rs +++ b/termwiz/src/surface/line.rs @@ -195,10 +195,10 @@ impl Line { s } - pub fn compute_double_click_range( + pub fn compute_double_click_range bool>( &self, click_col: usize, - is_word: fn(s: &str) -> bool, + is_word: F, ) -> DoubleClickRange { let mut lower = click_col; let mut upper = click_col;