mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 21:32:13 +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:
parent
e56dfa9875
commit
7c7825c070
@ -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
12
src/config/terminal.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
|
@ -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
26
term/src/config.rs
Normal 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>;
|
||||||
|
}
|
@ -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::*;
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user