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

termwiz: do not depend on derive_builder

derive_builder has some extra dependencies that take a while to compile.
The builder feature can be expressed via a 30-line macro. So let's do
that to make termwiz compile faster.
This commit is contained in:
Jun Wu 2020-02-04 07:20:03 -08:00 committed by Wez Furlong
parent f51650c891
commit ca2e9c013a
6 changed files with 121 additions and 146 deletions

View File

@ -14,7 +14,6 @@ readme = "README.md"
base64 = "0.10" base64 = "0.10"
bitflags = "1.0" bitflags = "1.0"
cassowary = {version="0.3", optional=true} cassowary = {version="0.3", optional=true}
derive_builder = "0.7"
anyhow = "1.0" anyhow = "1.0"
filedescriptor = { version="0.7", path = "../filedescriptor" } filedescriptor = { version="0.7", path = "../filedescriptor" }
fnv = {version="1.0", optional=true} fnv = {version="1.0", optional=true}

View File

@ -52,74 +52,74 @@
//! With all this in mind, this module presents a `Capabilities` struct //! With all this in mind, this module presents a `Capabilities` struct
//! that holds information about a terminal. The `new_from_env` method //! that holds information about a terminal. The `new_from_env` method
//! implements some heuristics (a fancy word for guessing) to compute //! implements some heuristics (a fancy word for guessing) to compute
//! the terminal capabilities, but also offers a `ProbeHintsBuilder` //! the terminal capabilities, but also offers a `ProbeHints`
//! that can be used by the embedding application to override those choices. //! that can be used by the embedding application to override those choices.
use crate::builder;
use anyhow::Error; use anyhow::Error;
use derive_builder::*;
use semver::Version; use semver::Version;
use std::env::var; use std::env::var;
use terminfo::{self, capability as cap}; use terminfo::{self, capability as cap};
/// Use the `ProbeHintsBuilder` to configure an instance of builder! {
/// the `ProbeHints` struct. `ProbeHints` are passed to the `Capabilities` /// Use the `ProbeHints` to configure an instance of
/// constructor to influence the effective set of terminal capabilities. /// the `ProbeHints` struct. `ProbeHints` are passed to the `Capabilities`
#[derive(Debug, Default, Builder, Clone)] /// constructor to influence the effective set of terminal capabilities.
#[builder(default)] #[derive(Debug, Default, Clone)]
pub struct ProbeHints { pub struct ProbeHints {
/// The contents of the TERM environment variable /// The contents of the TERM environment variable
term: Option<String>, term: Option<String>,
/// The contents of the COLORTERM environment variable. /// The contents of the COLORTERM environment variable.
/// <http://invisible-island.net/ncurses/ncurses-slang.html#env_COLORTERM> /// <http://invisible-island.net/ncurses/ncurses-slang.html#env_COLORTERM>
colorterm: Option<String>, colorterm: Option<String>,
/// The contents of the TERM_PROGRAM environment variable /// The contents of the TERM_PROGRAM environment variable
term_program: Option<String>, term_program: Option<String>,
/// Override the choice of the number of colors /// Override the choice of the number of colors
color_level: Option<ColorLevel>, color_level: Option<ColorLevel>,
/// The contents of the TERM_PROGRAM_VERSION environment variable /// The contents of the TERM_PROGRAM_VERSION environment variable
term_program_version: Option<String>, term_program_version: Option<String>,
/// Definitively set whether hyperlinks are supported. /// Definitively set whether hyperlinks are supported.
/// The default is to assume yes as this is mostly harmless. /// The default is to assume yes as this is mostly harmless.
hyperlinks: Option<bool>, hyperlinks: Option<bool>,
/// Configure whether sixel graphics are supported. /// Configure whether sixel graphics are supported.
sixel: Option<bool>, sixel: Option<bool>,
/// Configure whether iTerm2 style graphics embedding is supported /// Configure whether iTerm2 style graphics embedding is supported
/// See <https://www.iterm2.com/documentation-images.html> /// See <https://www.iterm2.com/documentation-images.html>
iterm2_image: Option<bool>, iterm2_image: Option<bool>,
/// Specify whether `bce`, background color erase, is supported. /// Specify whether `bce`, background color erase, is supported.
bce: Option<bool>, bce: Option<bool>,
/// The contents of the COLORTERM_BCE environment variable /// The contents of the COLORTERM_BCE environment variable
/// <http://invisible-island.net/ncurses/ncurses-slang.html#env_COLORTERM_BCE> /// <http://invisible-island.net/ncurses/ncurses-slang.html#env_COLORTERM_BCE>
colorterm_bce: Option<String>, colorterm_bce: Option<String>,
/// A loaded terminfo database entry /// A loaded terminfo database entry
terminfo_db: Option<terminfo::Database>, terminfo_db: Option<terminfo::Database>,
/// Whether bracketed paste mode is supported /// Whether bracketed paste mode is supported
bracketed_paste: Option<bool>, bracketed_paste: Option<bool>,
/// Whether mouse support is present and should be used /// Whether mouse support is present and should be used
mouse_reporting: Option<bool>, mouse_reporting: Option<bool>,
}
} }
impl ProbeHintsBuilder { impl ProbeHints {
pub fn new_from_env() -> ProbeHintsBuilder { pub fn new_from_env() -> Self {
let mut hints = ProbeHintsBuilder::default(); ProbeHints::default()
hints.term(var("TERM").ok()); .term(var("TERM").ok())
hints.colorterm(var("COLORTERM").ok()); .colorterm(var("COLORTERM").ok())
hints.colorterm_bce(var("COLORTERM_BCE").ok()); .colorterm_bce(var("COLORTERM_BCE").ok())
hints.term_program(var("TERM_PROGRAM").ok()); .term_program(var("TERM_PROGRAM").ok())
hints.term_program_version(var("TERM_PROGRAM_VERSION").ok()); .term_program_version(var("TERM_PROGRAM_VERSION").ok())
hints.terminfo_db(terminfo::Database::from_env().ok()); .terminfo_db(terminfo::Database::from_env().ok())
hints
} }
} }
@ -164,11 +164,7 @@ impl Capabilities {
/// This function inspects the environment variables to build /// This function inspects the environment variables to build
/// up configuration hints. /// up configuration hints.
pub fn new_from_env() -> Result<Self, Error> { pub fn new_from_env() -> Result<Self, Error> {
Self::new_with_hints( Self::new_with_hints(ProbeHints::new_from_env())
ProbeHintsBuilder::new_from_env()
.build()
.map_err(Error::msg)?,
)
} }
/// Build a `Capabilities` object based on the provided `ProbeHints` object. /// Build a `Capabilities` object based on the provided `ProbeHints` object.
@ -330,8 +326,7 @@ mod test {
#[test] #[test]
fn empty_hint() { fn empty_hint() {
let caps = let caps = Capabilities::new_with_hints(ProbeHints::default()).unwrap();
Capabilities::new_with_hints(ProbeHintsBuilder::default().build().unwrap()).unwrap();
assert_eq!(caps.color_level(), ColorLevel::Sixteen); assert_eq!(caps.color_level(), ColorLevel::Sixteen);
assert_eq!(caps.sixel(), false); assert_eq!(caps.sixel(), false);
@ -342,65 +337,45 @@ mod test {
#[test] #[test]
fn bce() { fn bce() {
let caps = Capabilities::new_with_hints( let caps =
ProbeHintsBuilder::default() Capabilities::new_with_hints(ProbeHints::default().colorterm_bce(Some("1".into())))
.colorterm_bce(Some("1".into())) .unwrap();
.build()
.unwrap(),
)
.unwrap();
assert_eq!(caps.bce(), true); assert_eq!(caps.bce(), true);
} }
#[test] #[test]
fn bce_terminfo() { fn bce_terminfo() {
let caps = Capabilities::new_with_hints( let caps =
ProbeHintsBuilder::default() Capabilities::new_with_hints(ProbeHints::default().terminfo_db(Some(load_terminfo())))
.terminfo_db(Some(load_terminfo())) .unwrap();
.build()
.unwrap(),
)
.unwrap();
assert_eq!(caps.bce(), true); assert_eq!(caps.bce(), true);
} }
#[test] #[test]
fn terminfo_color() { fn terminfo_color() {
let caps = Capabilities::new_with_hints( let caps =
ProbeHintsBuilder::default() Capabilities::new_with_hints(ProbeHints::default().terminfo_db(Some(load_terminfo())))
.terminfo_db(Some(load_terminfo())) .unwrap();
.build()
.unwrap(),
)
.unwrap();
assert_eq!(caps.color_level(), ColorLevel::TrueColor); assert_eq!(caps.color_level(), ColorLevel::TrueColor);
} }
#[test] #[test]
fn term_but_not_colorterm() { fn term_but_not_colorterm() {
let caps = Capabilities::new_with_hints( let caps =
ProbeHintsBuilder::default() Capabilities::new_with_hints(ProbeHints::default().term(Some("xterm-256color".into())))
.term(Some("xterm-256color".into())) .unwrap();
.build()
.unwrap(),
)
.unwrap();
assert_eq!(caps.color_level(), ColorLevel::TwoFiftySix); assert_eq!(caps.color_level(), ColorLevel::TwoFiftySix);
} }
#[test] #[test]
fn colorterm_but_no_term() { fn colorterm_but_no_term() {
let caps = Capabilities::new_with_hints( let caps =
ProbeHintsBuilder::default() Capabilities::new_with_hints(ProbeHints::default().colorterm(Some("24bit".into())))
.colorterm(Some("24bit".into())) .unwrap();
.build()
.unwrap(),
)
.unwrap();
assert_eq!(caps.color_level(), ColorLevel::TrueColor); assert_eq!(caps.color_level(), ColorLevel::TrueColor);
} }
@ -408,34 +383,28 @@ mod test {
#[test] #[test]
fn term_and_colorterm() { fn term_and_colorterm() {
let caps = Capabilities::new_with_hints( let caps = Capabilities::new_with_hints(
ProbeHintsBuilder::default() ProbeHints::default()
.term(Some("xterm-256color".into())) .term(Some("xterm-256color".into()))
// bogus value // bogus value
.colorterm(Some("24bot".into())) .colorterm(Some("24bot".into())),
.build()
.unwrap(),
) )
.unwrap(); .unwrap();
assert_eq!(caps.color_level(), ColorLevel::TwoFiftySix); assert_eq!(caps.color_level(), ColorLevel::TwoFiftySix);
let caps = Capabilities::new_with_hints( let caps = Capabilities::new_with_hints(
ProbeHintsBuilder::default() ProbeHints::default()
.term(Some("xterm-256color".into())) .term(Some("xterm-256color".into()))
.colorterm(Some("24bit".into())) .colorterm(Some("24bit".into())),
.build()
.unwrap(),
) )
.unwrap(); .unwrap();
assert_eq!(caps.color_level(), ColorLevel::TrueColor); assert_eq!(caps.color_level(), ColorLevel::TrueColor);
let caps = Capabilities::new_with_hints( let caps = Capabilities::new_with_hints(
ProbeHintsBuilder::default() ProbeHints::default()
.term(Some("xterm-256color".into())) .term(Some("xterm-256color".into()))
.colorterm(Some("truecolor".into())) .colorterm(Some("truecolor".into())),
.build()
.unwrap(),
) )
.unwrap(); .unwrap();
@ -445,41 +414,33 @@ mod test {
#[test] #[test]
fn iterm2_image() { fn iterm2_image() {
let caps = Capabilities::new_with_hints( let caps = Capabilities::new_with_hints(
ProbeHintsBuilder::default() ProbeHints::default()
.term_program(Some("iTerm.app".into())) .term_program(Some("iTerm.app".into()))
.term_program_version(Some("1.0.0".into())) .term_program_version(Some("1.0.0".into())),
.build()
.unwrap(),
) )
.unwrap(); .unwrap();
assert_eq!(caps.iterm2_image(), false); assert_eq!(caps.iterm2_image(), false);
let caps = Capabilities::new_with_hints( let caps = Capabilities::new_with_hints(
ProbeHintsBuilder::default() ProbeHints::default()
.term_program(Some("iTerm.app".into())) .term_program(Some("iTerm.app".into()))
.term_program_version(Some("2.9.0".into())) .term_program_version(Some("2.9.0".into())),
.build()
.unwrap(),
) )
.unwrap(); .unwrap();
assert_eq!(caps.iterm2_image(), false); assert_eq!(caps.iterm2_image(), false);
let caps = Capabilities::new_with_hints( let caps = Capabilities::new_with_hints(
ProbeHintsBuilder::default() ProbeHints::default()
.term_program(Some("iTerm.app".into())) .term_program(Some("iTerm.app".into()))
.term_program_version(Some("2.9.20150512".into())) .term_program_version(Some("2.9.20150512".into())),
.build()
.unwrap(),
) )
.unwrap(); .unwrap();
assert_eq!(caps.iterm2_image(), true); assert_eq!(caps.iterm2_image(), true);
let caps = Capabilities::new_with_hints( let caps = Capabilities::new_with_hints(
ProbeHintsBuilder::default() ProbeHints::default()
.term_program(Some("iTerm.app".into())) .term_program(Some("iTerm.app".into()))
.term_program_version(Some("3.2.0beta5".into())) .term_program_version(Some("3.2.0beta5".into())),
.build()
.unwrap(),
) )
.unwrap(); .unwrap();
assert_eq!(caps.iterm2_image(), true); assert_eq!(caps.iterm2_image(), true);

View File

@ -46,6 +46,7 @@ pub mod input;
pub mod istty; pub mod istty;
pub mod keymap; pub mod keymap;
pub mod lineedit; pub mod lineedit;
mod macros;
mod readbuf; mod readbuf;
pub mod render; pub mod render;
pub mod surface; pub mod surface;

View File

@ -34,12 +34,11 @@
//! Ctrl-W | Delete word leading up to cursor //! Ctrl-W | Delete word leading up to cursor
//! Alt-b, Alt-Left | Move the cursor backwards one word //! Alt-b, Alt-Left | Move the cursor backwards one word
//! Alt-f, Alt-Right | Move the cursor forwards one word //! Alt-f, Alt-Right | Move the cursor forwards one word
use crate::caps::{Capabilities, ProbeHintsBuilder}; use crate::caps::{Capabilities, ProbeHints};
use crate::cell::unicode_column_width; use crate::cell::unicode_column_width;
use crate::input::{InputEvent, KeyCode, KeyEvent, Modifiers}; use crate::input::{InputEvent, KeyCode, KeyEvent, Modifiers};
use crate::surface::{Change, Position}; use crate::surface::{Change, Position};
use crate::terminal::{new_terminal, Terminal}; use crate::terminal::{new_terminal, Terminal};
use anyhow::Error;
use unicode_segmentation::GraphemeCursor; use unicode_segmentation::GraphemeCursor;
mod actions; mod actions;
@ -118,14 +117,12 @@ impl<T: Terminal> LineEditor<T> {
/// editor: /// editor:
/// ///
/// ```no_run /// ```no_run
/// use termwiz::caps::{Capabilities, ProbeHintsBuilder}; /// use termwiz::caps::{Capabilities, ProbeHints};
/// use termwiz::terminal::new_terminal; /// use termwiz::terminal::new_terminal;
/// use anyhow::Error; /// use anyhow::Error;
/// // Disable mouse input in the line editor /// // Disable mouse input in the line editor
/// let hints = ProbeHintsBuilder::new_from_env() /// let hints = ProbeHints::new_from_env()
/// .mouse_reporting(Some(false)) /// .mouse_reporting(Some(false));
/// .build()
/// .map_err(Error::msg)?;
/// let caps = Capabilities::new_with_hints(hints)?; /// let caps = Capabilities::new_with_hints(hints)?;
/// let terminal = new_terminal(caps)?; /// let terminal = new_terminal(caps)?;
/// # Ok::<(), Error>(()) /// # Ok::<(), Error>(())
@ -561,10 +558,7 @@ impl<T: Terminal> LineEditor<T> {
/// Create a `Terminal` with the recommended settings, and use that /// Create a `Terminal` with the recommended settings, and use that
/// to create a `LineEditor` instance. /// to create a `LineEditor` instance.
pub fn line_editor() -> anyhow::Result<LineEditor<impl Terminal>> { pub fn line_editor() -> anyhow::Result<LineEditor<impl Terminal>> {
let hints = ProbeHintsBuilder::new_from_env() let hints = ProbeHints::new_from_env().mouse_reporting(Some(false));
.mouse_reporting(Some(false))
.build()
.map_err(Error::msg)?;
let caps = Capabilities::new_with_hints(hints)?; let caps = Capabilities::new_with_hints(hints)?;
let terminal = new_terminal(caps)?; let terminal = new_terminal(caps)?;
Ok(LineEditor::new(terminal)) Ok(LineEditor::new(terminal))

30
termwiz/src/macros.rs Normal file
View File

@ -0,0 +1,30 @@
#[doc(hidden)]
#[macro_export]
macro_rules! builder {
(
$( #[ $( $meta:tt )* ] )*
$vis:vis struct $name:ident {
$(
$( #[doc=$doc:expr] )*
$field:ident : $type:ty,
)*
}
) => {
$( #[ $( $meta )* ] )*
$vis struct $name {
$(
$( #[doc=$doc] )*
$field : $type,
)*
}
impl $name {
$(
pub fn $field(mut self, value: $type) -> Self {
self.$field = value;
self
}
)*
}
}
}

View File

@ -671,7 +671,7 @@ impl TerminfoRenderer {
#[cfg(all(test, unix))] #[cfg(all(test, unix))]
mod test { mod test {
use super::*; use super::*;
use crate::caps::ProbeHintsBuilder; use crate::caps::ProbeHints;
use crate::color::{AnsiColor, ColorAttribute, RgbColor}; use crate::color::{AnsiColor, ColorAttribute, RgbColor};
use crate::escape::parser::Parser; use crate::escape::parser::Parser;
use crate::escape::{Action, Esc, EscCode}; use crate::escape::{Action, Esc, EscCode};
@ -692,25 +692,15 @@ mod test {
// Load our own compiled data so that the tests have an // Load our own compiled data so that the tests have an
// environment that doesn't vary machine by machine. // environment that doesn't vary machine by machine.
let data = include_bytes!("../../data/xterm-256color"); let data = include_bytes!("../../data/xterm-256color");
Capabilities::new_with_hints( Capabilities::new_with_hints(ProbeHints::default().terminfo_db(Some(
ProbeHintsBuilder::default() terminfo::Database::from_buffer(data.as_ref()).unwrap(),
.terminfo_db(Some( )))
terminfo::Database::from_buffer(data.as_ref()).unwrap(),
))
.build()
.unwrap(),
)
.unwrap() .unwrap()
} }
fn no_terminfo_all_enabled() -> Capabilities { fn no_terminfo_all_enabled() -> Capabilities {
Capabilities::new_with_hints( Capabilities::new_with_hints(ProbeHints::default().color_level(Some(ColorLevel::TrueColor)))
ProbeHintsBuilder::default() .unwrap()
.color_level(Some(ColorLevel::TrueColor))
.build()
.unwrap(),
)
.unwrap()
} }
struct FakeTty { struct FakeTty {