mirror of
https://github.com/wez/wezterm.git
synced 2024-12-22 12:51:31 +03:00
config: cut over to wezterm-dynamic
Avoid using serde for mapping between Lua and Rust for the `Config` struct. This improves the build speed of the config crate by 2x; it goes down from 30 seconds to 9 seconds on my 5950x.
This commit is contained in:
parent
24c6830345
commit
f587cac145
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -672,6 +672,7 @@ dependencies = [
|
||||
"umask",
|
||||
"unicode-segmentation",
|
||||
"wezterm-bidi",
|
||||
"wezterm-dynamic",
|
||||
"wezterm-input-types",
|
||||
"wezterm-ssh",
|
||||
"wezterm-term",
|
||||
@ -2024,6 +2025,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"strsim 0.10.0",
|
||||
"thiserror",
|
||||
"wezterm-dynamic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2287,6 +2289,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"unicode-segmentation",
|
||||
"url",
|
||||
"wezterm-dynamic",
|
||||
"wezterm-ssh",
|
||||
"wezterm-term",
|
||||
"winapi 0.3.9",
|
||||
@ -4086,6 +4089,7 @@ dependencies = [
|
||||
"vtparse",
|
||||
"wezterm-bidi",
|
||||
"wezterm-color-types",
|
||||
"wezterm-dynamic",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
@ -4654,6 +4658,7 @@ dependencies = [
|
||||
"k9",
|
||||
"log",
|
||||
"serde",
|
||||
"wezterm-dynamic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4703,8 +4708,10 @@ dependencies = [
|
||||
name = "wezterm-dynamic"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"maplit",
|
||||
"ordered-float",
|
||||
"strsim 0.10.0",
|
||||
"thiserror",
|
||||
"wezterm-dynamic-derive",
|
||||
]
|
||||
@ -4817,6 +4824,7 @@ dependencies = [
|
||||
"walkdir",
|
||||
"wezterm-bidi",
|
||||
"wezterm-client",
|
||||
"wezterm-dynamic",
|
||||
"wezterm-font",
|
||||
"wezterm-gui-subcommands",
|
||||
"wezterm-mux-server-impl",
|
||||
@ -4845,6 +4853,7 @@ dependencies = [
|
||||
"euclid",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
"wezterm-dynamic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4953,6 +4962,7 @@ dependencies = [
|
||||
"unicode-width",
|
||||
"url",
|
||||
"wezterm-bidi",
|
||||
"wezterm-dynamic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -14,6 +14,7 @@ use_serde = ["serde"]
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
serde = {version="1.0", features = ["derive"], optional=true}
|
||||
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
||||
|
||||
[dev-dependencies]
|
||||
k9 = "0.11.0"
|
||||
|
@ -3,6 +3,7 @@ use level_stack::{LevelStack, Override};
|
||||
use log::trace;
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Range;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
mod bidi_brackets;
|
||||
mod bidi_class;
|
||||
@ -20,7 +21,7 @@ use serde::{Deserialize, Serialize};
|
||||
/// Placeholder codepoint index that corresponds to NO_LEVEL
|
||||
const DELETED: usize = usize::max_value();
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
pub enum ParagraphDirectionHint {
|
||||
LeftToRight,
|
||||
|
@ -41,6 +41,7 @@ termwiz = { path = "../termwiz", features=["use_serde"] }
|
||||
toml = "0.5"
|
||||
umask = { path = "../umask" }
|
||||
unicode-segmentation = "1.8"
|
||||
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
||||
wezterm-bidi = { path = "../bidi", features=["use_serde"] }
|
||||
wezterm-input-types = { path = "../wezterm-input-types" }
|
||||
wezterm-ssh = { path = "../wezterm-ssh" }
|
||||
|
@ -1,7 +1,7 @@
|
||||
use luahelper::impl_lua_conversion;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use luahelper::impl_lua_conversion_dynamic;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||
#[derive(Debug, Copy, Clone, FromDynamic, ToDynamic)]
|
||||
pub enum Interpolation {
|
||||
Linear,
|
||||
Basis,
|
||||
@ -14,7 +14,7 @@ impl Default for Interpolation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||
#[derive(Debug, Copy, Clone, FromDynamic, ToDynamic)]
|
||||
pub enum BlendMode {
|
||||
Rgb,
|
||||
LinearRgb,
|
||||
@ -28,7 +28,7 @@ impl Default for BlendMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||
#[derive(Debug, Copy, Clone, FromDynamic, ToDynamic)]
|
||||
pub enum GradientOrientation {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
@ -45,7 +45,7 @@ impl Default for GradientOrientation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||
#[derive(Debug, Copy, Clone, FromDynamic, ToDynamic)]
|
||||
pub enum GradientPreset {
|
||||
Blues,
|
||||
BrBg,
|
||||
@ -132,34 +132,33 @@ impl GradientPreset {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct Gradient {
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub orientation: GradientOrientation,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub colors: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub preset: Option<GradientPreset>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub interpolation: Interpolation,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub blend: BlendMode,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub segment_size: Option<usize>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub segment_smoothness: Option<f64>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub noise: Option<usize>,
|
||||
}
|
||||
|
||||
impl_lua_conversion!(Gradient);
|
||||
impl_lua_conversion_dynamic!(Gradient);
|
||||
|
||||
impl Gradient {
|
||||
pub fn build(&self) -> anyhow::Result<colorgrad::Gradient> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::*;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
/// <https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function>
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, FromDynamic, ToDynamic)]
|
||||
pub enum EasingFunction {
|
||||
Linear,
|
||||
CubicBezier(f32, f32, f32, f32),
|
||||
@ -11,7 +11,6 @@ pub enum EasingFunction {
|
||||
EaseOut,
|
||||
Constant,
|
||||
}
|
||||
impl_lua_conversion!(EasingFunction);
|
||||
|
||||
impl EasingFunction {
|
||||
pub fn evaluate_at_position(&self, position: f32) -> f32 {
|
||||
@ -40,27 +39,25 @@ impl Default for EasingFunction {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct VisualBell {
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub fade_in_duration_ms: u64,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub fade_in_function: EasingFunction,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub fade_out_duration_ms: u64,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub fade_out_function: EasingFunction,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub target: VisualBellTarget,
|
||||
}
|
||||
impl_lua_conversion!(VisualBell);
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum VisualBellTarget {
|
||||
BackgroundColor,
|
||||
CursorColor,
|
||||
}
|
||||
impl_lua_conversion!(VisualBellTarget);
|
||||
|
||||
impl Default for VisualBellTarget {
|
||||
fn default() -> VisualBellTarget {
|
||||
@ -68,12 +65,11 @@ impl Default for VisualBellTarget {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub enum AudibleBell {
|
||||
SystemBeep,
|
||||
Disabled,
|
||||
}
|
||||
impl_lua_conversion!(AudibleBell);
|
||||
|
||||
impl Default for AudibleBell {
|
||||
fn default() -> AudibleBell {
|
||||
|
@ -1,17 +1,19 @@
|
||||
use crate::lua::{format_as_escapes, FormatItem};
|
||||
use crate::*;
|
||||
use luahelper::impl_lua_conversion;
|
||||
use luahelper::impl_lua_conversion_dynamic;
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
use termwiz::cell::CellAttributes;
|
||||
pub use termwiz::color::{ColorSpec, RgbColor, SrgbaTuple};
|
||||
use wezterm_dynamic::{FromDynamic, FromDynamicOptions, ToDynamic, Value};
|
||||
|
||||
#[derive(Debug, Copy, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Copy, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct HsbTransform {
|
||||
#[serde(default = "default_one_point_oh")]
|
||||
#[dynamic(default = "default_one_point_oh")]
|
||||
pub hue: f32,
|
||||
#[serde(default = "default_one_point_oh")]
|
||||
#[dynamic(default = "default_one_point_oh")]
|
||||
pub saturation: f32,
|
||||
#[serde(default = "default_one_point_oh")]
|
||||
#[dynamic(default = "default_one_point_oh")]
|
||||
pub brightness: f32,
|
||||
}
|
||||
|
||||
@ -25,30 +27,56 @@ impl Default for HsbTransform {
|
||||
}
|
||||
}
|
||||
|
||||
fn de_indexed<'de, D>(deserializer: D) -> Result<HashMap<u8, RgbaColor>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
#[derive(Deserialize)]
|
||||
struct Wrap(HashMap<String, RgbaColor>);
|
||||
let Wrap(map) = Wrap::deserialize(deserializer)?;
|
||||
struct IndexedMap(HashMap<String, RgbaColor>);
|
||||
|
||||
Ok(map
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| match k.parse::<u8>() {
|
||||
Ok(n) if n >= 16 => Some((n, v)),
|
||||
_ => {
|
||||
log::warn!("Ignoring invalid color key {}", k);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
impl ToDynamic for IndexedMap {
|
||||
fn to_dynamic(&self) -> Value {
|
||||
self.0.to_dynamic()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[serde(try_from = "String", into = "String")]
|
||||
impl FromDynamic for IndexedMap {
|
||||
fn from_dynamic(
|
||||
value: &Value,
|
||||
options: FromDynamicOptions,
|
||||
) -> Result<Self, wezterm_dynamic::Error> {
|
||||
let inner = <HashMap<String, RgbaColor>>::from_dynamic(value, options)?;
|
||||
Ok(Self(inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&HashMap<u8, RgbaColor>> for IndexedMap {
|
||||
fn from(map: &HashMap<u8, RgbaColor>) -> IndexedMap {
|
||||
IndexedMap(
|
||||
map.iter()
|
||||
.map(|(k, v)| (k.to_string(), v.clone()))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<IndexedMap> for HashMap<u8, RgbaColor> {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(map: IndexedMap) -> Result<HashMap<u8, RgbaColor>, String> {
|
||||
Ok(map
|
||||
.0
|
||||
.into_iter()
|
||||
.filter_map(|(k, v)| match k.parse::<u8>() {
|
||||
Ok(n) if n >= 16 => Some((n, v)),
|
||||
_ => {
|
||||
log::warn!("Ignoring invalid color key {}", k);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, FromDynamic, ToDynamic)]
|
||||
#[dynamic(try_from = "String", into = "String")]
|
||||
pub struct RgbaColor {
|
||||
#[serde(flatten)]
|
||||
#[dynamic(flatten)]
|
||||
color: SrgbaTuple,
|
||||
}
|
||||
|
||||
@ -67,6 +95,12 @@ impl std::ops::Deref for RgbaColor {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for &RgbaColor {
|
||||
fn into(self) -> String {
|
||||
self.color.to_rgb_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for RgbaColor {
|
||||
fn into(self) -> String {
|
||||
self.color.to_rgb_string()
|
||||
@ -89,7 +123,7 @@ impl std::convert::TryFrom<String> for RgbaColor {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct Palette {
|
||||
/// The text color to use when the attributes are reset to default
|
||||
pub foreground: Option<RgbaColor>,
|
||||
@ -109,7 +143,7 @@ pub struct Palette {
|
||||
pub brights: Option<[RgbaColor; 8]>,
|
||||
/// A map for setting arbitrary colors ranging from 16 to 256 in the color
|
||||
/// palette
|
||||
#[serde(default, deserialize_with = "de_indexed")]
|
||||
#[dynamic(default, try_from = "IndexedMap", into = "IndexedMap")]
|
||||
pub indexed: HashMap<u8, RgbaColor>,
|
||||
/// Configure the colors and styling of the tab bar
|
||||
pub tab_bar: Option<TabBarColors>,
|
||||
@ -124,7 +158,7 @@ pub struct Palette {
|
||||
/// The color to use for the cursor when a dead key or leader state is active
|
||||
pub compose_cursor: Option<RgbaColor>,
|
||||
}
|
||||
impl_lua_conversion!(Palette);
|
||||
impl_lua_conversion_dynamic!(Palette);
|
||||
|
||||
impl From<Palette> for wezterm_term::color::ColorPalette {
|
||||
fn from(cfg: Palette) -> wezterm_term::color::ColorPalette {
|
||||
@ -164,26 +198,25 @@ impl From<Palette> for wezterm_term::color::ColorPalette {
|
||||
}
|
||||
|
||||
/// Specify the text styling for a tab in the tab bar
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Default)]
|
||||
#[derive(Debug, Clone, Default, FromDynamic, ToDynamic)]
|
||||
pub struct TabBarColor {
|
||||
/// Specifies the intensity attribute for the tab title text
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub intensity: wezterm_term::Intensity,
|
||||
/// Specifies the underline attribute for the tab title text
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub underline: wezterm_term::Underline,
|
||||
/// Specifies the italic attribute for the tab title text
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub italic: bool,
|
||||
/// Specifies the strikethrough attribute for the tab title text
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub strikethrough: bool,
|
||||
/// The background color for the tab
|
||||
pub bg_color: RgbColor,
|
||||
/// The forgeground/text color for the tab
|
||||
pub fg_color: RgbColor,
|
||||
}
|
||||
impl_lua_conversion!(TabBarColor);
|
||||
|
||||
impl TabBarColor {
|
||||
pub fn as_cell_attributes(&self) -> CellAttributes {
|
||||
@ -201,39 +234,38 @@ impl TabBarColor {
|
||||
/// Specifies the colors to use for the tab bar portion of the UI.
|
||||
/// These are not part of the terminal model and cannot be updated
|
||||
/// in the same way that the dynamic color schemes are.
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct TabBarColors {
|
||||
/// The background color for the tab bar
|
||||
#[serde(default = "default_background")]
|
||||
#[dynamic(default = "default_background")]
|
||||
pub background: RgbColor,
|
||||
|
||||
/// Styling for the active tab
|
||||
#[serde(default = "default_active_tab")]
|
||||
#[dynamic(default = "default_active_tab")]
|
||||
pub active_tab: TabBarColor,
|
||||
|
||||
/// Styling for other inactive tabs
|
||||
#[serde(default = "default_inactive_tab")]
|
||||
#[dynamic(default = "default_inactive_tab")]
|
||||
pub inactive_tab: TabBarColor,
|
||||
|
||||
/// Styling for an inactive tab with a mouse hovering
|
||||
#[serde(default = "default_inactive_tab_hover")]
|
||||
#[dynamic(default = "default_inactive_tab_hover")]
|
||||
pub inactive_tab_hover: TabBarColor,
|
||||
|
||||
/// Styling for the new tab button
|
||||
#[serde(default = "default_inactive_tab")]
|
||||
#[dynamic(default = "default_inactive_tab")]
|
||||
pub new_tab: TabBarColor,
|
||||
|
||||
/// Styling for the new tab button with a mouse hovering
|
||||
#[serde(default = "default_inactive_tab_hover")]
|
||||
#[dynamic(default = "default_inactive_tab_hover")]
|
||||
pub new_tab_hover: TabBarColor,
|
||||
|
||||
#[serde(default = "default_inactive_tab_edge")]
|
||||
#[dynamic(default = "default_inactive_tab_edge")]
|
||||
pub inactive_tab_edge: RgbaColor,
|
||||
|
||||
#[serde(default = "default_inactive_tab_edge_hover")]
|
||||
#[dynamic(default = "default_inactive_tab_edge_hover")]
|
||||
pub inactive_tab_edge_hover: RgbaColor,
|
||||
}
|
||||
impl_lua_conversion!(TabBarColors);
|
||||
|
||||
fn default_background() -> RgbColor {
|
||||
RgbColor::new_8bpc(0x33, 0x33, 0x33)
|
||||
@ -285,11 +317,11 @@ impl Default for TabBarColors {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct TabBarStyle {
|
||||
#[serde(default = "default_new_tab")]
|
||||
#[dynamic(default = "default_new_tab")]
|
||||
pub new_tab: String,
|
||||
#[serde(default = "default_new_tab")]
|
||||
#[dynamic(default = "default_new_tab")]
|
||||
pub new_tab_hover: String,
|
||||
}
|
||||
|
||||
@ -306,32 +338,32 @@ fn default_new_tab() -> String {
|
||||
format_as_escapes(vec![FormatItem::Text(" + ".to_string())]).unwrap()
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct WindowFrameConfig {
|
||||
#[serde(default = "default_inactive_titlebar_bg")]
|
||||
#[dynamic(default = "default_inactive_titlebar_bg")]
|
||||
pub inactive_titlebar_bg: RgbColor,
|
||||
#[serde(default = "default_active_titlebar_bg")]
|
||||
#[dynamic(default = "default_active_titlebar_bg")]
|
||||
pub active_titlebar_bg: RgbColor,
|
||||
#[serde(default = "default_inactive_titlebar_fg")]
|
||||
#[dynamic(default = "default_inactive_titlebar_fg")]
|
||||
pub inactive_titlebar_fg: RgbColor,
|
||||
#[serde(default = "default_active_titlebar_fg")]
|
||||
#[dynamic(default = "default_active_titlebar_fg")]
|
||||
pub active_titlebar_fg: RgbColor,
|
||||
#[serde(default = "default_inactive_titlebar_border_bottom")]
|
||||
#[dynamic(default = "default_inactive_titlebar_border_bottom")]
|
||||
pub inactive_titlebar_border_bottom: RgbColor,
|
||||
#[serde(default = "default_active_titlebar_border_bottom")]
|
||||
#[dynamic(default = "default_active_titlebar_border_bottom")]
|
||||
pub active_titlebar_border_bottom: RgbColor,
|
||||
#[serde(default = "default_button_fg")]
|
||||
#[dynamic(default = "default_button_fg")]
|
||||
pub button_fg: RgbColor,
|
||||
#[serde(default = "default_button_bg")]
|
||||
#[dynamic(default = "default_button_bg")]
|
||||
pub button_bg: RgbColor,
|
||||
#[serde(default = "default_button_hover_fg")]
|
||||
#[dynamic(default = "default_button_hover_fg")]
|
||||
pub button_hover_fg: RgbColor,
|
||||
#[serde(default = "default_button_hover_bg")]
|
||||
#[dynamic(default = "default_button_hover_bg")]
|
||||
pub button_hover_bg: RgbColor,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font: Option<TextStyle>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font_size: Option<f64>,
|
||||
}
|
||||
|
||||
@ -394,9 +426,20 @@ fn default_button_bg() -> RgbColor {
|
||||
RgbColor::new_8bpc(0x33, 0x33, 0x33)
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct ColorSchemeFile {
|
||||
/// The color palette
|
||||
pub colors: Palette,
|
||||
}
|
||||
impl_lua_conversion!(ColorSchemeFile);
|
||||
|
||||
impl ColorSchemeFile {
|
||||
pub fn from_toml_value(value: &toml::Value) -> anyhow::Result<Self> {
|
||||
Self::from_dynamic(&crate::toml_to_dynamic(value), Default::default())
|
||||
.map_err(|e| anyhow::anyhow!("{}", e))
|
||||
}
|
||||
|
||||
pub fn from_toml_str(s: &str) -> anyhow::Result<Self> {
|
||||
let scheme: toml::Value = toml::from_str(s)?;
|
||||
ColorSchemeFile::from_toml_value(&scheme)
|
||||
}
|
||||
}
|
||||
|
@ -14,18 +14,18 @@ use crate::keys::{Key, LeaderKey, Mouse};
|
||||
use crate::lua::make_lua_context;
|
||||
use crate::ssh::{SshBackend, SshDomain};
|
||||
use crate::tls::{TlsDomainClient, TlsDomainServer};
|
||||
use crate::units::{de_pixels, Dimension};
|
||||
use crate::units::Dimension;
|
||||
use crate::unix::UnixDomain;
|
||||
use crate::wsl::WslDomain;
|
||||
use crate::{
|
||||
de_number, de_vec_table, default_config_with_overrides_applied, default_one_point_oh,
|
||||
default_one_point_oh_f64, default_true, KeyMapPreference, LoadedConfig, CONFIG_DIR,
|
||||
CONFIG_FILE_OVERRIDE, CONFIG_OVERRIDES, CONFIG_SKIP, HOME_DIR,
|
||||
default_config_with_overrides_applied, default_one_point_oh, default_one_point_oh_f64,
|
||||
default_true, KeyMapPreference, LoadedConfig, CONFIG_DIR, CONFIG_FILE_OVERRIDE,
|
||||
CONFIG_OVERRIDES, CONFIG_SKIP, HOME_DIR,
|
||||
};
|
||||
use anyhow::Context;
|
||||
use luahelper::impl_lua_conversion;
|
||||
use luahelper::impl_lua_conversion_dynamic;
|
||||
use mlua::FromLua;
|
||||
use portable_pty::{CommandBuilder, PtySize};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::io::Read;
|
||||
@ -35,61 +35,62 @@ use std::time::Duration;
|
||||
use termwiz::hyperlink;
|
||||
use termwiz::surface::CursorShape;
|
||||
use wezterm_bidi::ParagraphDirectionHint;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
use wezterm_input_types::{Modifiers, WindowDecorations};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct Config {
|
||||
/// The font size, measured in points
|
||||
#[serde(default = "default_font_size", deserialize_with = "de_number")]
|
||||
#[dynamic(default = "default_font_size")]
|
||||
pub font_size: f64,
|
||||
|
||||
#[serde(default = "default_one_point_oh_f64")]
|
||||
#[dynamic(default = "default_one_point_oh_f64")]
|
||||
pub line_height: f64,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub allow_square_glyphs_to_overflow_width: AllowSquareGlyphOverflow,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub window_decorations: WindowDecorations,
|
||||
|
||||
/// When using FontKitXXX font systems, a set of directories to
|
||||
/// search ahead of the standard font locations for fonts.
|
||||
/// Relative paths are taken to be relative to the directory
|
||||
/// from which the config was loaded.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font_dirs: Vec<PathBuf>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub color_scheme_dirs: Vec<PathBuf>,
|
||||
|
||||
/// The DPI to assume
|
||||
pub dpi: Option<f64>,
|
||||
|
||||
/// The baseline font to use
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font: TextStyle,
|
||||
|
||||
/// An optional set of style rules to select the font based
|
||||
/// on the cell attributes
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font_rules: Vec<StyleRule>,
|
||||
|
||||
/// When true (the default), PaletteIndex 0-7 are shifted to
|
||||
/// bright when the font intensity is bold. The brightening
|
||||
/// doesn't apply to text that is the default color.
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub bold_brightens_ansi_colors: bool,
|
||||
|
||||
/// The color palette
|
||||
pub colors: Option<Palette>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub window_frame: WindowFrameConfig,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub tab_bar_style: TabBarStyle,
|
||||
|
||||
#[serde(skip)]
|
||||
#[dynamic(default)]
|
||||
pub resolved_palette: Palette,
|
||||
|
||||
/// Use a named color scheme rather than the palette specified
|
||||
@ -97,11 +98,11 @@ pub struct Config {
|
||||
pub color_scheme: Option<String>,
|
||||
|
||||
/// Named color schemes
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub color_schemes: HashMap<String, Palette>,
|
||||
|
||||
/// How many lines of scrollback you want to retain
|
||||
#[serde(default = "default_scrollback_lines")]
|
||||
#[dynamic(default = "default_scrollback_lines")]
|
||||
pub scrollback_lines: usize,
|
||||
|
||||
/// If no `prog` is specified on the command line, use this
|
||||
@ -118,7 +119,7 @@ pub struct Config {
|
||||
/// as the positional arguments to that command.
|
||||
pub default_prog: Option<Vec<String>>,
|
||||
|
||||
#[serde(default = "default_gui_startup_args")]
|
||||
#[dynamic(default = "default_gui_startup_args")]
|
||||
pub default_gui_startup_args: Vec<String>,
|
||||
|
||||
/// Specifies the default current working directory if none is specified
|
||||
@ -126,48 +127,48 @@ pub struct Config {
|
||||
/// info!)
|
||||
pub default_cwd: Option<PathBuf>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub exit_behavior: ExitBehavior,
|
||||
|
||||
#[serde(default = "default_clean_exits")]
|
||||
#[dynamic(default = "default_clean_exits")]
|
||||
pub clean_exit_codes: Vec<u32>,
|
||||
|
||||
/// Specifies a map of environment variables that should be set
|
||||
/// when spawning commands in the local domain.
|
||||
/// This is not used when working with remote domains.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub set_environment_variables: HashMap<String, String>,
|
||||
|
||||
/// Specifies the height of a new window, expressed in character cells.
|
||||
#[serde(default = "default_initial_rows")]
|
||||
#[dynamic(default = "default_initial_rows")]
|
||||
pub initial_rows: u16,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub enable_kitty_graphics: bool,
|
||||
|
||||
/// Specifies the width of a new window, expressed in character cells
|
||||
#[serde(default = "default_initial_cols")]
|
||||
#[dynamic(default = "default_initial_cols")]
|
||||
pub initial_cols: u16,
|
||||
|
||||
#[serde(default = "default_hyperlink_rules")]
|
||||
#[dynamic(default = "default_hyperlink_rules")]
|
||||
pub hyperlink_rules: Vec<hyperlink::Rule>,
|
||||
|
||||
/// What to set the TERM variable to
|
||||
#[serde(default = "default_term")]
|
||||
#[dynamic(default = "default_term")]
|
||||
pub term: String,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font_locator: FontLocatorSelection,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font_rasterizer: FontRasterizerSelection,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font_shaper: FontShaperSelection,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_load_target: FreeTypeLoadTarget,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_render_target: Option<FreeTypeLoadTarget>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_load_flags: FreeTypeLoadFlags,
|
||||
|
||||
/// Selects the freetype interpret version to use.
|
||||
@ -209,32 +210,32 @@ pub struct Config {
|
||||
/// # when using the Fira Code font
|
||||
/// harfbuzz_features = ["zero"]
|
||||
/// ```
|
||||
#[serde(default = "default_harfbuzz_features")]
|
||||
#[dynamic(default = "default_harfbuzz_features")]
|
||||
pub harfbuzz_features: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub front_end: FrontEndSelection,
|
||||
|
||||
#[serde(default = "WslDomain::default_domains")]
|
||||
#[dynamic(default = "WslDomain::default_domains")]
|
||||
pub wsl_domains: Vec<WslDomain>,
|
||||
|
||||
/// The set of unix domains
|
||||
#[serde(default = "UnixDomain::default_unix_domains")]
|
||||
#[dynamic(default = "UnixDomain::default_unix_domains")]
|
||||
pub unix_domains: Vec<UnixDomain>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub ssh_domains: Vec<SshDomain>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub ssh_backend: SshBackend,
|
||||
|
||||
/// When running in server mode, defines configuration for
|
||||
/// each of the endpoints that we'll listen for connections
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub tls_servers: Vec<TlsDomainServer>,
|
||||
|
||||
/// The set of tls domains that we can connect to as a client
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub tls_clients: Vec<TlsDomainClient>,
|
||||
|
||||
/// Constrains the rate at which the multiplexer client will
|
||||
@ -242,98 +243,95 @@ pub struct Config {
|
||||
/// This helps to avoid saturating the link between the client
|
||||
/// and server if the server is dumping a large amount of output
|
||||
/// to the client.
|
||||
#[serde(default = "default_ratelimit_line_prefetches_per_second")]
|
||||
#[dynamic(default = "default_ratelimit_line_prefetches_per_second")]
|
||||
pub ratelimit_mux_line_prefetches_per_second: u32,
|
||||
|
||||
/// The buffer size used by parse_buffered_data in the mux module.
|
||||
/// This should not be too large, otherwise the processing cost
|
||||
/// of applying a batch of actions to the terminal will be too
|
||||
/// high and the user experience will be laggy and less responsive.
|
||||
#[serde(default = "default_mux_output_parser_buffer_size")]
|
||||
#[dynamic(default = "default_mux_output_parser_buffer_size")]
|
||||
pub mux_output_parser_buffer_size: usize,
|
||||
|
||||
#[serde(default = "default_mux_env_remove", deserialize_with = "de_vec_table")]
|
||||
#[dynamic(default = "default_mux_env_remove")]
|
||||
pub mux_env_remove: Vec<String>,
|
||||
|
||||
#[serde(default, deserialize_with = "de_vec_table")]
|
||||
#[dynamic(default)]
|
||||
pub keys: Vec<Key>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub key_tables: HashMap<String, Vec<Key>>,
|
||||
|
||||
#[serde(
|
||||
default = "default_bypass_mouse_reporting_modifiers",
|
||||
deserialize_with = "crate::keys::de_modifiers"
|
||||
)]
|
||||
#[dynamic(default = "default_bypass_mouse_reporting_modifiers")]
|
||||
pub bypass_mouse_reporting_modifiers: Modifiers,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub debug_key_events: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub disable_default_key_bindings: bool,
|
||||
pub leader: Option<LeaderKey>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub disable_default_quick_select_patterns: bool,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub quick_select_patterns: Vec<String>,
|
||||
#[serde(default = "default_alphabet")]
|
||||
#[dynamic(default = "default_alphabet")]
|
||||
pub quick_select_alphabet: String,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub mouse_bindings: Vec<Mouse>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub disable_default_mouse_bindings: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub daemon_options: DaemonOptions,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub send_composed_key_when_left_alt_is_pressed: bool,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub send_composed_key_when_right_alt_is_pressed: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub treat_left_ctrlalt_as_altgr: bool,
|
||||
|
||||
/// If true, the `Backspace` and `Delete` keys generate `Delete` and `Backspace`
|
||||
/// keypresses, respectively, rather than their normal keycodes.
|
||||
/// On macOS the default for this is true because its Backspace key
|
||||
/// is labeled as Delete and things are backwards.
|
||||
#[serde(default = "default_swap_backspace_and_delete")]
|
||||
#[dynamic(default = "default_swap_backspace_and_delete")]
|
||||
pub swap_backspace_and_delete: bool,
|
||||
|
||||
/// If true, display the tab bar UI at the top of the window.
|
||||
/// The tab bar shows the titles of the tabs and which is the
|
||||
/// active tab. Clicking on a tab activates it.
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub enable_tab_bar: bool,
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub use_fancy_tab_bar: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub tab_bar_at_bottom: bool,
|
||||
|
||||
/// If true, tab bar titles are prefixed with the tab index
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub show_tab_index_in_tab_bar: bool,
|
||||
|
||||
/// If true, show_tab_index_in_tab_bar uses a zero-based index.
|
||||
/// The default is false and the tab shows a one-based index.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub tab_and_split_indices_are_zero_based: bool,
|
||||
|
||||
/// Specifies the maximum width that a tab can have in the
|
||||
/// tab bar. Defaults to 16 glyphs in width.
|
||||
#[serde(default = "default_tab_max_width")]
|
||||
#[dynamic(default = "default_tab_max_width")]
|
||||
pub tab_max_width: usize,
|
||||
|
||||
/// If true, hide the tab bar if the window only has a single tab.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub hide_tab_bar_if_only_one_tab: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub enable_scroll_bar: bool,
|
||||
|
||||
/// If false, do not try to use a Wayland protocol connection
|
||||
@ -341,23 +339,23 @@ pub struct Config {
|
||||
/// This option is only considered on X11/Wayland systems and
|
||||
/// has no effect on macOS or Windows.
|
||||
/// The default is true.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub enable_wayland: bool,
|
||||
|
||||
/// Whether to prefer EGL over other GL implementations.
|
||||
/// EGL on Windows has jankier resize behavior than WGL (which
|
||||
/// is used if EGL is unavailable), but EGL survives graphics
|
||||
/// driver updates without breaking and losing your work.
|
||||
#[serde(default = "default_prefer_egl")]
|
||||
#[dynamic(default = "default_prefer_egl")]
|
||||
pub prefer_egl: bool,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub custom_block_glyphs: bool,
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub anti_alias_custom_block_glyphs: bool,
|
||||
|
||||
/// Controls the amount of padding to use around the terminal cell area
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub window_padding: WindowPadding,
|
||||
|
||||
/// Specifies the path to a background image attachment file.
|
||||
@ -367,13 +365,13 @@ pub struct Config {
|
||||
/// of the window before any other content.
|
||||
///
|
||||
/// The image will be scaled to fit the window.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub window_background_image: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub window_background_gradient: Option<Gradient>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub window_background_image_hsb: Option<HsbTransform>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub foreground_text_hsb: HsbTransform,
|
||||
|
||||
/// Specifies the alpha value to use when rendering the background
|
||||
@ -386,7 +384,7 @@ pub struct Config {
|
||||
/// This only works on systems with a compositing window manager.
|
||||
/// Setting opacity to a value other than 1.0 can impact render
|
||||
/// performance.
|
||||
#[serde(default = "default_one_point_oh")]
|
||||
#[dynamic(default = "default_one_point_oh")]
|
||||
pub window_background_opacity: f32,
|
||||
|
||||
/// inactive_pane_hue, inactive_pane_saturation and
|
||||
@ -418,10 +416,10 @@ pub struct Config {
|
||||
/// A subtle dimming effect can be achieved by setting:
|
||||
/// inactive_pane_saturation = 0.9
|
||||
/// inactive_pane_brightness = 0.8
|
||||
#[serde(default = "default_inactive_pane_hsb")]
|
||||
#[dynamic(default = "default_inactive_pane_hsb")]
|
||||
pub inactive_pane_hsb: HsbTransform,
|
||||
|
||||
#[serde(default = "default_one_point_oh")]
|
||||
#[dynamic(default = "default_one_point_oh")]
|
||||
pub text_background_opacity: f32,
|
||||
|
||||
/// Specifies how often a blinking cursor transitions between visible
|
||||
@ -430,17 +428,17 @@ pub struct Config {
|
||||
/// Note that this value is approximate due to the way that the system
|
||||
/// event loop schedulers manage timers; non-zero values will be at
|
||||
/// least the interval specified with some degree of slop.
|
||||
#[serde(default = "default_cursor_blink_rate")]
|
||||
#[dynamic(default = "default_cursor_blink_rate")]
|
||||
pub cursor_blink_rate: u64,
|
||||
#[serde(default = "linear_ease")]
|
||||
#[dynamic(default = "linear_ease")]
|
||||
pub cursor_blink_ease_in: EasingFunction,
|
||||
#[serde(default = "linear_ease")]
|
||||
#[dynamic(default = "linear_ease")]
|
||||
pub cursor_blink_ease_out: EasingFunction,
|
||||
|
||||
#[serde(default = "default_anim_fps")]
|
||||
#[dynamic(default = "default_anim_fps")]
|
||||
pub animation_fps: u8,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub force_reverse_video_cursor: bool,
|
||||
|
||||
/// Specifies the default cursor style. various escape sequences
|
||||
@ -451,7 +449,7 @@ pub struct Config {
|
||||
/// Acceptable values are `SteadyBlock`, `BlinkingBlock`,
|
||||
/// `SteadyUnderline`, `BlinkingUnderline`, `SteadyBar`,
|
||||
/// and `BlinkingBar`.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub default_cursor_style: DefaultCursorStyle,
|
||||
|
||||
/// Specifies how often blinking text (normal speed) transitions
|
||||
@ -460,11 +458,11 @@ pub struct Config {
|
||||
/// value is approximate due to the way that the system event loop
|
||||
/// schedulers manage timers; non-zero values will be at least the
|
||||
/// interval specified with some degree of slop.
|
||||
#[serde(default = "default_text_blink_rate")]
|
||||
#[dynamic(default = "default_text_blink_rate")]
|
||||
pub text_blink_rate: u64,
|
||||
#[serde(default = "linear_ease")]
|
||||
#[dynamic(default = "linear_ease")]
|
||||
pub text_blink_ease_in: EasingFunction,
|
||||
#[serde(default = "linear_ease")]
|
||||
#[dynamic(default = "linear_ease")]
|
||||
pub text_blink_ease_out: EasingFunction,
|
||||
|
||||
/// Specifies how often blinking text (rapid speed) transitions
|
||||
@ -473,176 +471,180 @@ pub struct Config {
|
||||
/// value is approximate due to the way that the system event loop
|
||||
/// schedulers manage timers; non-zero values will be at least the
|
||||
/// interval specified with some degree of slop.
|
||||
#[serde(default = "default_text_blink_rate_rapid")]
|
||||
#[dynamic(default = "default_text_blink_rate_rapid")]
|
||||
pub text_blink_rate_rapid: u64,
|
||||
#[serde(default = "linear_ease")]
|
||||
#[dynamic(default = "linear_ease")]
|
||||
pub text_blink_rapid_ease_in: EasingFunction,
|
||||
#[serde(default = "linear_ease")]
|
||||
#[dynamic(default = "linear_ease")]
|
||||
pub text_blink_rapid_ease_out: EasingFunction,
|
||||
|
||||
/// If non-zero, specifies the period (in seconds) at which various
|
||||
/// statistics are logged. Note that there is a minimum period of
|
||||
/// 10 seconds.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub periodic_stat_logging: u64,
|
||||
|
||||
/// If false, do not scroll to the bottom of the terminal when
|
||||
/// you send input to the terminal.
|
||||
/// The default is to scroll to the bottom when you send input
|
||||
/// to the terminal.
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub scroll_to_bottom_on_input: bool,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub use_ime: bool,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub xim_im_name: Option<String>,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub use_dead_keys: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub launch_menu: Vec<SpawnCommand>,
|
||||
|
||||
/// When true, watch the config file and reload it automatically
|
||||
/// when it is detected as changing.
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub automatically_reload_config: bool,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub check_for_updates: bool,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub show_update_window: bool,
|
||||
|
||||
#[serde(default = "default_update_interval")]
|
||||
#[dynamic(default = "default_update_interval")]
|
||||
pub check_for_updates_interval_seconds: u64,
|
||||
|
||||
/// When set to true, use the CSI-U encoding scheme as described
|
||||
/// in http://www.leonerd.org.uk/hacks/fixterms/
|
||||
/// This is off by default because @wez and @jsgf find the shift-space
|
||||
/// mapping annoying in vim :-p
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub enable_csi_u_key_encoding: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub window_close_confirmation: WindowCloseConfirmation,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub native_macos_fullscreen_mode: bool,
|
||||
|
||||
#[serde(default = "default_word_boundary")]
|
||||
#[dynamic(default = "default_word_boundary")]
|
||||
pub selection_word_boundary: String,
|
||||
|
||||
#[serde(default = "default_enq_answerback")]
|
||||
#[dynamic(default = "default_enq_answerback")]
|
||||
pub enq_answerback: String,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub adjust_window_size_when_changing_font_size: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub use_resize_increments: bool,
|
||||
|
||||
#[serde(default = "default_alternate_buffer_wheel_scroll_speed")]
|
||||
#[dynamic(default = "default_alternate_buffer_wheel_scroll_speed")]
|
||||
pub alternate_buffer_wheel_scroll_speed: u8,
|
||||
|
||||
#[serde(default = "default_status_update_interval")]
|
||||
#[dynamic(default = "default_status_update_interval")]
|
||||
pub status_update_interval: u64,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub experimental_pixel_positioning: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub bidi_enabled: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub bidi_direction: ParagraphDirectionHint,
|
||||
|
||||
#[serde(default = "default_stateless_process_list")]
|
||||
#[dynamic(default = "default_stateless_process_list")]
|
||||
pub skip_close_confirmation_for_processes_named: Vec<String>,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub warn_about_missing_glyphs: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub sort_fallback_fonts_by_coverage: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub search_font_dirs_for_fallback: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub use_cap_height_to_scale_fallback_fonts: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub swallow_mouse_click_on_pane_focus: bool,
|
||||
|
||||
#[serde(default = "default_swallow_mouse_click_on_window_focus")]
|
||||
#[dynamic(default = "default_swallow_mouse_click_on_window_focus")]
|
||||
pub swallow_mouse_click_on_window_focus: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub pane_focus_follows_mouse: bool,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub unzoom_on_switch_pane: bool,
|
||||
|
||||
#[serde(default = "default_max_fps")]
|
||||
#[dynamic(default = "default_max_fps")]
|
||||
pub max_fps: u8,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub visual_bell: VisualBell,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub audible_bell: AudibleBell,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub canonicalize_pasted_newlines: Option<NewlineCanon>,
|
||||
|
||||
#[serde(default = "default_unicode_version")]
|
||||
#[dynamic(default = "default_unicode_version")]
|
||||
pub unicode_version: u8,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub treat_east_asian_ambiguous_width_as_wide: bool,
|
||||
|
||||
#[serde(default = "default_true")]
|
||||
#[dynamic(default = "default_true")]
|
||||
pub allow_download_protocols: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub allow_win32_input_mode: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub default_domain: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub default_workspace: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub xcursor_theme: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub xcursor_size: Option<u32>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub key_map_preference: KeyMapPreference,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub quote_dropped_files: DroppedFileQuoting,
|
||||
}
|
||||
impl_lua_conversion!(Config);
|
||||
impl_lua_conversion_dynamic!(Config);
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
// Ask serde to provide the defaults based on the attributes
|
||||
// Ask FromDynamic to provide the defaults based on the attributes
|
||||
// specified in the struct so that we don't have to repeat
|
||||
// the same thing in a different form down here
|
||||
toml::from_str("").unwrap()
|
||||
Config::from_dynamic(
|
||||
&wezterm_dynamic::Value::Object(Default::default()),
|
||||
Default::default(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn load() -> anyhow::Result<LoadedConfig> {
|
||||
Self::load_with_overrides(&serde_json::Value::default())
|
||||
Self::load_with_overrides(&wezterm_dynamic::Value::default())
|
||||
}
|
||||
|
||||
pub fn load_with_overrides(overrides: &serde_json::Value) -> anyhow::Result<LoadedConfig> {
|
||||
pub fn load_with_overrides(overrides: &wezterm_dynamic::Value) -> anyhow::Result<LoadedConfig> {
|
||||
// Note that the directories crate has methods for locating project
|
||||
// specific config directories, but only returns one of them, not
|
||||
// multiple. In addition, it spawns a lot of subprocesses,
|
||||
@ -707,8 +709,8 @@ impl Config {
|
||||
.eval_async(),
|
||||
)?;
|
||||
let config = Self::apply_overrides_to(&lua, config)?;
|
||||
let config = Self::apply_overrides_obj_to(config, overrides)?;
|
||||
cfg = luahelper::from_lua_value(config).with_context(|| {
|
||||
let config = Self::apply_overrides_obj_to(&lua, config, overrides)?;
|
||||
cfg = Config::from_lua(config, &lua).with_context(|| {
|
||||
format!(
|
||||
"Error converting lua value returned by script {} to Config struct",
|
||||
p.display()
|
||||
@ -746,15 +748,17 @@ impl Config {
|
||||
}
|
||||
|
||||
pub(crate) fn apply_overrides_obj_to<'l>(
|
||||
lua: &'l mlua::Lua,
|
||||
mut config: mlua::Value<'l>,
|
||||
overrides: &serde_json::Value,
|
||||
overrides: &wezterm_dynamic::Value,
|
||||
) -> anyhow::Result<mlua::Value<'l>> {
|
||||
match overrides {
|
||||
serde_json::Value::Object(obj) => {
|
||||
wezterm_dynamic::Value::Object(obj) => {
|
||||
if let mlua::Value::Table(tbl) = &mut config {
|
||||
for (key, value) in obj {
|
||||
let value = luahelper::JsonLua(value.clone());
|
||||
tbl.set(key.as_str(), value)?;
|
||||
let key = luahelper::dynamic_to_lua_value(lua, key.clone())?;
|
||||
let value = luahelper::dynamic_to_lua_value(lua, value.clone())?;
|
||||
tbl.set(key, value)?;
|
||||
}
|
||||
}
|
||||
Ok(config)
|
||||
@ -955,8 +959,7 @@ impl Config {
|
||||
|
||||
fn load_scheme(path: &Path) -> anyhow::Result<ColorSchemeFile> {
|
||||
let s = std::fs::read_to_string(path)?;
|
||||
let scheme: ColorSchemeFile = toml::from_str(&s).context("parsing TOML")?;
|
||||
Ok(scheme)
|
||||
ColorSchemeFile::from_toml_str(&s).context("parsing TOML")
|
||||
}
|
||||
|
||||
for colors_dir in paths {
|
||||
@ -1289,7 +1292,7 @@ fn default_inactive_pane_hsb() -> HsbTransform {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Copy, Debug)]
|
||||
#[derive(FromDynamic, ToDynamic, Clone, Copy, Debug)]
|
||||
pub enum DefaultCursorStyle {
|
||||
BlinkingBlock,
|
||||
SteadyBlock,
|
||||
@ -1298,7 +1301,6 @@ pub enum DefaultCursorStyle {
|
||||
BlinkingBar,
|
||||
SteadyBar,
|
||||
}
|
||||
impl_lua_conversion!(DefaultCursorStyle);
|
||||
|
||||
impl Default for DefaultCursorStyle {
|
||||
fn default() -> Self {
|
||||
@ -1334,18 +1336,17 @@ const fn default_half_cell() -> Dimension {
|
||||
Dimension::Cells(0.5)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Copy, Debug)]
|
||||
#[derive(FromDynamic, ToDynamic, Clone, Copy, Debug)]
|
||||
pub struct WindowPadding {
|
||||
#[serde(deserialize_with = "de_pixels", default = "default_one_cell")]
|
||||
#[dynamic(try_from = "crate::units::PixelUnit", default = "default_one_cell")]
|
||||
pub left: Dimension,
|
||||
#[serde(deserialize_with = "de_pixels", default = "default_half_cell")]
|
||||
#[dynamic(try_from = "crate::units::PixelUnit", default = "default_half_cell")]
|
||||
pub top: Dimension,
|
||||
#[serde(deserialize_with = "de_pixels", default = "default_one_cell")]
|
||||
#[dynamic(try_from = "crate::units::PixelUnit", default = "default_one_cell")]
|
||||
pub right: Dimension,
|
||||
#[serde(deserialize_with = "de_pixels", default = "default_half_cell")]
|
||||
#[dynamic(try_from = "crate::units::PixelUnit", default = "default_half_cell")]
|
||||
pub bottom: Dimension,
|
||||
}
|
||||
impl_lua_conversion!(WindowPadding);
|
||||
|
||||
impl Default for WindowPadding {
|
||||
fn default() -> Self {
|
||||
@ -1358,74 +1359,22 @@ impl Default for WindowPadding {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[derive(FromDynamic, ToDynamic, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum NewlineCanon {
|
||||
// FIXME: also allow deserialziing from bool
|
||||
None,
|
||||
LineFeed,
|
||||
CarriageReturn,
|
||||
CarriageReturnAndLineFeed,
|
||||
}
|
||||
impl_lua_conversion!(NewlineCanon);
|
||||
|
||||
impl<'de> Deserialize<'de> for NewlineCanon {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct Helper;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for Helper {
|
||||
type Value = NewlineCanon;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("true, false, \"None\", \"LineFeed\", \"CarriageReturnAndLineFeed\", \"CarriageReturnAndLineFeed\"")
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, value: bool) -> Result<NewlineCanon, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(if value {
|
||||
NewlineCanon::CarriageReturnAndLineFeed
|
||||
} else {
|
||||
NewlineCanon::LineFeed
|
||||
})
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
match v {
|
||||
"None" => Ok(NewlineCanon::None),
|
||||
"LineFeed" => Ok(NewlineCanon::LineFeed),
|
||||
"CarriageReturn" => Ok(NewlineCanon::CarriageReturn),
|
||||
"CarriageReturnAndLineFeed" => Ok(NewlineCanon::CarriageReturnAndLineFeed),
|
||||
_ => Err(serde::de::Error::unknown_variant(
|
||||
v,
|
||||
&[
|
||||
"None",
|
||||
"LineFeed",
|
||||
"CarriageReturn",
|
||||
"CarriageReturnAndLineFeed",
|
||||
],
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(Helper)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Copy, Debug)]
|
||||
#[derive(FromDynamic, ToDynamic, Clone, Copy, Debug)]
|
||||
pub enum WindowCloseConfirmation {
|
||||
AlwaysPrompt,
|
||||
NeverPrompt,
|
||||
// TODO: something smart where we see whether the
|
||||
// running programs are stateful
|
||||
}
|
||||
impl_lua_conversion!(WindowCloseConfirmation);
|
||||
|
||||
impl Default for WindowCloseConfirmation {
|
||||
fn default() -> Self {
|
||||
@ -1453,7 +1402,7 @@ impl PathPossibility {
|
||||
}
|
||||
|
||||
/// Behavior when the program spawned by wezterm terminates
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, FromDynamic, ToDynamic, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ExitBehavior {
|
||||
/// Close the associated pane
|
||||
Close,
|
||||
@ -1469,7 +1418,7 @@ impl Default for ExitBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, FromDynamic, ToDynamic, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DroppedFileQuoting {
|
||||
/// No quoting is performed, the file name is passed through as-is
|
||||
None,
|
||||
|
@ -1,14 +1,14 @@
|
||||
use crate::*;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::path::PathBuf;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct DaemonOptions {
|
||||
pub pid_file: Option<PathBuf>,
|
||||
pub stdout: Option<PathBuf>,
|
||||
pub stderr: Option<PathBuf>,
|
||||
}
|
||||
impl_lua_conversion!(DaemonOptions);
|
||||
|
||||
/// Set the sticky bit on path.
|
||||
/// This is used in a couple of situations where we want files that
|
||||
|
@ -2,13 +2,13 @@ use crate::color::RgbaColor;
|
||||
use crate::*;
|
||||
use bitflags::*;
|
||||
use enum_display_derive::Display;
|
||||
use luahelper::impl_lua_conversion;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use luahelper::impl_lua_conversion_dynamic;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Display;
|
||||
use wezterm_dynamic::{FromDynamic, FromDynamicOptions, ToDynamic, Value};
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, Hash, Display, PartialOrd, Ord,
|
||||
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, PartialOrd, Ord, FromDynamic, ToDynamic,
|
||||
)]
|
||||
pub enum FontStyle {
|
||||
Normal,
|
||||
@ -23,7 +23,7 @@ impl Default for FontStyle {
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, Display, PartialOrd, Ord,
|
||||
Debug, Clone, Copy, PartialEq, Eq, Hash, Display, PartialOrd, Ord, FromDynamic, ToDynamic,
|
||||
)]
|
||||
pub enum FontStretch {
|
||||
UltraCondensed,
|
||||
@ -134,56 +134,36 @@ impl FontWeight {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for FontWeight {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
impl ToDynamic for FontWeight {
|
||||
fn to_dynamic(&self) -> Value {
|
||||
match self.categorize_weight() {
|
||||
FontWeightOrLabel::Weight(n) => serializer.serialize_u16(n),
|
||||
FontWeightOrLabel::Label(l) => serializer.serialize_str(l),
|
||||
FontWeightOrLabel::Weight(n) => Value::U64(n as u64),
|
||||
FontWeightOrLabel::Label(l) => Value::String(l.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for FontWeight {
|
||||
fn deserialize<D>(deserializer: D) -> Result<FontWeight, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct V {}
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for V {
|
||||
type Value = FontWeight;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("string or font weight value")
|
||||
impl FromDynamic for FontWeight {
|
||||
fn from_dynamic(
|
||||
value: &Value,
|
||||
_options: FromDynamicOptions,
|
||||
) -> Result<Self, wezterm_dynamic::Error> {
|
||||
match value {
|
||||
Value::String(s) => {
|
||||
Ok(Self::from_str(s).ok_or_else(|| format!("invalid font weight {}", s))?)
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<FontWeight, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
match FontWeight::from_str(value) {
|
||||
Some(w) => Ok(w),
|
||||
None => Err(E::custom(format!("invalid font weight {}", value))),
|
||||
}
|
||||
}
|
||||
|
||||
// Lua gives us an integer in this format
|
||||
fn visit_i64<E>(self, value: i64) -> Result<FontWeight, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if value > 0 && value <= u16::MAX as i64 {
|
||||
Ok(FontWeight(value as u16))
|
||||
Value::U64(value) => {
|
||||
if *value > 0 && *value <= (u16::MAX as u64) {
|
||||
Ok(FontWeight(*value as u16))
|
||||
} else {
|
||||
Err(E::custom(format!("invalid font weight {}", value)))
|
||||
Err(format!("invalid font weight {}", value).into())
|
||||
}
|
||||
}
|
||||
other => Err(wezterm_dynamic::Error::NoConversion {
|
||||
source_type: other.variant_name().to_string(),
|
||||
dest_type: "FontWeight",
|
||||
}),
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(V {})
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,7 +215,7 @@ impl FontWeight {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromDynamic, ToDynamic)]
|
||||
pub enum FreeTypeLoadTarget {
|
||||
/// This corresponds to the default hinting algorithm, optimized
|
||||
/// for standard gray-level rendering.
|
||||
@ -265,8 +245,8 @@ bitflags! {
|
||||
// Note that these are strongly coupled with deps/freetype/src/lib.rs,
|
||||
// but we can't directly reference that from here without making config
|
||||
// depend on freetype.
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
#[serde(try_from="String", into="String")]
|
||||
#[derive(Default, FromDynamic, ToDynamic)]
|
||||
#[dynamic(try_from="String", into="String")]
|
||||
pub struct FreeTypeLoadFlags: u32 {
|
||||
/// FT_LOAD_DEFAULT
|
||||
const DEFAULT = 0;
|
||||
@ -290,6 +270,12 @@ impl Into<String> for FreeTypeLoadFlags {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for &FreeTypeLoadFlags {
|
||||
fn into(self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for FreeTypeLoadFlags {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = vec![];
|
||||
@ -339,33 +325,33 @@ impl TryFrom<String> for FreeTypeLoadFlags {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, FromDynamic, ToDynamic)]
|
||||
pub struct FontAttributes {
|
||||
/// The font family name
|
||||
pub family: String,
|
||||
/// Whether the font should be a bold variant
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub weight: FontWeight,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub stretch: FontStretch,
|
||||
/// Whether the font should be an italic variant
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub style: FontStyle,
|
||||
pub is_fallback: bool,
|
||||
pub is_synthetic: bool,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub harfbuzz_features: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_load_target: Option<FreeTypeLoadTarget>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_render_target: Option<FreeTypeLoadTarget>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_load_flags: Option<FreeTypeLoadFlags>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub scale: Option<NotNan<f64>>,
|
||||
}
|
||||
impl_lua_conversion!(FontAttributes);
|
||||
impl_lua_conversion_dynamic!(FontAttributes);
|
||||
|
||||
impl std::fmt::Display for FontAttributes {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
@ -430,9 +416,9 @@ impl Default for FontAttributes {
|
||||
}
|
||||
|
||||
/// Represents textual styling.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, FromDynamic, ToDynamic)]
|
||||
pub struct TextStyle {
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub font: Vec<FontAttributes>,
|
||||
|
||||
/// If set, when rendering text that is set to the default
|
||||
@ -441,7 +427,7 @@ pub struct TextStyle {
|
||||
/// the text color for eg: bold text.
|
||||
pub foreground: Option<RgbaColor>,
|
||||
}
|
||||
impl_lua_conversion!(TextStyle);
|
||||
impl_lua_conversion_dynamic!(TextStyle);
|
||||
|
||||
impl Default for TextStyle {
|
||||
fn default() -> Self {
|
||||
@ -604,7 +590,7 @@ impl TextStyle {
|
||||
/// The above is translated as: "if the `CellAttributes` have the italic bit
|
||||
/// set, then use the italic style of font rather than the default", and
|
||||
/// stop processing further font rules.
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Default, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct StyleRule {
|
||||
/// If present, this rule matches when CellAttributes::intensity holds
|
||||
/// a value that matches this rule. Valid values are "Bold", "Normal",
|
||||
@ -633,9 +619,8 @@ pub struct StyleRule {
|
||||
/// When this rule matches, `font` specifies the styling to be used.
|
||||
pub font: TextStyle,
|
||||
}
|
||||
impl_lua_conversion!(StyleRule);
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum AllowSquareGlyphOverflow {
|
||||
Never,
|
||||
Always,
|
||||
@ -648,7 +633,7 @@ impl Default for AllowSquareGlyphOverflow {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum FontLocatorSelection {
|
||||
/// Use fontconfig APIs to resolve fonts (!macos, posix systems)
|
||||
FontConfig,
|
||||
@ -672,30 +657,7 @@ impl Default for FontLocatorSelection {
|
||||
}
|
||||
}
|
||||
|
||||
impl FontLocatorSelection {
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["FontConfig", "CoreText", "ConfigDirsOnly", "Gdi"]
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for FontLocatorSelection {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_ref() {
|
||||
"fontconfig" => Ok(Self::FontConfig),
|
||||
"coretext" => Ok(Self::CoreText),
|
||||
"configdirsonly" => Ok(Self::ConfigDirsOnly),
|
||||
"gdi" => Ok(Self::Gdi),
|
||||
_ => Err(anyhow!(
|
||||
"{} is not a valid FontLocatorSelection variant, possible values are {:?}",
|
||||
s,
|
||||
Self::variants()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, FromDynamic, ToDynamic)]
|
||||
pub enum FontRasterizerSelection {
|
||||
FreeType,
|
||||
}
|
||||
@ -706,27 +668,7 @@ impl Default for FontRasterizerSelection {
|
||||
}
|
||||
}
|
||||
|
||||
impl FontRasterizerSelection {
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["FreeType"]
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for FontRasterizerSelection {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_ref() {
|
||||
"freetype" => Ok(Self::FreeType),
|
||||
_ => Err(anyhow!(
|
||||
"{} is not a valid FontRasterizerSelection variant, possible values are {:?}",
|
||||
s,
|
||||
Self::variants()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, FromDynamic, ToDynamic)]
|
||||
pub enum FontShaperSelection {
|
||||
Allsorts,
|
||||
Harfbuzz,
|
||||
@ -738,27 +680,6 @@ impl Default for FontShaperSelection {
|
||||
}
|
||||
}
|
||||
|
||||
impl FontShaperSelection {
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["Harfbuzz", "AllSorts"]
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for FontShaperSelection {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_ref() {
|
||||
"harfbuzz" => Ok(Self::Harfbuzz),
|
||||
"allsorts" => Ok(Self::Allsorts),
|
||||
_ => Err(anyhow!(
|
||||
"{} is not a valid FontShaperSelection variant, possible values are {:?}",
|
||||
s,
|
||||
Self::variants()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -1,36 +1,13 @@
|
||||
use super::*;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum FrontEndSelection {
|
||||
OpenGL,
|
||||
Software,
|
||||
}
|
||||
impl_lua_conversion!(FrontEndSelection);
|
||||
|
||||
impl Default for FrontEndSelection {
|
||||
fn default() -> Self {
|
||||
FrontEndSelection::OpenGL
|
||||
}
|
||||
}
|
||||
|
||||
impl FrontEndSelection {
|
||||
// TODO: find or build a proc macro for this
|
||||
pub fn variants() -> Vec<&'static str> {
|
||||
vec!["OpenGL", "Software"]
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for FrontEndSelection {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_ref() {
|
||||
"software" => Ok(FrontEndSelection::Software),
|
||||
"opengl" => Ok(FrontEndSelection::OpenGL),
|
||||
_ => Err(anyhow!(
|
||||
"{} is not a valid FrontEndSelection variant, possible values are {:?}",
|
||||
s,
|
||||
FrontEndSelection::variants()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,23 @@
|
||||
use crate::de_notnan;
|
||||
use crate::keys::KeyNoAction;
|
||||
use luahelper::impl_lua_conversion;
|
||||
use luahelper::impl_lua_conversion_dynamic;
|
||||
use ordered_float::NotNan;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
use wezterm_input_types::{KeyCode, Modifiers};
|
||||
use wezterm_term::input::MouseButton;
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic, PartialEq, Eq)]
|
||||
pub struct LauncherActionArgs {
|
||||
pub flags: LauncherFlags,
|
||||
pub title: Option<String>,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
#[serde(try_from="String", into="String")]
|
||||
#[derive(Default, FromDynamic, ToDynamic)]
|
||||
#[dynamic(try_from="String", into="String")]
|
||||
pub struct LauncherFlags :u32 {
|
||||
const ZERO = 0;
|
||||
const FUZZY = 1;
|
||||
@ -36,6 +36,12 @@ impl Into<String> for LauncherFlags {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for &LauncherFlags {
|
||||
fn into(self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for LauncherFlags {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = vec![];
|
||||
@ -89,7 +95,7 @@ impl TryFrom<String> for LauncherFlags {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, FromDynamic, ToDynamic)]
|
||||
pub enum SelectionMode {
|
||||
Cell,
|
||||
Word,
|
||||
@ -98,7 +104,7 @@ pub enum SelectionMode {
|
||||
Block,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum Pattern {
|
||||
CaseSensitiveString(String),
|
||||
CaseInSensitiveString(String),
|
||||
@ -133,7 +139,7 @@ impl std::ops::DerefMut for Pattern {
|
||||
}
|
||||
|
||||
/// A mouse event that can trigger an action
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, FromDynamic, ToDynamic)]
|
||||
pub enum MouseEventTrigger {
|
||||
/// Mouse button is pressed. streak is how many times in a row
|
||||
/// it was pressed.
|
||||
@ -148,7 +154,7 @@ pub enum MouseEventTrigger {
|
||||
|
||||
/// When spawning a tab, specify which domain should be used to
|
||||
/// host/spawn that tab.
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum SpawnTabDomain {
|
||||
/// Use the default domain
|
||||
DefaultDomain,
|
||||
@ -166,7 +172,7 @@ impl Default for SpawnTabDomain {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Default, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub struct SpawnCommand {
|
||||
/// Optional descriptive label
|
||||
pub label: Option<String>,
|
||||
@ -187,10 +193,10 @@ pub struct SpawnCommand {
|
||||
|
||||
/// Specifies a map of environment variables that should be set.
|
||||
/// Whether this is used depends on the domain.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub set_environment_variables: HashMap<String, String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub domain: SpawnTabDomain,
|
||||
}
|
||||
|
||||
@ -220,7 +226,7 @@ impl std::fmt::Display for SpawnCommand {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum PaneDirection {
|
||||
Up,
|
||||
Down,
|
||||
@ -230,7 +236,7 @@ pub enum PaneDirection {
|
||||
Prev,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum ScrollbackEraseMode {
|
||||
ScrollbackOnly,
|
||||
ScrollbackAndViewport,
|
||||
@ -242,7 +248,7 @@ impl Default for ScrollbackEraseMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum ClipboardCopyDestination {
|
||||
Clipboard,
|
||||
PrimarySelection,
|
||||
@ -255,7 +261,7 @@ impl Default for ClipboardCopyDestination {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum ClipboardPasteSource {
|
||||
Clipboard,
|
||||
PrimarySelection,
|
||||
@ -267,22 +273,22 @@ impl Default for ClipboardPasteSource {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Default, Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub struct QuickSelectArguments {
|
||||
/// Overrides the main quick_select_alphabet config
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub alphabet: String,
|
||||
/// Overrides the main quick_select_patterns config
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub patterns: Vec<String>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub action: Option<Box<KeyAssignment>>,
|
||||
/// Label to use in place of "copy" when `action` is set
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum KeyAssignment {
|
||||
SpawnTab(SpawnTabDomain),
|
||||
SpawnWindow,
|
||||
@ -312,7 +318,6 @@ pub enum KeyAssignment {
|
||||
ReloadConfiguration,
|
||||
MoveTabRelative(isize),
|
||||
MoveTab(usize),
|
||||
#[serde(deserialize_with = "de_notnan")]
|
||||
ScrollByPage(NotNan<f64>),
|
||||
ScrollByLine(isize),
|
||||
ScrollToPrompt(isize),
|
||||
@ -361,11 +366,11 @@ pub enum KeyAssignment {
|
||||
|
||||
ActivateKeyTable {
|
||||
name: String,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
timeout_milliseconds: Option<u64>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
replace_current: bool,
|
||||
#[serde(default = "crate::default_true")]
|
||||
#[dynamic(default = "crate::default_true")]
|
||||
one_shot: bool,
|
||||
},
|
||||
PopKeyTable,
|
||||
@ -375,9 +380,9 @@ pub enum KeyAssignment {
|
||||
|
||||
CopyMode(CopyModeAssignment),
|
||||
}
|
||||
impl_lua_conversion!(KeyAssignment);
|
||||
impl_lua_conversion_dynamic!(KeyAssignment);
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum CopyModeAssignment {
|
||||
MoveToViewportBottom,
|
||||
MoveToViewportTop,
|
||||
@ -408,7 +413,6 @@ pub enum CopyModeAssignment {
|
||||
EditPattern,
|
||||
AcceptPattern,
|
||||
}
|
||||
impl_lua_conversion!(CopyModeAssignment);
|
||||
|
||||
pub type KeyTable = HashMap<(KeyCode, Modifiers), KeyTableEntry>;
|
||||
|
||||
|
@ -1,15 +1,13 @@
|
||||
use crate::keyassignment::{KeyAssignment, MouseEventTrigger};
|
||||
use luahelper::impl_lua_conversion;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::convert::TryFrom;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
use wezterm_input_types::{KeyCode, Modifiers, PhysKeyCode};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, FromDynamic, ToDynamic)]
|
||||
pub enum KeyMapPreference {
|
||||
Physical,
|
||||
Mapped,
|
||||
}
|
||||
impl_lua_conversion!(KeyMapPreference);
|
||||
|
||||
impl Default for KeyMapPreference {
|
||||
fn default() -> Self {
|
||||
@ -17,8 +15,8 @@ impl Default for KeyMapPreference {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(into = "String", try_from = "String")]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, FromDynamic, ToDynamic)]
|
||||
#[dynamic(into = "String", try_from = "String")]
|
||||
pub enum DeferredKeyCode {
|
||||
KeyCode(KeyCode),
|
||||
Either {
|
||||
@ -64,6 +62,15 @@ impl DeferredKeyCode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for &DeferredKeyCode {
|
||||
fn into(self) -> String {
|
||||
match self {
|
||||
DeferredKeyCode::KeyCode(key) => key.to_string(),
|
||||
DeferredKeyCode::Either { original, .. } => original.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for DeferredKeyCode {
|
||||
fn into(self) -> String {
|
||||
match self {
|
||||
@ -104,89 +111,36 @@ impl TryFrom<&str> for DeferredKeyCode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub struct KeyNoAction {
|
||||
pub key: DeferredKeyCode,
|
||||
#[serde(
|
||||
deserialize_with = "de_modifiers",
|
||||
serialize_with = "ser_modifiers",
|
||||
default
|
||||
)]
|
||||
#[dynamic(default)]
|
||||
pub mods: Modifiers,
|
||||
}
|
||||
impl_lua_conversion!(KeyNoAction);
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct Key {
|
||||
#[serde(flatten)]
|
||||
#[dynamic(flatten)]
|
||||
pub key: KeyNoAction,
|
||||
pub action: KeyAssignment,
|
||||
}
|
||||
impl_lua_conversion!(Key);
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct LeaderKey {
|
||||
#[serde(flatten)]
|
||||
#[dynamic(flatten)]
|
||||
pub key: KeyNoAction,
|
||||
#[serde(default = "default_leader_timeout")]
|
||||
#[dynamic(default = "default_leader_timeout")]
|
||||
pub timeout_milliseconds: u64,
|
||||
}
|
||||
impl_lua_conversion!(LeaderKey);
|
||||
|
||||
fn default_leader_timeout() -> u64 {
|
||||
1000
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct Mouse {
|
||||
pub event: MouseEventTrigger,
|
||||
#[serde(
|
||||
deserialize_with = "de_modifiers",
|
||||
serialize_with = "ser_modifiers",
|
||||
default
|
||||
)]
|
||||
#[dynamic(default, into = "String", try_from = "String")]
|
||||
pub mods: Modifiers,
|
||||
pub action: KeyAssignment,
|
||||
}
|
||||
impl_lua_conversion!(Mouse);
|
||||
|
||||
pub(crate) fn ser_modifiers<S>(mods: &Modifiers, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let s = mods.to_string();
|
||||
serializer.serialize_str(&s)
|
||||
}
|
||||
|
||||
pub(crate) fn de_modifiers<'de, D>(deserializer: D) -> Result<Modifiers, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
let mut mods = Modifiers::NONE;
|
||||
for ele in s.split('|') {
|
||||
// Allow for whitespace; debug printing Modifiers includes spaces
|
||||
// around the `|` so it is desirable to be able to reverse that
|
||||
// encoding here.
|
||||
let ele = ele.trim();
|
||||
if ele == "SHIFT" {
|
||||
mods |= Modifiers::SHIFT;
|
||||
} else if ele == "ALT" || ele == "OPT" || ele == "META" {
|
||||
mods |= Modifiers::ALT;
|
||||
} else if ele == "CTRL" {
|
||||
mods |= Modifiers::CTRL;
|
||||
} else if ele == "SUPER" || ele == "CMD" || ele == "WIN" {
|
||||
mods |= Modifiers::SUPER;
|
||||
} else if ele == "LEADER" {
|
||||
mods |= Modifiers::LEADER;
|
||||
} else if ele == "NONE" || ele == "" {
|
||||
mods |= Modifiers::NONE;
|
||||
} else {
|
||||
return Err(serde::de::Error::custom(format!(
|
||||
"invalid modifier name {} in {}",
|
||||
ele, s
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(mods)
|
||||
}
|
||||
|
@ -2,17 +2,14 @@
|
||||
|
||||
use anyhow::{anyhow, bail, Context, Error};
|
||||
use lazy_static::lazy_static;
|
||||
use luahelper::impl_lua_conversion;
|
||||
use mlua::Lua;
|
||||
use mlua::{FromLua, Lua};
|
||||
use ordered_float::NotNan;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use smol::channel::{Receiver, Sender};
|
||||
use smol::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::ffi::OsString;
|
||||
use std::fs::DirBuilder;
|
||||
use std::marker::PhantomData;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::DirBuilderExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -20,6 +17,7 @@ use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use wezterm_dynamic::{ToDynamic, Value};
|
||||
|
||||
mod background;
|
||||
mod bell;
|
||||
@ -75,11 +73,32 @@ thread_local! {
|
||||
static LUA_CONFIG: RefCell<Option<LuaConfigState>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
fn toml_to_dynamic(value: &toml::Value) -> Value {
|
||||
match value {
|
||||
toml::Value::String(s) => s.to_dynamic(),
|
||||
toml::Value::Integer(n) => n.to_dynamic(),
|
||||
toml::Value::Float(n) => n.to_dynamic(),
|
||||
toml::Value::Boolean(b) => b.to_dynamic(),
|
||||
toml::Value::Datetime(d) => d.to_string().to_dynamic(),
|
||||
toml::Value::Array(a) => a
|
||||
.iter()
|
||||
.map(|element| toml_to_dynamic(&element))
|
||||
.collect::<Vec<_>>()
|
||||
.to_dynamic(),
|
||||
toml::Value::Table(t) => Value::Object(
|
||||
t.iter()
|
||||
.map(|(k, v)| (Value::String(k.to_string()), toml_to_dynamic(v)))
|
||||
.collect::<BTreeMap<_, _>>()
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_default_schemes() -> HashMap<String, Palette> {
|
||||
let mut color_schemes = HashMap::new();
|
||||
for (scheme_name, data) in SCHEMES.iter() {
|
||||
let scheme_name = scheme_name.to_string();
|
||||
let scheme: ColorSchemeFile = toml::from_str(data).unwrap();
|
||||
let scheme = ColorSchemeFile::from_toml_str(data).unwrap();
|
||||
color_schemes.insert(scheme_name, scheme.colors);
|
||||
}
|
||||
color_schemes
|
||||
@ -236,7 +255,7 @@ fn default_config_with_overrides_applied() -> anyhow::Result<Config> {
|
||||
let table = mlua::Value::Table(lua.create_table()?);
|
||||
let config = Config::apply_overrides_to(&lua, table)?;
|
||||
|
||||
let cfg: Config = luahelper::from_lua_value(config)
|
||||
let cfg: Config = Config::from_lua(config, &lua)
|
||||
.context("Error converting lua value from overrides to Config struct")?;
|
||||
// Compute but discard the key bindings here so that we raise any
|
||||
// problems earlier than we use them.
|
||||
@ -334,7 +353,7 @@ pub fn configuration() -> ConfigHandle {
|
||||
|
||||
/// Returns a version of the config (loaded from the config file)
|
||||
/// with some field overridden based on the supplied overrides object.
|
||||
pub fn overridden_config(overrides: &serde_json::Value) -> Result<ConfigHandle, Error> {
|
||||
pub fn overridden_config(overrides: &wezterm_dynamic::Value) -> Result<ConfigHandle, Error> {
|
||||
CONFIG.overridden(overrides)
|
||||
}
|
||||
|
||||
@ -527,7 +546,7 @@ impl ConfigInner {
|
||||
self.generation += 1;
|
||||
}
|
||||
|
||||
fn overridden(&mut self, overrides: &serde_json::Value) -> Result<ConfigHandle, Error> {
|
||||
fn overridden(&mut self, overrides: &wezterm_dynamic::Value) -> Result<ConfigHandle, Error> {
|
||||
let config = Config::load_with_overrides(overrides)?;
|
||||
Ok(ConfigHandle {
|
||||
config: Arc::new(config.config),
|
||||
@ -602,7 +621,7 @@ impl Configuration {
|
||||
inner.use_this_config(cfg);
|
||||
}
|
||||
|
||||
fn overridden(&self, overrides: &serde_json::Value) -> Result<ConfigHandle, Error> {
|
||||
fn overridden(&self, overrides: &wezterm_dynamic::Value) -> Result<ConfigHandle, Error> {
|
||||
let mut inner = self.inner.lock().unwrap();
|
||||
inner.overridden(overrides)
|
||||
}
|
||||
@ -659,104 +678,6 @@ impl std::ops::Deref for ConfigHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn de_notnan<'de, D>(deserializer: D) -> Result<NotNan<f64>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value: f64 = de_number(deserializer)?;
|
||||
NotNan::new(value).map_err(|err| serde::de::Error::custom(err.to_string()))
|
||||
}
|
||||
|
||||
/// Deserialize either an integer or a float as a float
|
||||
pub(crate) fn de_number<'de, D>(deserializer: D) -> Result<f64, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct Number;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for Number {
|
||||
type Value = f64;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("f64 or i64")
|
||||
}
|
||||
|
||||
fn visit_f64<E>(self, value: f64) -> Result<f64, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, value: i64) -> Result<f64, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(value as f64)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(Number)
|
||||
}
|
||||
|
||||
/// Helper for deserializing a Vec<T> from lua code.
|
||||
/// In lua, `{}` could be either an empty map or an empty vec.
|
||||
/// This helper allows an empty map to be specified and treated as an empty vec.
|
||||
pub fn de_vec_table<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
struct V<T> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'de, T> serde::de::Visitor<'de> for V<T>
|
||||
where
|
||||
T: Deserialize<'de>,
|
||||
{
|
||||
type Value = Vec<T>;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("Empty table or vector-like table")
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::SeqAccess<'de>,
|
||||
{
|
||||
let mut values = if let Some(hint) = seq.size_hint() {
|
||||
Vec::with_capacity(hint)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
while let Some(ele) = seq.next_element::<T>()? {
|
||||
values.push(ele);
|
||||
}
|
||||
Ok(values)
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: serde::de::MapAccess<'de>,
|
||||
{
|
||||
if map.next_entry::<String, T>()?.is_some() {
|
||||
use serde::de::Error;
|
||||
Err(A::Error::custom(
|
||||
"expected empty table or vector-like table",
|
||||
))
|
||||
} else {
|
||||
// Empty map is equivalent to empty vec
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(V {
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub struct LoadedConfig {
|
||||
pub config: Config,
|
||||
pub file_name: Option<PathBuf>,
|
||||
|
@ -8,7 +8,6 @@ use bstr::BString;
|
||||
pub use luahelper::*;
|
||||
use mlua::{FromLua, Lua, Table, ToLua, ToLuaMulti, Value, Variadic};
|
||||
use ordered_float::NotNan;
|
||||
use serde::*;
|
||||
use smol::prelude::*;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
@ -18,6 +17,7 @@ use termwiz::color::{AnsiColor, ColorAttribute, ColorSpec, RgbColor};
|
||||
use termwiz::input::Modifiers;
|
||||
use termwiz::surface::change::Change;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
static LUA_REGISTRY_USER_CALLBACK_COUNT: &str = "wezterm-user-callback-count";
|
||||
|
||||
@ -278,12 +278,7 @@ pub fn new_wezterm_terminfo_renderer() -> TerminfoRenderer {
|
||||
TerminfoRenderer::new(CAPS.clone())
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[serde(transparent)]
|
||||
struct ChangeWrap(Change);
|
||||
impl_lua_conversion!(ChangeWrap);
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, FromDynamic, ToDynamic, Clone, PartialEq, Eq)]
|
||||
pub enum FormatColor {
|
||||
AnsiColor(AnsiColor),
|
||||
Color(String),
|
||||
@ -312,14 +307,14 @@ impl Into<ColorSpec> for FormatColor {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, FromDynamic, ToDynamic, Clone, PartialEq, Eq)]
|
||||
pub enum FormatItem {
|
||||
Foreground(FormatColor),
|
||||
Background(FormatColor),
|
||||
Attribute(AttributeChange),
|
||||
Text(String),
|
||||
}
|
||||
impl_lua_conversion!(FormatItem);
|
||||
impl_lua_conversion_dynamic!(FormatItem);
|
||||
|
||||
impl Into<Change> for FormatItem {
|
||||
fn into(self) -> Change {
|
||||
@ -370,7 +365,7 @@ fn format<'lua>(_: &'lua Lua, items: Vec<FormatItem>) -> mlua::Result<String> {
|
||||
format_as_escapes(items).map_err(|e| mlua::Error::external(e))
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(FromDynamic, ToDynamic, Debug)]
|
||||
struct BatteryInfo {
|
||||
state_of_charge: f32,
|
||||
vendor: String,
|
||||
@ -380,7 +375,7 @@ struct BatteryInfo {
|
||||
time_to_full: Option<f32>,
|
||||
time_to_empty: Option<f32>,
|
||||
}
|
||||
impl_lua_conversion!(BatteryInfo);
|
||||
impl_lua_conversion_dynamic!(BatteryInfo);
|
||||
|
||||
fn opt_string(s: Option<&str>) -> String {
|
||||
match s {
|
||||
@ -442,17 +437,17 @@ fn hostname<'lua>(_: &'lua Lua, _: ()) -> mlua::Result<String> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Default, FromDynamic, ToDynamic, Clone, PartialEq, Eq, Hash)]
|
||||
struct TextStyleAttributes {
|
||||
/// Whether the font should be a bold variant
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub bold: Option<bool>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub weight: Option<FontWeight>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub stretch: FontStretch,
|
||||
/// Whether the font should be an italic variant
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub style: FontStyle,
|
||||
// Ideally we'd simply use serde's aliasing functionality on the `style`
|
||||
// field to support backwards compatibility, but aliases are invisible
|
||||
@ -466,7 +461,7 @@ struct TextStyleAttributes {
|
||||
}
|
||||
impl<'lua> FromLua<'lua> for TextStyleAttributes {
|
||||
fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self, mlua::Error> {
|
||||
let mut attr: TextStyleAttributes = from_lua_value(value)?;
|
||||
let mut attr: TextStyleAttributes = from_lua_value_dynamic(value)?;
|
||||
if let Some(italic) = attr.italic.take() {
|
||||
attr.style = if italic {
|
||||
FontStyle::Italic
|
||||
@ -478,33 +473,33 @@ impl<'lua> FromLua<'lua> for TextStyleAttributes {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Default, FromDynamic, ToDynamic, Clone, PartialEq, Eq, Hash)]
|
||||
struct LuaFontAttributes {
|
||||
/// The font family name
|
||||
pub family: String,
|
||||
/// Whether the font should be a bold variant
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub weight: FontWeight,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub stretch: FontStretch,
|
||||
/// Whether the font should be an italic variant
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub style: FontStyle,
|
||||
// Ideally we'd simply use serde's aliasing functionality on the `style`
|
||||
// field to support backwards compatibility, but aliases are invisible
|
||||
// to serde_lua, so we do a little fixup here ourselves in our from_lua impl.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
italic: Option<bool>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub harfbuzz_features: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_load_target: Option<FreeTypeLoadTarget>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_render_target: Option<FreeTypeLoadTarget>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub freetype_load_flags: Option<String>,
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub scale: Option<NotNan<f64>>,
|
||||
}
|
||||
impl<'lua> FromLua<'lua> for LuaFontAttributes {
|
||||
@ -516,7 +511,7 @@ impl<'lua> FromLua<'lua> for LuaFontAttributes {
|
||||
Ok(attr)
|
||||
}
|
||||
v => {
|
||||
let mut attr: LuaFontAttributes = from_lua_value(v)?;
|
||||
let mut attr: LuaFontAttributes = from_lua_value_dynamic(v)?;
|
||||
if let Some(italic) = attr.italic.take() {
|
||||
attr.style = if italic {
|
||||
FontStyle::Italic
|
||||
@ -662,8 +657,8 @@ fn font_with_fallback<'lua>(
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
fn action<'lua>(_lua: &'lua Lua, action: Table<'lua>) -> mlua::Result<KeyAssignment> {
|
||||
Ok(from_lua_value(Value::Table(action))?)
|
||||
fn action<'lua>(lua: &'lua Lua, action: Table<'lua>) -> mlua::Result<KeyAssignment> {
|
||||
Ok(KeyAssignment::from_lua(Value::Table(action), lua)?)
|
||||
}
|
||||
|
||||
fn action_callback<'lua>(lua: &'lua Lua, callback: mlua::Function) -> mlua::Result<KeyAssignment> {
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::*;
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
|
||||
#[derive(Debug, Clone, Copy, FromDynamic, ToDynamic)]
|
||||
pub enum SshBackend {
|
||||
Ssh2,
|
||||
LibSsh,
|
||||
}
|
||||
impl_lua_conversion!(SshBackend);
|
||||
|
||||
impl Default for SshBackend {
|
||||
fn default() -> Self {
|
||||
@ -15,13 +15,12 @@ impl Default for SshBackend {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum SshMultiplexing {
|
||||
WezTerm,
|
||||
None,
|
||||
// TODO: Tmux-cc in the future?
|
||||
}
|
||||
impl_lua_conversion!(SshMultiplexing);
|
||||
|
||||
impl Default for SshMultiplexing {
|
||||
fn default() -> Self {
|
||||
@ -29,7 +28,7 @@ impl Default for SshMultiplexing {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum Shell {
|
||||
/// Unknown command shell: no assumptions can be made
|
||||
Unknown,
|
||||
@ -39,7 +38,6 @@ pub enum Shell {
|
||||
Posix,
|
||||
// TODO: Cmd, PowerShell in the future?
|
||||
}
|
||||
impl_lua_conversion!(Shell);
|
||||
|
||||
impl Default for Shell {
|
||||
fn default() -> Self {
|
||||
@ -47,7 +45,7 @@ impl Default for Shell {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct SshDomain {
|
||||
/// The name of this specific domain. Must be unique amongst
|
||||
/// all types of domain in the configuration file.
|
||||
@ -57,20 +55,20 @@ pub struct SshDomain {
|
||||
pub remote_address: String,
|
||||
|
||||
/// Whether agent auth should be disabled
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub no_agent_auth: bool,
|
||||
|
||||
/// The username to use for authenticating with the remote host
|
||||
pub username: Option<String>,
|
||||
|
||||
/// If true, connect to this domain automatically at startup
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub connect_automatically: bool,
|
||||
|
||||
#[serde(default = "default_read_timeout")]
|
||||
#[dynamic(default = "default_read_timeout")]
|
||||
pub timeout: Duration,
|
||||
|
||||
#[serde(default = "default_local_echo_threshold_ms")]
|
||||
#[dynamic(default = "default_local_echo_threshold_ms")]
|
||||
pub local_echo_threshold_ms: Option<u64>,
|
||||
|
||||
/// The path to the wezterm binary on the remote host
|
||||
@ -82,19 +80,18 @@ pub struct SshDomain {
|
||||
/// just connect directly using ssh. This doesn't require
|
||||
/// that the remote host have wezterm installed, and is equivalent
|
||||
/// to using `wezterm ssh` to connect.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub multiplexing: SshMultiplexing,
|
||||
|
||||
/// ssh_config option values
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub ssh_option: HashMap<String, String>,
|
||||
|
||||
pub default_prog: Option<Vec<String>>,
|
||||
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub assume_shell: Shell,
|
||||
}
|
||||
impl_lua_conversion!(SshDomain);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SshParameters {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::*;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct TlsDomainServer {
|
||||
/// The address:port combination on which the server will listen
|
||||
/// for client connections
|
||||
@ -20,12 +21,11 @@ pub struct TlsDomainServer {
|
||||
/// or to a PEM encoded CA file. If an entry is a directory,
|
||||
/// then its contents will be loaded as CA certs and added
|
||||
/// to the trust store.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub pem_root_certs: Vec<PathBuf>,
|
||||
}
|
||||
impl_lua_conversion!(TlsDomainServer);
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct TlsDomainClient {
|
||||
/// The name of this specific domain. Must be unique amongst
|
||||
/// all types of domain in the configuration file.
|
||||
@ -52,7 +52,7 @@ pub struct TlsDomainClient {
|
||||
/// Each entry can be either the path to a directory or to a PEM encoded
|
||||
/// CA file. If an entry is a directory, then its contents will be
|
||||
/// loaded as CA certs and added to the trust store.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub pem_root_certs: Vec<PathBuf>,
|
||||
|
||||
/// explicitly control whether the client checks that the certificate
|
||||
@ -61,7 +61,7 @@ pub struct TlsDomainClient {
|
||||
/// available for troubleshooting purposes and should not be used outside
|
||||
/// of a controlled environment as it weakens the security of the TLS
|
||||
/// channel.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub accept_invalid_hostnames: bool,
|
||||
|
||||
/// the hostname string that we expect to match against the common name
|
||||
@ -71,22 +71,21 @@ pub struct TlsDomainClient {
|
||||
pub expected_cn: Option<String>,
|
||||
|
||||
/// If true, connect to this domain automatically at startup
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub connect_automatically: bool,
|
||||
|
||||
#[serde(default = "default_read_timeout")]
|
||||
#[dynamic(default = "default_read_timeout")]
|
||||
pub read_timeout: Duration,
|
||||
|
||||
#[serde(default = "default_write_timeout")]
|
||||
#[dynamic(default = "default_write_timeout")]
|
||||
pub write_timeout: Duration,
|
||||
|
||||
#[serde(default = "default_local_echo_threshold_ms")]
|
||||
#[dynamic(default = "default_local_echo_threshold_ms")]
|
||||
pub local_echo_threshold_ms: Option<u64>,
|
||||
|
||||
/// The path to the wezterm binary on the remote host
|
||||
pub remote_wezterm_path: Option<String>,
|
||||
}
|
||||
impl_lua_conversion!(TlsDomainClient);
|
||||
|
||||
impl TlsDomainClient {
|
||||
pub fn ssh_parameters(&self) -> Option<anyhow::Result<SshParameters>> {
|
||||
|
@ -1,4 +1,22 @@
|
||||
use serde::{Deserializer, Serialize, Serializer};
|
||||
use wezterm_dynamic::{FromDynamic, FromDynamicOptions, ToDynamic, Value};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PixelUnit(Dimension);
|
||||
|
||||
impl Into<Dimension> for PixelUnit {
|
||||
fn into(self) -> Dimension {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl FromDynamic for PixelUnit {
|
||||
fn from_dynamic(
|
||||
value: &Value,
|
||||
_options: FromDynamicOptions,
|
||||
) -> Result<Self, wezterm_dynamic::Error> {
|
||||
Ok(Self(DefaultUnit::Pixels.from_dynamic_impl(value)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum DefaultUnit {
|
||||
@ -19,63 +37,47 @@ impl DefaultUnit {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for DefaultUnit {
|
||||
type Value = Dimension;
|
||||
impl DefaultUnit {
|
||||
fn from_dynamic_impl(self, value: &Value) -> Result<Dimension, String> {
|
||||
match value {
|
||||
Value::F64(f) => Ok(self.to_dimension(f.into_inner() as f32)),
|
||||
Value::I64(i) => Ok(self.to_dimension(*i as f32)),
|
||||
Value::U64(u) => Ok(self.to_dimension(*u as f32)),
|
||||
Value::String(s) => {
|
||||
if let Ok(value) = s.parse::<f32>() {
|
||||
Ok(self.to_dimension(value))
|
||||
} else {
|
||||
fn is_unit(s: &str, unit: &'static str) -> Option<f32> {
|
||||
let s = s.strip_suffix(unit)?.trim();
|
||||
s.parse().ok()
|
||||
}
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("f64 or i64")
|
||||
}
|
||||
|
||||
fn visit_f32<E>(self, value: f32) -> Result<Dimension, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(self.to_dimension(value))
|
||||
}
|
||||
|
||||
fn visit_f64<E>(self, value: f64) -> Result<Dimension, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(self.to_dimension(value as f32))
|
||||
}
|
||||
|
||||
fn visit_i64<E>(self, value: i64) -> Result<Dimension, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
Ok(self.to_dimension(value as f32))
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Dimension, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
if let Ok(value) = s.parse::<f32>() {
|
||||
Ok(self.to_dimension(value))
|
||||
} else {
|
||||
fn is_unit(s: &str, unit: &'static str) -> Option<f32> {
|
||||
let s = s.strip_suffix(unit)?.trim();
|
||||
s.parse().ok()
|
||||
}
|
||||
|
||||
if let Some(v) = is_unit(s, "px") {
|
||||
Ok(DefaultUnit::Pixels.to_dimension(v))
|
||||
} else if let Some(v) = is_unit(s, "%") {
|
||||
Ok(DefaultUnit::Percent.to_dimension(v))
|
||||
} else if let Some(v) = is_unit(s, "pt") {
|
||||
Ok(DefaultUnit::Points.to_dimension(v))
|
||||
} else if let Some(v) = is_unit(s, "cell") {
|
||||
Ok(DefaultUnit::Cells.to_dimension(v))
|
||||
} else {
|
||||
Err(serde::de::Error::custom(format!(
|
||||
"expected either a number or a string of \
|
||||
if let Some(v) = is_unit(s, "px") {
|
||||
Ok(DefaultUnit::Pixels.to_dimension(v))
|
||||
} else if let Some(v) = is_unit(s, "%") {
|
||||
Ok(DefaultUnit::Percent.to_dimension(v))
|
||||
} else if let Some(v) = is_unit(s, "pt") {
|
||||
Ok(DefaultUnit::Points.to_dimension(v))
|
||||
} else if let Some(v) = is_unit(s, "cell") {
|
||||
Ok(DefaultUnit::Cells.to_dimension(v))
|
||||
} else {
|
||||
Err(format!(
|
||||
"expected either a number or a string of \
|
||||
the form '123px' where 'px' is a unit and \
|
||||
can be one of 'px', '%', 'pt' or 'cell', \
|
||||
but got {}",
|
||||
s
|
||||
)))
|
||||
s
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
other => Err(format!(
|
||||
"expected either a number or a string of \
|
||||
the form '123px' where 'px' is a unit and \
|
||||
can be one of 'px', '%', 'pt' or 'cell', \
|
||||
but got {}",
|
||||
other.variant_name()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,18 +117,15 @@ impl Default for Dimension {
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Dimension {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
impl ToDynamic for Dimension {
|
||||
fn to_dynamic(&self) -> Value {
|
||||
let s = match self {
|
||||
Self::Points(n) => format!("{}pt", n),
|
||||
Self::Pixels(n) => format!("{}px", n),
|
||||
Self::Percent(n) => format!("{}%", n * 100.),
|
||||
Self::Cells(n) => format!("{}cell", n),
|
||||
};
|
||||
serializer.serialize_str(&s)
|
||||
Value::String(s)
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,38 +167,3 @@ impl Default for GeometryOrigin {
|
||||
Self::ScreenCoordinateSystem
|
||||
}
|
||||
}
|
||||
|
||||
fn de_dimension<'de, D>(unit: DefaultUnit, deserializer: D) -> Result<Dimension, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserializer.deserialize_any(unit)
|
||||
}
|
||||
|
||||
pub fn de_pixels<'de, D>(deserializer: D) -> Result<Dimension, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
de_dimension(DefaultUnit::Pixels, deserializer)
|
||||
}
|
||||
|
||||
pub fn de_points<'de, D>(deserializer: D) -> Result<Dimension, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
de_dimension(DefaultUnit::Points, deserializer)
|
||||
}
|
||||
|
||||
pub fn de_percent<'de, D>(deserializer: D) -> Result<Dimension, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
de_dimension(DefaultUnit::Percent, deserializer)
|
||||
}
|
||||
|
||||
pub fn de_cells<'de, D>(deserializer: D) -> Result<Dimension, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
de_dimension(DefaultUnit::Cells, deserializer)
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use crate::*;
|
||||
use std::path::PathBuf;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
/// Configures an instance of a multiplexer that can be communicated
|
||||
/// with via a unix domain socket
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct UnixDomain {
|
||||
/// The name of this specific domain. Must be unique amongst
|
||||
/// all types of domain in the configuration file.
|
||||
@ -14,12 +15,12 @@ pub struct UnixDomain {
|
||||
pub socket_path: Option<PathBuf>,
|
||||
|
||||
/// If true, connect to this domain automatically at startup
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub connect_automatically: bool,
|
||||
|
||||
/// If true, do not attempt to start this server if we try and fail to
|
||||
/// connect to it.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub no_serve_automatically: bool,
|
||||
|
||||
/// If we decide that we need to start the server, the command to run
|
||||
@ -40,20 +41,19 @@ pub struct UnixDomain {
|
||||
/// system, but is useful for example when running the
|
||||
/// server inside a WSL container but with the socket
|
||||
/// on the host NTFS volume.
|
||||
#[serde(default)]
|
||||
#[dynamic(default)]
|
||||
pub skip_permissions_check: bool,
|
||||
|
||||
#[serde(default = "default_read_timeout")]
|
||||
#[dynamic(default = "default_read_timeout")]
|
||||
pub read_timeout: Duration,
|
||||
|
||||
#[serde(default = "default_write_timeout")]
|
||||
#[dynamic(default = "default_write_timeout")]
|
||||
pub write_timeout: Duration,
|
||||
|
||||
/// Don't use default_local_echo_threshold_ms() here to
|
||||
/// disable the predictive echo for Unix domains by default.
|
||||
pub local_echo_threshold_ms: Option<u64>,
|
||||
}
|
||||
impl_lua_conversion!(UnixDomain);
|
||||
|
||||
impl Default for UnixDomain {
|
||||
fn default() -> Self {
|
||||
|
@ -1,7 +1,9 @@
|
||||
use crate::*;
|
||||
use luahelper::impl_lua_conversion_dynamic;
|
||||
use std::collections::HashMap;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct WslDomain {
|
||||
pub name: String,
|
||||
pub distribution: Option<String>,
|
||||
@ -9,7 +11,7 @@ pub struct WslDomain {
|
||||
pub default_cwd: Option<PathBuf>,
|
||||
pub default_prog: Option<Vec<String>>,
|
||||
}
|
||||
impl_lua_conversion!(WslDomain);
|
||||
impl_lua_conversion_dynamic!(WslDomain);
|
||||
|
||||
impl WslDomain {
|
||||
pub fn default_domains() -> Vec<WslDomain> {
|
||||
@ -33,7 +35,7 @@ impl WslDomain {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct WslDistro {
|
||||
pub name: String,
|
||||
pub state: String,
|
||||
|
@ -14,3 +14,4 @@ serde = {version="1.0", features = ["rc", "derive"]}
|
||||
serde_json = "1.0"
|
||||
strsim = "0.10"
|
||||
thiserror = "1.0"
|
||||
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
||||
|
@ -1,9 +1,11 @@
|
||||
#![macro_use]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic, Value as DynValue};
|
||||
|
||||
mod serde_lua;
|
||||
pub use mlua;
|
||||
use mlua::{ToLua, Value as LuaValue};
|
||||
pub use serde_lua::from_lua_value;
|
||||
pub use serde_lua::ser::to_lua_value;
|
||||
|
||||
@ -36,9 +38,133 @@ macro_rules! impl_lua_conversion {
|
||||
};
|
||||
}
|
||||
|
||||
pub use serde_lua::ValueWrapper;
|
||||
#[macro_export]
|
||||
macro_rules! impl_lua_conversion_dynamic {
|
||||
($struct:ident) => {
|
||||
impl<'lua> $crate::mlua::ToLua<'lua> for $struct {
|
||||
fn to_lua(
|
||||
self,
|
||||
lua: &'lua $crate::mlua::Lua,
|
||||
) -> Result<$crate::mlua::Value<'lua>, $crate::mlua::Error> {
|
||||
use wezterm_dynamic::ToDynamic;
|
||||
let value = self.to_dynamic();
|
||||
$crate::dynamic_to_lua_value(lua, value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct JsonLua(pub serde_json::Value);
|
||||
impl_lua_conversion!(JsonLua);
|
||||
impl<'lua> $crate::mlua::FromLua<'lua> for $struct {
|
||||
fn from_lua(
|
||||
value: $crate::mlua::Value<'lua>,
|
||||
_lua: &'lua $crate::mlua::Lua,
|
||||
) -> Result<Self, $crate::mlua::Error> {
|
||||
use wezterm_dynamic::FromDynamic;
|
||||
let lua_type = value.type_name();
|
||||
let value = $crate::lua_value_to_dynamic(value)?;
|
||||
$struct::from_dynamic(&value, Default::default()).map_err(|e| {
|
||||
$crate::mlua::Error::FromLuaConversionError {
|
||||
from: lua_type,
|
||||
to: stringify!($struct),
|
||||
message: Some(e.to_string()),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dynamic_to_lua_value<'lua>(
|
||||
lua: &'lua mlua::Lua,
|
||||
value: DynValue,
|
||||
) -> mlua::Result<mlua::Value> {
|
||||
Ok(match value {
|
||||
DynValue::Null => LuaValue::Nil,
|
||||
DynValue::Bool(b) => LuaValue::Boolean(b),
|
||||
DynValue::String(s) => s.to_lua(lua)?,
|
||||
DynValue::U64(u) => u.to_lua(lua)?,
|
||||
DynValue::F64(u) => u.to_lua(lua)?,
|
||||
DynValue::I64(u) => u.to_lua(lua)?,
|
||||
DynValue::Array(array) => {
|
||||
let table = lua.create_table()?;
|
||||
for (idx, value) in array.into_iter().enumerate() {
|
||||
table.set(idx + 1, dynamic_to_lua_value(lua, value)?)?;
|
||||
}
|
||||
LuaValue::Table(table)
|
||||
}
|
||||
DynValue::Object(object) => {
|
||||
let table = lua.create_table()?;
|
||||
for (key, value) in object.into_iter() {
|
||||
table.set(
|
||||
dynamic_to_lua_value(lua, key)?,
|
||||
dynamic_to_lua_value(lua, value)?,
|
||||
)?;
|
||||
}
|
||||
LuaValue::Table(table)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lua_value_to_dynamic(value: LuaValue) -> mlua::Result<DynValue> {
|
||||
Ok(match value {
|
||||
LuaValue::Nil => DynValue::Null,
|
||||
LuaValue::String(s) => DynValue::String(s.to_str()?.to_string()),
|
||||
LuaValue::Boolean(b) => DynValue::Bool(b),
|
||||
LuaValue::Integer(i) => DynValue::I64(i),
|
||||
LuaValue::Number(i) => DynValue::F64(i.into()),
|
||||
LuaValue::LightUserData(_) | LuaValue::UserData(_) => {
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: "userdata",
|
||||
to: "wezterm_dynamic::Value",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
LuaValue::Function(_) => {
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: "function",
|
||||
to: "wezterm_dynamic::Value",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
LuaValue::Thread(_) => {
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: "thread",
|
||||
to: "wezterm_dynamic::Value",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
LuaValue::Error(e) => return Err(e),
|
||||
LuaValue::Table(table) => {
|
||||
if let Ok(true) = table.contains_key(1) {
|
||||
let mut array = vec![];
|
||||
for value in table.sequence_values() {
|
||||
array.push(lua_value_to_dynamic(value?)?);
|
||||
}
|
||||
DynValue::Array(array.into())
|
||||
} else {
|
||||
let mut obj = BTreeMap::default();
|
||||
for pair in table.pairs::<LuaValue, LuaValue>() {
|
||||
let (key, value) = pair?;
|
||||
obj.insert(lua_value_to_dynamic(key)?, lua_value_to_dynamic(value)?);
|
||||
}
|
||||
DynValue::Object(obj.into())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_lua_value_dynamic<T: FromDynamic>(value: LuaValue) -> mlua::Result<T> {
|
||||
let type_name = value.type_name();
|
||||
let value = lua_value_to_dynamic(value)?;
|
||||
T::from_dynamic(&value, Default::default()).map_err(|e| mlua::Error::FromLuaConversionError {
|
||||
from: type_name,
|
||||
to: "Rust Type",
|
||||
message: Some(e.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(FromDynamic, ToDynamic)]
|
||||
pub struct ValueLua {
|
||||
pub value: wezterm_dynamic::Value,
|
||||
}
|
||||
impl_lua_conversion_dynamic!(ValueLua);
|
||||
|
||||
pub use serde_lua::ValueWrapper;
|
||||
|
@ -41,6 +41,7 @@ thiserror = "1.0"
|
||||
unicode-segmentation = "1.8"
|
||||
url = "2"
|
||||
wezterm-ssh = { path = "../wezterm-ssh" }
|
||||
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
||||
wezterm-term = { path = "../term", features=["use_serde"] }
|
||||
flume = "0.10"
|
||||
|
||||
|
@ -1,21 +1,26 @@
|
||||
use luahelper::impl_lua_conversion;
|
||||
use luahelper::impl_lua_conversion_dynamic;
|
||||
use rangeset::RangeSet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::Range;
|
||||
use termwiz::surface::{SequenceNo, SEQ_ZERO};
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
use wezterm_term::{Line, StableRowIndex, Terminal};
|
||||
|
||||
/// Describes the location of the cursor
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(
|
||||
Debug, Default, Copy, Clone, Eq, PartialEq, Deserialize, Serialize, FromDynamic, ToDynamic,
|
||||
)]
|
||||
pub struct StableCursorPosition {
|
||||
pub x: usize,
|
||||
pub y: StableRowIndex,
|
||||
pub shape: termwiz::surface::CursorShape,
|
||||
pub visibility: termwiz::surface::CursorVisibility,
|
||||
}
|
||||
impl_lua_conversion!(StableCursorPosition);
|
||||
impl_lua_conversion_dynamic!(StableCursorPosition);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize)]
|
||||
#[derive(
|
||||
Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize, Serialize, FromDynamic, ToDynamic,
|
||||
)]
|
||||
pub struct RenderableDimensions {
|
||||
/// The viewport width
|
||||
pub cols: usize,
|
||||
@ -34,7 +39,7 @@ pub struct RenderableDimensions {
|
||||
/// expressed as a stable index.
|
||||
pub scrollback_top: StableRowIndex,
|
||||
}
|
||||
impl_lua_conversion!(RenderableDimensions);
|
||||
impl_lua_conversion_dynamic!(RenderableDimensions);
|
||||
|
||||
/// Implements Pane::get_cursor_position for Terminal
|
||||
pub fn terminal_get_cursor_position(term: &mut Terminal) -> StableCursorPosition {
|
||||
|
@ -9,7 +9,7 @@ edition = "2021"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
luahelper = { path = "../luahelper" }
|
||||
serde = {version="1.0", features = ["rc", "derive"]}
|
||||
serde = {version="1.0", features = ["derive"]}
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
ntapi = "0.3"
|
||||
|
@ -31,6 +31,7 @@ unicode-segmentation = "1.8"
|
||||
unicode-width = "0.1"
|
||||
url = "2"
|
||||
wezterm-bidi = { path = "../bidi" }
|
||||
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.9"
|
||||
|
@ -8,11 +8,12 @@ use super::VisibleRowIndex;
|
||||
#[cfg(feature = "use_serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::{Duration, Instant};
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
pub use termwiz::input::{KeyCode, Modifiers as KeyModifiers};
|
||||
|
||||
#[cfg_attr(feature = "use_serde", derive(Deserialize, Serialize))]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, FromDynamic, ToDynamic)]
|
||||
pub enum MouseButton {
|
||||
Left,
|
||||
Middle,
|
||||
|
@ -40,6 +40,7 @@ ucd-trie = "0.1"
|
||||
vtparse = { version="0.6", path="../vtparse" }
|
||||
wezterm-bidi = { path = "../bidi", version="0.1" }
|
||||
wezterm-color-types = { path = "../color-types", version="0.1" }
|
||||
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
||||
|
||||
[features]
|
||||
widgets = ["cassowary", "fnv"]
|
||||
|
@ -8,6 +8,7 @@ use crate::widechar_width::WcWidth;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
@ -164,7 +165,7 @@ impl Default for SemanticType {
|
||||
/// using an alternative color. Some terminals implement `Intensity::Half`
|
||||
/// as a dimmer color variant.
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
#[repr(u16)]
|
||||
pub enum Intensity {
|
||||
Normal = 0,
|
||||
@ -180,7 +181,7 @@ impl Default for Intensity {
|
||||
|
||||
/// Specify just how underlined you want your `Cell` to be
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromDynamic, ToDynamic)]
|
||||
#[repr(u16)]
|
||||
pub enum Underline {
|
||||
/// The cell is not underlined
|
||||
@ -214,7 +215,7 @@ impl Into<bool> for Underline {
|
||||
|
||||
/// Specify whether you want to slowly or rapidly annoy your users
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
#[repr(u16)]
|
||||
pub enum Blink {
|
||||
None = 0,
|
||||
@ -939,7 +940,7 @@ pub fn grapheme_column_width(s: &str, version: Option<UnicodeVersion>) -> usize
|
||||
/// Each variant specifies one of the possible attributes; the corresponding
|
||||
/// value holds the new value to be used for that attribute.
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, FromDynamic, ToDynamic)]
|
||||
pub enum AttributeChange {
|
||||
Intensity(Intensity),
|
||||
Underline(Underline),
|
||||
|
@ -6,8 +6,9 @@ use num_derive::*;
|
||||
#[cfg(feature = "use_serde")]
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
pub use wezterm_color_types::{LinearRgba, SrgbaTuple};
|
||||
use wezterm_dynamic::{FromDynamic, FromDynamicOptions, ToDynamic, Value};
|
||||
|
||||
#[derive(Debug, Clone, Copy, FromPrimitive, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, FromPrimitive, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[repr(u8)]
|
||||
/// These correspond to the classic ANSI color indices and are
|
||||
@ -200,6 +201,23 @@ impl<'de> Deserialize<'de> for RgbColor {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToDynamic for RgbColor {
|
||||
fn to_dynamic(&self) -> Value {
|
||||
self.to_rgb_string().to_dynamic()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromDynamic for RgbColor {
|
||||
fn from_dynamic(
|
||||
value: &Value,
|
||||
options: FromDynamicOptions,
|
||||
) -> Result<Self, wezterm_dynamic::Error> {
|
||||
let s = String::from_dynamic(value, options)?;
|
||||
Ok(RgbColor::from_named_or_rgb_string(&s)
|
||||
.ok_or_else(|| format!("unknown color name: {}", s))?)
|
||||
}
|
||||
}
|
||||
|
||||
/// An index into the fixed color palette.
|
||||
pub type PaletteIndex = u8;
|
||||
|
||||
@ -238,7 +256,7 @@ impl From<RgbColor> for ColorSpec {
|
||||
/// TrueColor value, allowing a fallback to a more traditional palette
|
||||
/// index if TrueColor is not available.
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, FromDynamic, ToDynamic)]
|
||||
pub enum ColorAttribute {
|
||||
/// Use RgbColor when supported, falling back to the specified PaletteIndex.
|
||||
TrueColorWithPaletteFallback(RgbColor, PaletteIndex),
|
||||
|
@ -12,9 +12,10 @@ use std::collections::HashMap;
|
||||
use std::fmt::{Display, Error as FmtError, Formatter};
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
use wezterm_dynamic::{FromDynamic, FromDynamicOptions, ToDynamic, Value};
|
||||
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub struct Hyperlink {
|
||||
params: HashMap<String, String>,
|
||||
uri: String,
|
||||
@ -124,7 +125,7 @@ impl Display for Hyperlink {
|
||||
/// The Rule struct is configuration that is passed to the terminal
|
||||
/// and is evaluated when processing mouse hover events.
|
||||
#[cfg_attr(feature = "use_serde", derive(Deserialize, Serialize))]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, FromDynamic, ToDynamic)]
|
||||
pub struct Rule {
|
||||
/// The compiled regex for the rule. This is used to match
|
||||
/// against a line of text from the screen (typically the line
|
||||
@ -136,6 +137,7 @@ pub struct Rule {
|
||||
serialize_with = "serialize_regex"
|
||||
)
|
||||
)]
|
||||
#[dynamic(into = "RegexWrap", try_from = "RegexWrap")]
|
||||
regex: Regex,
|
||||
/// The format string that defines how to transform the matched
|
||||
/// text into a URL. For example, a format string of `$0` expands
|
||||
@ -150,6 +152,36 @@ pub struct Rule {
|
||||
format: String,
|
||||
}
|
||||
|
||||
struct RegexWrap(Regex);
|
||||
|
||||
impl FromDynamic for RegexWrap {
|
||||
fn from_dynamic(
|
||||
value: &Value,
|
||||
options: FromDynamicOptions,
|
||||
) -> std::result::Result<RegexWrap, wezterm_dynamic::Error> {
|
||||
let s = String::from_dynamic(value, options)?;
|
||||
Ok(RegexWrap(Regex::new(&s).map_err(|e| e.to_string())?))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Regex> for RegexWrap {
|
||||
fn from(regex: &Regex) -> RegexWrap {
|
||||
RegexWrap(regex.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Regex> for RegexWrap {
|
||||
fn into(self) -> Regex {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ToDynamic for RegexWrap {
|
||||
fn to_dynamic(&self) -> Value {
|
||||
self.0.to_string().to_dynamic()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "use_serde")]
|
||||
fn deserialize_regex<'de, D>(deserializer: D) -> std::result::Result<Regex, D::Error>
|
||||
where
|
||||
|
@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::min;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
pub mod change;
|
||||
pub mod line;
|
||||
@ -31,7 +32,7 @@ pub enum Position {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromDynamic, ToDynamic)]
|
||||
pub enum CursorVisibility {
|
||||
Hidden,
|
||||
Visible,
|
||||
@ -44,7 +45,7 @@ impl Default for CursorVisibility {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, FromDynamic, ToDynamic)]
|
||||
pub enum CursorShape {
|
||||
Default,
|
||||
BlinkingBlock,
|
||||
|
@ -71,6 +71,7 @@ url = "2"
|
||||
walkdir = "2"
|
||||
wezterm-bidi = { path = "../bidi" }
|
||||
wezterm-client = { path = "../wezterm-client" }
|
||||
wezterm-dynamic = { path = "../wezterm-dynamic" }
|
||||
wezterm-font = { path = "../wezterm-font" }
|
||||
wezterm-gui-subcommands = { path = "../wezterm-gui-subcommands" }
|
||||
wezterm-mux-server-impl = { path = "../wezterm-mux-server-impl" }
|
||||
|
@ -8,7 +8,7 @@ use luahelper::*;
|
||||
use mlua::{UserData, UserDataMethods};
|
||||
use mux::window::WindowId as MuxWindowId;
|
||||
use mux::Mux;
|
||||
use serde::*;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
use wezterm_toast_notification::ToastNotification;
|
||||
use window::{Connection, ConnectionOps, DeadKeyStatus, WindowOps, WindowState};
|
||||
|
||||
@ -60,14 +60,14 @@ impl UserData for GuiWin {
|
||||
.map_err(|e| anyhow::anyhow!("{:#}", e))
|
||||
.map_err(luaerr)?;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(FromDynamic, ToDynamic)]
|
||||
struct Dims {
|
||||
pixel_width: usize,
|
||||
pixel_height: usize,
|
||||
dpi: usize,
|
||||
is_full_screen: bool,
|
||||
}
|
||||
impl_lua_conversion!(Dims);
|
||||
impl_lua_conversion_dynamic!(Dims);
|
||||
|
||||
let dims = Dims {
|
||||
pixel_width: dims.pixel_width,
|
||||
@ -125,12 +125,12 @@ impl UserData for GuiWin {
|
||||
.map_err(|e| anyhow::anyhow!("{:#}", e))
|
||||
.map_err(luaerr)?;
|
||||
|
||||
let wrap = JsonLua(overrides);
|
||||
let wrap = ValueLua { value: overrides };
|
||||
Ok(wrap)
|
||||
});
|
||||
methods.add_method("set_config_overrides", |_, this, value: JsonLua| {
|
||||
methods.add_method("set_config_overrides", |_, this, value: ValueLua| {
|
||||
this.window
|
||||
.notify(TermWindowNotif::SetConfigOverrides(value.0));
|
||||
.notify(TermWindowNotif::SetConfigOverrides(value.value));
|
||||
Ok(())
|
||||
});
|
||||
methods.add_async_method("leader_is_active", |_, this, _: ()| async move {
|
||||
|
@ -112,8 +112,8 @@ pub enum TermWindowNotif {
|
||||
name: String,
|
||||
again: bool,
|
||||
},
|
||||
GetConfigOverrides(Sender<serde_json::Value>),
|
||||
SetConfigOverrides(serde_json::Value),
|
||||
GetConfigOverrides(Sender<wezterm_dynamic::Value>),
|
||||
SetConfigOverrides(wezterm_dynamic::Value),
|
||||
CancelOverlayForPane(PaneId),
|
||||
CancelOverlayForTab {
|
||||
tab_id: TabId,
|
||||
@ -317,7 +317,7 @@ enum EventState {
|
||||
pub struct TermWindow {
|
||||
pub window: Option<Window>,
|
||||
pub config: ConfigHandle,
|
||||
pub config_overrides: serde_json::Value,
|
||||
pub config_overrides: wezterm_dynamic::Value,
|
||||
os_parameters: Option<parameters::Parameters>,
|
||||
/// When we most recently received keyboard focus
|
||||
focused: Option<Instant>,
|
||||
@ -748,7 +748,7 @@ impl TermWindow {
|
||||
window: None,
|
||||
window_background,
|
||||
config: config.clone(),
|
||||
config_overrides: serde_json::Value::default(),
|
||||
config_overrides: wezterm_dynamic::Value::default(),
|
||||
palette: None,
|
||||
focused: None,
|
||||
mux_window_id,
|
||||
|
@ -11,3 +11,4 @@ bitflags = "1.3"
|
||||
euclid = "0.22"
|
||||
lazy_static = "1.4"
|
||||
serde = {version="1.0", features = ["rc", "derive"]}
|
||||
wezterm-dynamic = {path="../wezterm-dynamic"}
|
||||
|
@ -4,6 +4,7 @@ use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
use wezterm_dynamic::{FromDynamic, ToDynamic};
|
||||
|
||||
pub struct PixelUnit;
|
||||
pub struct ScreenPixelUnit;
|
||||
@ -14,7 +15,19 @@ pub type ScreenPoint = euclid::Point2D<isize, ScreenPixelUnit>;
|
||||
/// Which key is pressed. Not all of these are probable to appear
|
||||
/// on most systems. A lot of this list is @wez trawling docs and
|
||||
/// making an entry for things that might be possible in this first pass.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, Ord, PartialOrd)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Deserialize,
|
||||
Serialize,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
FromDynamic,
|
||||
ToDynamic,
|
||||
)]
|
||||
pub enum KeyCode {
|
||||
/// The decoded unicode character
|
||||
Char(char),
|
||||
@ -438,7 +451,8 @@ impl ToString for KeyCode {
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
#[derive(Default, Deserialize, Serialize, FromDynamic, ToDynamic)]
|
||||
#[dynamic(into="String", try_from="String")]
|
||||
pub struct Modifiers: u8 {
|
||||
const NONE = 0;
|
||||
const SHIFT = 1<<1;
|
||||
@ -451,6 +465,42 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Modifiers {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(s: String) -> Result<Modifiers, String> {
|
||||
let mut mods = Modifiers::NONE;
|
||||
for ele in s.split('|') {
|
||||
// Allow for whitespace; debug printing Modifiers includes spaces
|
||||
// around the `|` so it is desirable to be able to reverse that
|
||||
// encoding here.
|
||||
let ele = ele.trim();
|
||||
if ele == "SHIFT" {
|
||||
mods |= Modifiers::SHIFT;
|
||||
} else if ele == "ALT" || ele == "OPT" || ele == "META" {
|
||||
mods |= Modifiers::ALT;
|
||||
} else if ele == "CTRL" {
|
||||
mods |= Modifiers::CTRL;
|
||||
} else if ele == "SUPER" || ele == "CMD" || ele == "WIN" {
|
||||
mods |= Modifiers::SUPER;
|
||||
} else if ele == "LEADER" {
|
||||
mods |= Modifiers::LEADER;
|
||||
} else if ele == "NONE" || ele == "" {
|
||||
mods |= Modifiers::NONE;
|
||||
} else {
|
||||
return Err(format!("invalid modifier name {} in {}", ele, s));
|
||||
}
|
||||
}
|
||||
Ok(mods)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for &Modifiers {
|
||||
fn into(self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Modifiers {
|
||||
fn to_string(&self) -> String {
|
||||
let mut s = String::new();
|
||||
@ -482,7 +532,20 @@ impl ToString for Modifiers {
|
||||
|
||||
/// These keycodes identify keys based on their physical
|
||||
/// position on an ANSI-standard US keyboard.
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Hash, Copy, Ord, PartialOrd)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Deserialize,
|
||||
Serialize,
|
||||
Clone,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Copy,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
FromDynamic,
|
||||
ToDynamic,
|
||||
)]
|
||||
pub enum PhysKeyCode {
|
||||
A,
|
||||
B,
|
||||
@ -1136,8 +1199,9 @@ impl KeyEvent {
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Deserialize, Serialize, FromDynamic, ToDynamic)]
|
||||
#[serde(try_from = "String")]
|
||||
#[dynamic(try_from = "String")]
|
||||
pub struct WindowDecorations: u8 {
|
||||
const TITLE = 1;
|
||||
const RESIZE = 2;
|
||||
|
Loading…
Reference in New Issue
Block a user