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

term: extract configuration to a trait

This isn't complete but begins the process of extracting
the embedding application configuration into a trait provided
by the application rather than passing the values in at
construction.

This allows the application to change configuration at
runtime.

The first option to handle this is the scrollback size.
This commit is contained in:
Wez Furlong 2019-11-24 12:41:29 -08:00
parent e56dfa9875
commit 7c7825c070
11 changed files with 113 additions and 38 deletions

View File

@ -26,6 +26,7 @@ mod daemon;
mod font; mod font;
mod keys; mod keys;
mod ssh; mod ssh;
mod terminal;
mod tls; mod tls;
mod unix; mod unix;
pub use color::*; pub use color::*;
@ -33,6 +34,7 @@ pub use daemon::*;
pub use font::*; pub use font::*;
pub use keys::*; pub use keys::*;
pub use ssh::*; pub use ssh::*;
pub use terminal::*;
pub use tls::*; pub use tls::*;
pub use unix::*; pub use unix::*;
@ -214,7 +216,8 @@ pub struct Config {
pub colors: Option<Palette>, pub colors: Option<Palette>,
/// How many lines of scrollback you want to retain /// How many lines of scrollback you want to retain
pub scrollback_lines: Option<usize>, #[serde(default = "default_scrollback_lines")]
pub scrollback_lines: usize,
/// If no `prog` is specified on the command line, use this /// If no `prog` is specified on the command line, use this
/// instead of running the user's shell. /// instead of running the user's shell.
@ -459,6 +462,10 @@ fn default_swap_backspace_and_delete() -> bool {
cfg!(target_os = "macos") cfg!(target_os = "macos")
} }
fn default_scrollback_lines() -> usize {
3500
}
fn default_hyperlink_rules() -> Vec<hyperlink::Rule> { fn default_hyperlink_rules() -> Vec<hyperlink::Rule> {
vec![ vec![
// URL with a protocol // URL with a protocol

12
src/config/terminal.rs Normal file
View File

@ -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
}
}

View File

@ -100,8 +100,8 @@ impl Domain for LocalDomain {
size.cols as usize, size.cols as usize,
size.pixel_width as usize, size.pixel_width as usize,
size.pixel_height as usize, size.pixel_height as usize,
config.scrollback_lines.unwrap_or(3500),
config.hyperlink_rules.clone(), config.hyperlink_rules.clone(),
std::sync::Arc::new(crate::config::TermConfig {}),
); );
let mux = Mux::get().unwrap(); let mux = Mux::get().unwrap();

View File

@ -352,8 +352,8 @@ impl Domain for RemoteSshDomain {
size.cols as usize, size.cols as usize,
size.pixel_width as usize, size.pixel_width as usize,
size.pixel_height as usize, size.pixel_height as usize,
config.scrollback_lines.unwrap_or(3500),
config.hyperlink_rules.clone(), config.hyperlink_rules.clone(),
std::sync::Arc::new(crate::config::TermConfig {}),
); );
let mux = Mux::get().unwrap(); let mux = Mux::get().unwrap();

26
term/src/config.rs Normal file
View File

@ -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<HyperlinkRule>;
}

View File

@ -5,6 +5,9 @@ use failure::Error;
use std::ops::{Deref, DerefMut, Range}; use std::ops::{Deref, DerefMut, Range};
use std::str; use std::str;
pub mod config;
pub use config::TerminalConfiguration;
pub mod input; pub mod input;
pub use crate::input::*; pub use crate::input::*;

View File

@ -1,6 +1,7 @@
use super::*; use super::*;
use log::debug; use log::debug;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::Arc;
/// Holds the model of a screen. This can either be the primary screen /// Holds the model of a screen. This can either be the primary screen
/// which includes lines of scrollback text, or the alternate 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 /// would otherwise have exceeded the line capacity
pub lines: VecDeque<Line>, pub lines: VecDeque<Line>,
/// Maximum number of lines of scrollback /// config so we can access Maximum number of lines of scrollback
pub scrollback_size: usize, config: Arc<dyn TerminalConfiguration>,
allow_scrollback: bool,
/// Physical, visible height of the screen (not including scrollback) /// Physical, visible height of the screen (not including scrollback)
pub physical_rows: usize, pub physical_rows: usize,
@ -27,33 +29,52 @@ pub struct Screen {
pub physical_cols: usize, pub physical_cols: usize,
} }
fn scrollback_size(config: &Arc<dyn TerminalConfiguration>, allow_scrollback: bool) -> usize {
if allow_scrollback {
config.scrollback_size()
} else {
0
}
}
impl Screen { impl Screen {
/// Create a new Screen with the specified dimensions. /// Create a new Screen with the specified dimensions.
/// The Cells in the viewable portion of the screen are set to the /// The Cells in the viewable portion of the screen are set to the
/// default cell attributes. /// 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<dyn TerminalConfiguration>,
allow_scrollback: bool,
) -> Screen {
let physical_rows = physical_rows.max(1); let physical_rows = physical_rows.max(1);
let physical_cols = physical_cols.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 { for _ in 0..physical_rows {
lines.push_back(Line::with_width(physical_cols)); lines.push_back(Line::with_width(physical_cols));
} }
Screen { Screen {
lines, lines,
scrollback_size, config: Arc::clone(config),
allow_scrollback,
physical_rows, physical_rows,
physical_cols, physical_cols,
} }
} }
fn scrollback_size(&self) -> usize {
scrollback_size(&self.config, self.allow_scrollback)
}
/// Resize the physical, viewable portion of the screen /// Resize the physical, viewable portion of the screen
pub fn resize(&mut self, physical_rows: usize, physical_cols: usize) { pub fn resize(&mut self, physical_rows: usize, physical_cols: usize) {
let physical_rows = physical_rows.max(1); let physical_rows = physical_rows.max(1);
let physical_cols = physical_cols.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(); let current_capacity = self.lines.capacity();
if capacity > current_capacity { if capacity > current_capacity {
self.lines.reserve(capacity - current_capacity); self.lines.reserve(capacity - current_capacity);
@ -209,7 +230,7 @@ impl Screen {
// Remove the scrolled lines // Remove the scrolled lines
num_rows num_rows
} else { } 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 { if self.lines.len() + num_rows >= max_allowed {
(self.lines.len() + num_rows) - max_allowed (self.lines.len() + num_rows) - max_allowed
} else { } else {

View File

@ -72,8 +72,8 @@ impl Terminal {
physical_cols: usize, physical_cols: usize,
pixel_width: usize, pixel_width: usize,
pixel_height: usize, pixel_height: usize,
scrollback_size: usize,
hyperlink_rules: Vec<HyperlinkRule>, hyperlink_rules: Vec<HyperlinkRule>,
config: Arc<dyn TerminalConfiguration>,
) -> Terminal { ) -> Terminal {
Terminal { Terminal {
state: TerminalState::new( state: TerminalState::new(
@ -81,8 +81,8 @@ impl Terminal {
physical_cols, physical_cols,
pixel_height, pixel_height,
pixel_width, pixel_width,
scrollback_size,
hyperlink_rules, hyperlink_rules,
config,
), ),
parser: Parser::new(), parser: Parser::new(),
} }

View File

@ -100,9 +100,13 @@ impl DerefMut for ScreenOrAlt {
} }
impl ScreenOrAlt { impl ScreenOrAlt {
pub fn new(physical_rows: usize, physical_cols: usize, scrollback_size: usize) -> Self { pub fn new(
let screen = Screen::new(physical_rows, physical_cols, scrollback_size); physical_rows: usize,
let alt_screen = Screen::new(physical_rows, physical_cols, 0); physical_cols: usize,
config: &Arc<dyn TerminalConfiguration>,
) -> Self {
let screen = Screen::new(physical_rows, physical_cols, config, true);
let alt_screen = Screen::new(physical_rows, physical_cols, config, false);
Self { Self {
screen, screen,
@ -140,6 +144,8 @@ impl ScreenOrAlt {
} }
pub struct TerminalState { pub struct TerminalState {
config: Arc<dyn TerminalConfiguration>,
screen: ScreenOrAlt, screen: ScreenOrAlt,
/// The current set of attributes in effect for the next /// The current set of attributes in effect for the next
/// attempt to print to the display /// attempt to print to the display
@ -203,6 +209,7 @@ pub struct TerminalState {
tabs: TabStop, tabs: TabStop,
/// FIXME: replace hyperlink_rules with config access
hyperlink_rules: Vec<HyperlinkRule>, hyperlink_rules: Vec<HyperlinkRule>,
/// The terminal title string /// The terminal title string
@ -213,20 +220,6 @@ pub struct TerminalState {
pixel_height: usize, 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 { fn encode_modifiers(mods: KeyModifiers) -> u8 {
let mut number = 0; let mut number = 0;
if mods.contains(KeyModifiers::SHIFT) { if mods.contains(KeyModifiers::SHIFT) {
@ -267,12 +260,13 @@ impl TerminalState {
physical_cols: usize, physical_cols: usize,
pixel_width: usize, pixel_width: usize,
pixel_height: usize, pixel_height: usize,
scrollback_size: usize,
hyperlink_rules: Vec<HyperlinkRule>, hyperlink_rules: Vec<HyperlinkRule>,
config: Arc<dyn TerminalConfiguration>,
) -> TerminalState { ) -> TerminalState {
let screen = ScreenOrAlt::new(physical_rows, physical_cols, scrollback_size); let screen = ScreenOrAlt::new(physical_rows, physical_cols, &config);
TerminalState { TerminalState {
config,
screen, screen,
pen: CellAttributes::default(), pen: CellAttributes::default(),
cursor: CursorPosition::default(), cursor: CursorPosition::default(),
@ -483,7 +477,7 @@ impl TerminalState {
- self.viewport_offset as ScrollbackOrVisibleRowIndex; - self.viewport_offset as ScrollbackOrVisibleRowIndex;
let idx = self.screen().scrollback_or_visible_row(y); let idx = self.screen().scrollback_or_visible_row(y);
let selection_range = match self.screen().lines[idx] 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 { DoubleClickRange::Range(click_range) => SelectionRange {
start: SelectionCoordinate { start: SelectionCoordinate {
@ -508,7 +502,7 @@ impl TerminalState {
for y_cont in idx + 1..self.screen().lines.len() { for y_cont in idx + 1..self.screen().lines.len() {
match self.screen().lines[y_cont] 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) => { DoubleClickRange::Range(range_end) => {
if range_end.end > range_end.start { if range_end.end > range_end.start {
@ -1089,8 +1083,10 @@ impl TerminalState {
writer.write_all(to_send.as_bytes())?; writer.write_all(to_send.as_bytes())?;
// Reset the viewport if we sent data to the parser // Reset the viewport if we sent data to the parser
if !to_send.is_empty() && self.viewport_offset != 0 { if !to_send.is_empty()
// TODO: some folks like to configure this behavior. && self.viewport_offset != 0
&& self.config.scroll_to_bottom_on_key_input()
{
self.set_scroll_viewport(0); self.set_scroll_viewport(0);
} }

View File

@ -86,6 +86,16 @@ struct TestTerm {
host: TestHost, host: TestHost,
} }
#[derive(Debug)]
struct TestTermConfig {
scrollback: usize,
}
impl TerminalConfiguration for TestTermConfig {
fn scrollback_size(&self) -> usize {
self.scrollback
}
}
impl TestTerm { impl TestTerm {
fn new(height: usize, width: usize, scrollback: usize) -> Self { fn new(height: usize, width: usize, scrollback: usize) -> Self {
Self { Self {
@ -94,8 +104,8 @@ impl TestTerm {
width, width,
height * 16, height * 16,
width * 8, width * 8,
scrollback,
Vec::new(), Vec::new(),
Arc::new(TestTermConfig { scrollback }),
), ),
host: TestHost::new(), host: TestHost::new(),
} }

View File

@ -195,10 +195,10 @@ impl Line {
s s
} }
pub fn compute_double_click_range( pub fn compute_double_click_range<F: Fn(&str) -> bool>(
&self, &self,
click_col: usize, click_col: usize,
is_word: fn(s: &str) -> bool, is_word: F,
) -> DoubleClickRange { ) -> DoubleClickRange {
let mut lower = click_col; let mut lower = click_col;
let mut upper = click_col; let mut upper = click_col;