diff options
| author | Christian Duerr <chrisduerr@users.noreply.github.com> | 2019-01-17 09:17:26 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-01-17 09:17:26 +0000 |
| commit | 0d16478f5d997b6da5488885e15bfb09ca8e7f6d (patch) | |
| tree | 9905e264149d5955ce1161ecf41ad2f23ec9ec91 /src | |
| parent | 5864c30a54b250163c3a94f053f5f1b907adf9c9 (diff) | |
| download | r-alacritty-0d16478f5d997b6da5488885e15bfb09ca8e7f6d.tar.gz r-alacritty-0d16478f5d997b6da5488885e15bfb09ca8e7f6d.tar.bz2 r-alacritty-0d16478f5d997b6da5488885e15bfb09ca8e7f6d.zip | |
Make all configuration fields optional
All configuration fields now have fallback values which will be used if
the field is not present. This includes mouse, key bindings and platform
specific differences.
The mouse and key bindings are now filled by default, if the user
rebinds a default mapping, it will be overwritten. To unbind a default
binding, it can be mapped to `chars: ""`.
Since all platform differences can now be correctly handled by the
`src/config/mod.rs` code, it's no longer necessary to maintain separate
configuration files, so the `alacritty_macos.yml` and
`alacritty_windows.yml` have been deleted.
Fixes #40.
Fixes #1923.
Diffstat (limited to 'src')
| -rw-r--r-- | src/config/bindings.rs | 209 | ||||
| -rw-r--r-- | src/config/mod.rs (renamed from src/config.rs) | 788 | ||||
| -rw-r--r-- | src/input.rs | 46 | ||||
| -rw-r--r-- | src/renderer/mod.rs | 8 | ||||
| -rw-r--r-- | src/term/mod.rs | 6 | ||||
| -rw-r--r-- | src/url.rs | 2 |
6 files changed, 717 insertions, 342 deletions
diff --git a/src/config/bindings.rs b/src/config/bindings.rs new file mode 100644 index 00000000..701fadc1 --- /dev/null +++ b/src/config/bindings.rs @@ -0,0 +1,209 @@ +// Copyright 2016 Joe Wilm, The Alacritty Project Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +use glutin::{MouseButton, ModifiersState}; + +use crate::input::{MouseBinding, KeyBinding, Action}; +use crate::term::TermMode; +use super::Key; + +macro_rules! bindings { + ( + $ty:ident; + $( + $key:path + $(,[$($mod:ident: $enabled:expr),*])* + $(,+$mode:expr)* + $(,~$notmode:expr)* + ;$action:expr + );* + $(;)* + ) => {{ + let mut v = Vec::new(); + + $( + let mut _mods = ModifiersState { + $($($mod: $enabled),*,)* + ..Default::default() + }; + let mut _mode = TermMode::empty(); + $(_mode = $mode;)* + let mut _notmode = TermMode::empty(); + $(_notmode = $notmode;)* + + v.push($ty { + trigger: $key, + mods: _mods, + mode: _mode, + notmode: _notmode, + action: $action, + ..Default::default() + }); + )* + + v + }} +} + +pub fn default_mouse_bindings() -> Vec<MouseBinding> { + bindings!( + MouseBinding; + MouseButton::Middle; Action::PasteSelection; + ) +} + +pub fn default_key_bindings() -> Vec<KeyBinding> { + let mut bindings = bindings!( + KeyBinding; + Key::Paste; Action::Paste; + Key::Copy; Action::Copy; + Key::L, [ctrl: true]; Action::ClearLogNotice; + Key::L, [ctrl: true]; Action::Esc("\x0c".into()); + Key::Home, +TermMode::APP_CURSOR; Action::Esc("\x1bOH".into()); + Key::Home, ~TermMode::APP_CURSOR; Action::Esc("\x1b[H".into()); + Key::End, +TermMode::APP_CURSOR; Action::Esc("\x1bOF".into()); + Key::End, ~TermMode::APP_CURSOR; Action::Esc("\x1b[F".into()); + Key::PageUp, [shift: true]; Action::Esc("\x1b[5;2~".into()); + Key::PageUp, [ctrl: true]; Action::Esc("\x1b[5;5~".into()); + Key::PageUp; Action::Esc("\x1b[5~".into()); + Key::PageDown, [shift: true]; Action::Esc("\x1b[6;2~".into()); + Key::PageDown, [ctrl: true]; Action::Esc("\x1b[6;5~".into()); + Key::PageDown; Action::Esc("\x1b[6~".into()); + Key::Tab, [shift: true]; Action::Esc("\x1b[Z".into()); + Key::Back; Action::Esc("\x7f".into()); + Key::Back, [alt: true]; Action::Esc("\x1b\x7f".into()); + Key::Insert; Action::Esc("\x1b[2~".into()); + Key::Delete; Action::Esc("\x1b[3~".into()); + Key::Left, [shift: true]; Action::Esc("\x1b[1;2D".into()); + Key::Left, [ctrl: true]; Action::Esc("\x1b[1;5D".into()); + Key::Left, [alt: true]; Action::Esc("\x1b[1;3D".into()); + Key::Left, ~TermMode::APP_CURSOR; Action::Esc("\x1b[D".into()); + Key::Left, +TermMode::APP_CURSOR; Action::Esc("\x1bOD".into()); + Key::Right, [shift: true]; Action::Esc("\x1b[1;2C".into()); + Key::Right, [ctrl: true]; Action::Esc("\x1b[1;5C".into()); + Key::Right, [alt: true]; Action::Esc("\x1b[1;3C".into()); + Key::Right, ~TermMode::APP_CURSOR; Action::Esc("\x1b[C".into()); + Key::Right, +TermMode::APP_CURSOR; Action::Esc("\x1bOC".into()); + Key::Up, [shift: true]; Action::Esc("\x1b[1;2A".into()); + Key::Up, [ctrl: true]; Action::Esc("\x1b[1;5A".into()); + Key::Up, [alt: true]; Action::Esc("\x1b[1;3A".into()); + Key::Up, ~TermMode::APP_CURSOR; Action::Esc("\x1b[A".into()); + Key::Up, +TermMode::APP_CURSOR; Action::Esc("\x1bOA".into()); + Key::Down, [shift: true]; Action::Esc("\x1b[1;2B".into()); + Key::Down, [ctrl: true]; Action::Esc("\x1b[1;5B".into()); + Key::Down, [alt: true]; Action::Esc("\x1b[1;3B".into()); + Key::Down, ~TermMode::APP_CURSOR; Action::Esc("\x1b[B".into()); + Key::Down, +TermMode::APP_CURSOR; Action::Esc("\x1bOB".into()); + Key::F1; Action::Esc("\x1bOP".into()); + Key::F2; Action::Esc("\x1bOQ".into()); + Key::F3; Action::Esc("\x1bOR".into()); + Key::F4; Action::Esc("\x1bOS".into()); + Key::F5; Action::Esc("\x1b[15~".into()); + Key::F6; Action::Esc("\x1b[17~".into()); + Key::F7; Action::Esc("\x1b[18~".into()); + Key::F8; Action::Esc("\x1b[19~".into()); + Key::F9; Action::Esc("\x1b[20~".into()); + Key::F10; Action::Esc("\x1b[21~".into()); + Key::F11; Action::Esc("\x1b[23~".into()); + Key::F12; Action::Esc("\x1b[24~".into()); + Key::F1, [shift: true]; Action::Esc("\x1b[1;2P".into()); + Key::F2, [shift: true]; Action::Esc("\x1b[1;2Q".into()); + Key::F3, [shift: true]; Action::Esc("\x1b[1;2R".into()); + Key::F4, [shift: true]; Action::Esc("\x1b[1;2S".into()); + Key::F5, [shift: true]; Action::Esc("\x1b[15;2~".into()); + Key::F6, [shift: true]; Action::Esc("\x1b[17;2~".into()); + Key::F7, [shift: true]; Action::Esc("\x1b[18;2~".into()); + Key::F8, [shift: true]; Action::Esc("\x1b[19;2~".into()); + Key::F9, [shift: true]; Action::Esc("\x1b[20;2~".into()); + Key::F10, [shift: true]; Action::Esc("\x1b[21;2~".into()); + Key::F11, [shift: true]; Action::Esc("\x1b[23;2~".into()); + Key::F12, [shift: true]; Action::Esc("\x1b[24;2~".into()); + Key::F1, [ctrl: true]; Action::Esc("\x1b[1;5P".into()); + Key::F2, [ctrl: true]; Action::Esc("\x1b[1;5Q".into()); + Key::F3, [ctrl: true]; Action::Esc("\x1b[1;5R".into()); + Key::F4, [ctrl: true]; Action::Esc("\x1b[1;5S".into()); + Key::F5, [ctrl: true]; Action::Esc("\x1b[15;5~".into()); + Key::F6, [ctrl: true]; Action::Esc("\x1b[17;5~".into()); + Key::F7, [ctrl: true]; Action::Esc("\x1b[18;5~".into()); + Key::F8, [ctrl: true]; Action::Esc("\x1b[19;5~".into()); + Key::F9, [ctrl: true]; Action::Esc("\x1b[20;5~".into()); + Key::F10, [ctrl: true]; Action::Esc("\x1b[21;5~".into()); + Key::F11, [ctrl: true]; Action::Esc("\x1b[23;5~".into()); + Key::F12, [ctrl: true]; Action::Esc("\x1b[24;5~".into()); + Key::F1, [alt: true]; Action::Esc("\x1b[1;6P".into()); + Key::F2, [alt: true]; Action::Esc("\x1b[1;6Q".into()); + Key::F3, [alt: true]; Action::Esc("\x1b[1;6R".into()); + Key::F4, [alt: true]; Action::Esc("\x1b[1;6S".into()); + Key::F5, [alt: true]; Action::Esc("\x1b[15;6~".into()); + Key::F6, [alt: true]; Action::Esc("\x1b[17;6~".into()); + Key::F7, [alt: true]; Action::Esc("\x1b[18;6~".into()); + Key::F8, [alt: true]; Action::Esc("\x1b[19;6~".into()); + Key::F9, [alt: true]; Action::Esc("\x1b[20;6~".into()); + Key::F10, [alt: true]; Action::Esc("\x1b[21;6~".into()); + Key::F11, [alt: true]; Action::Esc("\x1b[23;6~".into()); + Key::F12, [alt: true]; Action::Esc("\x1b[24;6~".into()); + Key::F1, [logo: true]; Action::Esc("\x1b[1;3P".into()); + Key::F2, [logo: true]; Action::Esc("\x1b[1;3Q".into()); + Key::F3, [logo: true]; Action::Esc("\x1b[1;3R".into()); + Key::F4, [logo: true]; Action::Esc("\x1b[1;3S".into()); + Key::F5, [logo: true]; Action::Esc("\x1b[15;3~".into()); + Key::F6, [logo: true]; Action::Esc("\x1b[17;3~".into()); + Key::F7, [logo: true]; Action::Esc("\x1b[18;3~".into()); + Key::F8, [logo: true]; Action::Esc("\x1b[19;3~".into()); + Key::F9, [logo: true]; Action::Esc("\x1b[20;3~".into()); + Key::F10, [logo: true]; Action::Esc("\x1b[21;3~".into()); + Key::F11, [logo: true]; Action::Esc("\x1b[23;3~".into()); + Key::F12, [logo: true]; Action::Esc("\x1b[24;3~".into()); + Key::NumpadEnter; Action::Esc("\n".into()); + ); + + bindings.extend(platform_key_bindings()); + + bindings +} + +#[cfg(not(any(target_os = "macos", test)))] +pub fn platform_key_bindings() -> Vec<KeyBinding> { + bindings!( + KeyBinding; + Key::V, [ctrl: true, shift: true]; Action::Paste; + Key::C, [ctrl: true, shift: true]; Action::Copy; + Key::Insert, [shift: true]; Action::PasteSelection; + Key::Key0, [ctrl: true]; Action::ResetFontSize; + Key::Equals, [ctrl: true]; Action::IncreaseFontSize; + Key::Subtract, [ctrl: true]; Action::DecreaseFontSize; + ) +} + +#[cfg(all(target_os = "macos", not(test)))] +pub fn platform_key_bindings() -> Vec<KeyBinding> { + bindings!( + KeyBinding; + Key::Key0, [logo: true]; Action::ResetFontSize; + Key::Equals, [logo: true]; Action::IncreaseFontSize; + Key::Minus, [logo: true]; Action::DecreaseFontSize; + Key::K, [logo: true]; Action::ClearHistory; + Key::K, [logo: true]; Action::Esc("\x0c".into()); + Key::V, [logo: true]; Action::Paste; + Key::C, [logo: true]; Action::Copy; + Key::H, [logo: true]; Action::Hide; + Key::Q, [logo: true]; Action::Quit; + Key::W, [logo: true]; Action::Quit; + ) +} + +// Don't return any bindings for tests since they are commented-out by default +#[cfg(test)] +pub fn platform_key_bindings() -> Vec<KeyBinding> { + vec![] +} diff --git a/src/config.rs b/src/config/mod.rs index 200acbfe..fd40776d 100644 --- a/src/config.rs +++ b/src/config/mod.rs @@ -20,7 +20,6 @@ use serde::{self, de, Deserialize}; use serde::de::Error as SerdeError; use serde::de::{Visitor, MapAccess, Unexpected}; use notify::{Watcher, watcher, DebouncedEvent, RecursiveMode}; - use glutin::ModifiersState; use crate::cli::Options; @@ -28,32 +27,50 @@ use crate::input::{Action, Binding, MouseBinding, KeyBinding}; use crate::index::{Line, Column}; use crate::ansi::{CursorStyle, NamedColor, Color}; -const MAX_SCROLLBACK_LINES: u32 = 100_000; +mod bindings; -/// Function that returns true for serde default -fn true_bool() -> bool { - true -} +const MAX_SCROLLBACK_LINES: u32 = 100_000; +static DEFAULT_ALACRITTY_CONFIG: &'static str = + include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml")); -#[derive(Clone, Debug, Deserialize)] +#[serde(default)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] pub struct Selection { + #[serde(deserialize_with = "deserialize_escape_chars")] pub semantic_escape_chars: String, - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub save_to_clipboard: bool, } impl Default for Selection { fn default() -> Selection { Selection { - semantic_escape_chars: String::new(), - save_to_clipboard: false + semantic_escape_chars: default_escape_chars(), + save_to_clipboard: Default::default(), } } } -#[derive(Clone, Debug, Deserialize)] +fn deserialize_escape_chars<'a, D>(deserializer: D) -> ::std::result::Result<String, D::Error> + where D: de::Deserializer<'a> +{ + match String::deserialize(deserializer) { + Ok(escape_chars) => Ok(escape_chars), + Err(err) => { + error!("Problem with config: {}; using default value", err); + Ok(default_escape_chars()) + }, + } +} + +fn default_escape_chars() -> String { + String::from(",│`|:\"' ()[]{}<>") +} + +#[serde(default)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] pub struct ClickHandler { - #[serde(deserialize_with="deserialize_duration_ms")] + #[serde(deserialize_with = "deserialize_duration_ms")] pub threshold: Duration, } @@ -79,58 +96,57 @@ fn deserialize_duration_ms<'a, D>(deserializer: D) -> ::std::result::Result<Dura } } -#[derive(Clone, Debug, Deserialize)] +#[serde(default)] +#[derive(Default, Clone, Debug, Deserialize, PartialEq, Eq)] pub struct Mouse { - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub double_click: ClickHandler, - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub triple_click: ClickHandler, - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub hide_when_typing: bool, - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub url: Url, // TODO: DEPRECATED - #[serde(default)] pub faux_scrollback_lines: Option<usize>, } -#[derive(Default, Clone, Debug, Deserialize)] +#[serde(default)] +#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] pub struct Url { // Program for opening links - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub launcher: Option<CommandWrapper>, // Modifier used to open links - #[serde(default, deserialize_with = "deserialize_modifiers")] + #[serde(deserialize_with = "deserialize_modifiers")] pub modifiers: ModifiersState, } +impl Default for Url { + fn default() -> Url { + Url { + #[cfg(not(any(target_os = "macos", windows)))] + launcher: Some(CommandWrapper::Just(String::from("xdg-open"))), + #[cfg(target_os = "macos")] + launcher: Some(CommandWrapper::Just(String::from("open"))), + #[cfg(windows)] + launcher: Some(CommandWrapper::Just(String::from("explorer"))), + modifiers: Default::default(), + } + } +} + fn deserialize_modifiers<'a, D>(deserializer: D) -> ::std::result::Result<ModifiersState, D::Error> where D: de::Deserializer<'a> { ModsWrapper::deserialize(deserializer).map(|wrapper| wrapper.into_inner()) } -impl Default for Mouse { - fn default() -> Mouse { - Mouse { - double_click: ClickHandler { - threshold: Duration::from_millis(300), - }, - triple_click: ClickHandler { - threshold: Duration::from_millis(300), - }, - hide_when_typing: false, - url: Url::default(), - faux_scrollback_lines: None, - } - } -} - /// `VisualBellAnimations` are modeled after a subset of CSS transitions and Robert /// Penner's Easing Functions. -#[derive(Clone, Copy, Debug, Deserialize)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)] pub enum VisualBellAnimation { Ease, // CSS EaseOut, // CSS @@ -150,30 +166,29 @@ impl Default for VisualBellAnimation { } } -#[derive(Debug, Deserialize)] +#[serde(default)] +#[derive(Debug, Deserialize, PartialEq, Eq)] pub struct VisualBellConfig { /// Visual bell animation function - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] animation: VisualBellAnimation, /// Visual bell duration in milliseconds - #[serde(default, deserialize_with = "deserialize_visual_bell_duration")] + #[serde(deserialize_with = "failure_default")] duration: u16, /// Visual bell flash color - #[serde(default="default_visual_bell_color", deserialize_with = "rgb_from_hex")] + #[serde(deserialize_with = "rgb_from_hex")] color: Rgb, } -fn deserialize_visual_bell_duration<'a, D>(deserializer: D) -> ::std::result::Result<u16, D::Error> - where D: de::Deserializer<'a> -{ - match u16::deserialize(deserializer) { - Ok(duration) => Ok(duration), - Err(err) => { - error!("Problem with config: {}; using default value", err); - Ok(0) - }, +impl Default for VisualBellConfig { + fn default() -> VisualBellConfig { + VisualBellConfig { + animation: Default::default(), + duration: Default::default(), + color: default_visual_bell_color(), + } } } @@ -201,17 +216,7 @@ impl VisualBellConfig { } } -impl Default for VisualBellConfig { - fn default() -> VisualBellConfig { - VisualBellConfig { - animation: VisualBellAnimation::default(), - color: default_visual_bell_color(), - duration: 0, - } - } -} - -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, PartialEq, Eq)] pub struct Shell<'a> { program: Cow<'a, str>, @@ -248,7 +253,7 @@ impl<'a> Shell<'a> { } /// Wrapper around f32 that represents an alpha value between 0.0 and 1.0 -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Alpha(f32); impl Alpha { @@ -282,7 +287,7 @@ impl Default for Alpha { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum Decorations { Full, Transparent, @@ -373,29 +378,42 @@ impl<'de> Deserialize<'de> for Decorations { } } -#[derive(Debug, Copy, Clone, Deserialize)] +#[serde(default)] +#[derive(Debug, Copy, Clone, Deserialize, PartialEq, Eq)] pub struct WindowConfig { /// Initial dimensions #[serde(default, deserialize_with = "failure_default")] dimensions: Dimensions, /// Pixel padding - #[serde(default="default_padding", deserialize_with = "deserialize_padding")] + #[serde(deserialize_with = "deserialize_padding")] padding: Delta<u8>, /// Draw the window with title bar / borders - #[serde(default)] + #[serde(deserialize_with = "failure_default")] decorations: Decorations, /// Spread out additional padding evenly - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] dynamic_padding: bool, /// Start maximized - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] start_maximized: bool, } +impl Default for WindowConfig { + fn default() -> Self { + WindowConfig{ + dimensions: Default::default(), + padding: default_padding(), + decorations: Default::default(), + dynamic_padding: Default::default(), + start_maximized: Default::default(), + } + } +} + fn default_padding() -> Delta<u8> { Delta { x: 2, y: 2 } } @@ -426,20 +444,8 @@ impl WindowConfig { } } -impl Default for WindowConfig { - fn default() -> Self { - WindowConfig{ - dimensions: Default::default(), - padding: default_padding(), - decorations: Default::default(), - dynamic_padding: false, - start_maximized: false, - } - } -} - /// Top-level config type -#[derive(Debug, Deserialize)] +#[derive(Debug, PartialEq, Deserialize)] pub struct Config { /// Initial dimensions #[serde(default, deserialize_with = "failure_default")] @@ -462,7 +468,7 @@ pub struct Config { render_timer: bool, /// Should draw bold text with brighter colors instead of bold font - #[serde(default="true_bool", deserialize_with = "default_true_bool")] + #[serde(default = "default_true_bool", deserialize_with = "deserialize_true_bool")] draw_bold_text_with_bright_colors: bool, #[serde(default, deserialize_with = "failure_default")] @@ -477,11 +483,11 @@ pub struct Config { window: WindowConfig, /// Keybindings - #[serde(default, deserialize_with = "failure_default_vec")] + #[serde(default="default_key_bindings", deserialize_with = "deserialize_key_bindings")] key_bindings: Vec<KeyBinding>, /// Bindings for the mouse - #[serde(default, deserialize_with = "failure_default_vec")] + #[serde(default="default_mouse_bindings", deserialize_with = "deserialize_mouse_bindings")] mouse_bindings: Vec<MouseBinding>, #[serde(default, deserialize_with = "failure_default")] @@ -503,50 +509,95 @@ pub struct Config { visual_bell: VisualBellConfig, /// Use dynamic title - #[serde(default="true_bool", deserialize_with = "default_true_bool")] + #[serde(default = "default_true_bool", deserialize_with = "deserialize_true_bool")] dynamic_title: bool, /// Live config reload - #[serde(default="true_bool", deserialize_with = "default_true_bool")] + #[serde(default = "default_true_bool", deserialize_with = "deserialize_true_bool")] live_config_reload: bool, /// Number of spaces in one tab - #[serde(default="default_tabspaces", deserialize_with = "deserialize_tabspaces")] + #[serde(default = "default_tabspaces", deserialize_with = "deserialize_tabspaces")] tabspaces: usize, /// How much scrolling history to keep - #[serde(default, deserialize_with="failure_default")] + #[serde(default, deserialize_with = "failure_default")] scrolling: Scrolling, /// Cursor configuration - #[serde(default, deserialize_with="failure_default")] + #[serde(default, deserialize_with = "failure_default")] cursor: Cursor, /// Keep the log file after quitting - #[serde(default, deserialize_with="failure_default")] + #[serde(default, deserialize_with = "failure_default")] persistent_logging: bool, - // TODO: DEPRECATED + /// Enable experimental conpty backend instead of using winpty. + /// Will only take effect on Windows 10 Oct 2018 and later. + #[cfg(windows)] #[serde(default, deserialize_with = "failure_default")] + enable_experimental_conpty_backend: bool, + + // TODO: DEPRECATED custom_cursor_colors: Option<bool>, // TODO: DEPRECATED - #[serde(default, deserialize_with = "failure_default")] hide_cursor_when_typing: Option<bool>, // TODO: DEPRECATED - #[serde(default, deserialize_with = "failure_default")] cursor_style: Option<CursorStyle>, // TODO: DEPRECATED - #[serde(default, deserialize_with = "failure_default")] unfocused_hollow_cursor: Option<bool>, +} - /// Enable experimental conpty backend instead of using winpty. - /// Will only take effect on Windows 10 Oct 2018 and later. - #[cfg(windows)] - #[serde(default, deserialize_with="failure_default")] - enable_experimental_conpty_backend: bool +impl Default for Config { + fn default() -> Self { + serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG) + .expect("default config is invalid") + } +} + +fn default_key_bindings() -> Vec<KeyBinding> { + bindings::default_key_bindings() +} + +fn default_mouse_bindings() -> Vec<MouseBinding> { + bindings::default_mouse_bindings() +} + +fn deserialize_key_bindings<'a, D>(deserializer: D) + -> ::std::result::Result<Vec<KeyBinding>, D::Error> +where + D: de::Deserializer<'a>, +{ + deserialize_bindings(deserializer, bindings::default_key_bindings()) +} + +fn deserialize_mouse_bindings<'a, D>(deserializer: D) + -> ::std::result::Result<Vec<MouseBinding>, D::Error> +where + D: de::Deserializer<'a>, +{ + deserialize_bindings(deserializer, bindings::default_mouse_bindings()) +} + +fn deserialize_bindings<'a, D, T>(deserializer: D, mut default: Vec<Binding<T>>) + -> ::std::result::Result<Vec<Binding<T>>, D::Error> +where + D: de::Deserializer<'a>, + T: Copy + Eq + std::hash::Hash + std::fmt::Debug, + Binding<T>: de::Deserialize<'a>, +{ + let mut bindings: Vec<Binding<T>> = failure_default_vec(deserializer)?; + + for binding in bindings.iter() { + default.retain(|b| !b.triggers_match(binding)); + } + + bindings.extend(default); + + Ok(bindings) } fn failure_default_vec<'a, D, T>(deserializer: D) -> ::std::result::Result<Vec<T>, D::Error> @@ -592,7 +643,7 @@ fn deserialize_tabspaces<'a, D>(deserializer: D) -> ::std::result::Result<usize, } } -fn default_true_bool<'a, D>(deserializer: D) -> ::std::result::Result<bool, D::Error> +fn deserialize_true_bool<'a, D>(deserializer: D) -> ::std::result::Result<bool, D::Error> where D: de::Deserializer<'a> { match bool::deserialize(deserializer) { @@ -604,6 +655,10 @@ fn default_true_bool<'a, D>(deserializer: D) -> ::std::result::Result<bool, D::E } } +fn default_true_bool() -> bool { + true +} + fn failure_default<'a, D, T>(deserializer: D) -> ::std::result::Result<T, D::Error> where D: de::Deserializer<'a>, @@ -618,56 +673,40 @@ fn failure_default<'a, D, T>(deserializer: D) } } -#[cfg(not(any(windows, target_os="macos")))] -static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty.yml"); -#[cfg(target_os="macos")] -static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty_macos.yml"); -#[cfg(windows)] -static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty_windows.yml"); - -impl Default for Config { - fn default() -> Self { - serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG) - .expect("default config is invalid") - } -} - /// Struct for scrolling related settings -#[derive(Copy, Clone, Debug, Deserialize)] +#[serde(default)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)] pub struct Scrolling { - #[serde(deserialize_with="deserialize_scrolling_history")] - #[serde(default="default_scrolling_history")] + #[serde(deserialize_with = "deserialize_scrolling_history")] pub history: u32, - #[serde(deserialize_with="deserialize_scrolling_multiplier")] - #[serde(default="default_scrolling_multiplier")] + #[serde(deserialize_with = "deserialize_scrolling_multiplier")] pub multiplier: u8, - #[serde(deserialize_with="deserialize_scrolling_multiplier")] - #[serde(default="default_scrolling_multiplier")] + #[serde(deserialize_with = "deserialize_scrolling_multiplier")] pub faux_multiplier: u8, - #[serde(default, deserialize_with="failure_default")] + #[serde(deserialize_with = "failure_default")] pub auto_scroll: bool, } -fn default_scrolling_history() -> u32 { - 10_000 -} - -// Default for normal and faux scrolling -fn default_scrolling_multiplier() -> u8 { - 3 -} - impl Default for Scrolling { fn default() -> Self { Self { history: default_scrolling_history(), multiplier: default_scrolling_multiplier(), faux_multiplier: default_scrolling_multiplier(), - auto_scroll: false, + auto_scroll: Default::default(), } } } +fn default_scrolling_history() -> u32 { + 10_000 +} + +// Default for normal and faux scrolling +fn default_scrolling_multiplier() -> u8 { + 3 +} + fn deserialize_scrolling_history<'a, D>(deserializer: D) -> ::std::result::Result<u32, D::Error> where D: de::Deserializer<'a> { @@ -739,6 +778,7 @@ impl<'a> de::Deserialize<'a> for ModsWrapper { "Shift" => res.shift = true, "Alt" | "Option" => res.alt = true, "Control" => res.ctrl = true, + "None" => (), _ => error!("Unknown modifier {:?}", modifier), } } @@ -771,7 +811,8 @@ impl<'a> de::Deserialize<'a> for ActionWrapper { fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Paste, Copy, PasteSelection, IncreaseFontSize, DecreaseFontSize, \ ResetFontSize, ScrollPageUp, ScrollPageDown, ScrollToTop, \ - ScrollToBottom, ClearHistory, Hide, ClearLogNotice, SpawnNewInstance or Quit") + ScrollToBottom, ClearHistory, Hide, ClearLogNotice, SpawnNewInstance, \ + None or Quit") } fn visit_str<E>(self, value: &str) -> ::std::result::Result<ActionWrapper, E> @@ -793,6 +834,7 @@ impl<'a> de::Deserialize<'a> for ActionWrapper { "Quit" => Action::Quit, "ClearLogNotice" => Action::ClearLogNotice, "SpawnNewInstance" => Action::SpawnNewInstance, + "None" => Action::None, _ => return Err(E::invalid_value(Unexpected::Str(value), &self)), })) } @@ -801,8 +843,8 @@ impl<'a> de::Deserialize<'a> for ActionWrapper { } } -#[derive(Debug, Deserialize, Clone)] #[serde(untagged)] +#[derive(Debug, Deserialize, Clone, PartialEq, Eq)] pub enum CommandWrapper { Just(String), WithArgs { @@ -918,6 +960,7 @@ impl<'a> de::Deserialize<'a> for MouseButton { /// Bindings are deserialized into a `RawBinding` before being parsed as a /// `KeyBinding` or `MouseBinding`. +#[derive(PartialEq, Eq)] struct RawBinding { key: Option<Key>, mouse: Option<::glutin::MouseButton>, @@ -1196,21 +1239,87 @@ pub enum Error { Yaml(serde_yaml::Error), } -#[derive(Debug, Deserialize)] +#[serde(default)] +#[derive(Debug, Deserialize, PartialEq, Eq)] pub struct Colors { - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub primary: PrimaryColors, - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub cursor: CursorColors, + #[serde(deserialize_with = "deserialize_normal_colors")] pub normal: AnsiColors, + #[serde(deserialize_with = "deserialize_bright_colors")] pub bright: AnsiColors, - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub dim: Option<AnsiColors>, - #[serde(default, deserialize_with = "failure_default_vec")] + #[serde(deserialize_with = "failure_default_vec")] pub indexed_colors: Vec<IndexedColor>, } -#[derive(Debug, Deserialize)] +impl Default for Colors { + fn default() -> Colors { + Colors { + primary: Default::default(), + cursor: Default::default(), + normal: default_normal_colors(), + bright: default_bright_colors(), + dim: Default::default(), + indexed_colors: Default::default(), + } + } +} + +fn default_normal_colors() -> AnsiColors { + AnsiColors { + black: Rgb {r: 0x00, g: 0x00, b: 0x00}, + red: Rgb {r: 0xd5, g: 0x4e, b: 0x53}, + green: Rgb {r: 0xb9, g: 0xca, b: 0x4a}, + yellow: Rgb {r: 0xe6, g: 0xc5, b: 0x47}, + blue: Rgb {r: 0x7a, g: 0xa6, b: 0xda}, + magenta: Rgb {r: 0xc3, g: 0x97, b: 0xd8}, + cyan: Rgb {r: 0x70, g: 0xc0, b: 0xba}, + white: Rgb {r: 0xea, g: 0xea, b: 0xea}, + } +} + +fn default_bright_colors() -> AnsiColors { + AnsiColors { + black: Rgb {r: 0x66, g: 0x66, b: 0x66}, + red: Rgb {r: 0xff, g: 0x33, b: 0x34}, + green: Rgb {r: 0x9e, g: 0xc4, b: 0x00}, + yellow: Rgb {r: 0xe7, g: 0xc5, b: 0x47}, + blue: Rgb {r: 0x7a, g: 0xa6, b: 0xda}, + magenta: Rgb {r: 0xb7, g: 0x7e, b: 0xe0}, + cyan: Rgb {r: 0x54, g: 0xce, b: 0xd6}, + white: Rgb {r: 0xff, g: 0xff, b: 0xff}, + } +} + +fn deserialize_normal_colors<'a, D>(deserializer: D) -> ::std::result::Result<AnsiColors, D::Error> + where D: de::Deserializer<'a> +{ + match AnsiColors::deserialize(deserializer) { + Ok(escape_chars) => Ok(escape_chars), + Err(err) => { + error!("Problem with config: {}; using default value", err); + Ok(default_normal_colors()) + }, + } +} + +fn deserialize_bright_colors<'a, D>(deserializer: D) -> ::std::result::Result<AnsiColors, D::Error> + where D: de::Deserializer<'a> +{ + match AnsiColors::deserialize(deserializer) { + Ok(escape_chars) => Ok(escape_chars), + Err(err) => { + error!("Problem with config: {}; using default value", err); + Ok(default_bright_colors()) + }, + } +} + +#[derive(Debug, Deserialize, PartialEq, Eq)] pub struct IndexedColor { #[serde(deserialize_with = "deserialize_color_index")] pub index: u8, @@ -1246,11 +1355,12 @@ fn deserialize_color_index<'a, D>(deserializer: D) -> ::std::result::Result<u8, } } -#[derive(Copy, Clone, Debug, Deserialize)] +#[serde(default)] +#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq)] pub struct Cursor { - #[serde(default, deserialize_with = "failure_default")] + #[serde(deserialize_with = "failure_default")] pub style: CursorStyle, - #[serde(default="true_bool", deserialize_with = "default_true_bool")] + #[serde(deserialize_with = "deserialize_true_bool")] pub unfocused_hollow: bool, } @@ -1263,26 +1373,39 @@ impl Default for Cursor { } } -#[derive(Debug, Copy, Clone, Default, Deserialize)] +#[serde(default)] +#[derive(Debug, Copy, Clone, Default, Deserialize, PartialEq, Eq)] pub struct CursorColors { - #[serde(default, deserialize_with = "deserialize_optional_color")] + #[serde(deserialize_with = "deserialize_optional_color")] pub text: Option<Rgb>, - #[serde(default, deserialize_with = "deserialize_optional_color")] + #[serde(deserialize_with = "deserialize_optional_color")] pub cursor: Option<Rgb>, } -#[derive(Debug, Deserialize)] +#[serde(default)] +#[derive(Debug, Deserialize, PartialEq, Eq)] pub struct PrimaryColors { #[serde(deserialize_with = "rgb_from_hex")] pub background: Rgb, #[serde(deserialize_with = "rgb_from_hex")] pub foreground: Rgb, - #[serde(default, deserialize_with = "deserialize_optional_color")] + #[serde(deserialize_with = "deserialize_optional_color")] pub bright_foreground: Option<Rgb>, - #[serde(default, deserialize_with = "deserialize_optional_color")] + #[serde(deserialize_with = "deserialize_optional_color")] pub dim_foreground: Option<Rgb>, } +impl Default for PrimaryColors { + fn default() -> Self { + PrimaryColors { |