summaryrefslogtreecommitdiff
path: root/src/config.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs2516
1 files changed, 0 insertions, 2516 deletions
diff --git a/src/config.rs b/src/config.rs
deleted file mode 100644
index 200acbfe..00000000
--- a/src/config.rs
+++ /dev/null
@@ -1,2516 +0,0 @@
-//! Configuration definitions and file loading
-//!
-//! Alacritty reads from a config file at startup to determine various runtime
-//! parameters including font family and style, font size, etc. In the future,
-//! the config file will also hold user and platform specific keybindings.
-use std::borrow::Cow;
-use std::{env, fmt};
-use std::fs::{self, File};
-use std::io::{self, Read, Write};
-use std::path::{Path, PathBuf};
-use std::str::FromStr;
-use std::sync::mpsc;
-use std::time::Duration;
-use std::collections::HashMap;
-
-use crate::Rgb;
-use font::Size;
-use serde_yaml;
-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;
-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;
-
-/// Function that returns true for serde default
-fn true_bool() -> bool {
- true
-}
-
-#[derive(Clone, Debug, Deserialize)]
-pub struct Selection {
- pub semantic_escape_chars: String,
- #[serde(default, 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
- }
- }
-}
-
-#[derive(Clone, Debug, Deserialize)]
-pub struct ClickHandler {
- #[serde(deserialize_with="deserialize_duration_ms")]
- pub threshold: Duration,
-}
-
-impl Default for ClickHandler {
- fn default() -> Self {
- ClickHandler { threshold: default_threshold_ms() }
- }
-}
-
-fn default_threshold_ms() -> Duration {
- Duration::from_millis(300)
-}
-
-fn deserialize_duration_ms<'a, D>(deserializer: D) -> ::std::result::Result<Duration, D::Error>
- where D: de::Deserializer<'a>
-{
- match u64::deserialize(deserializer) {
- Ok(threshold_ms) => Ok(Duration::from_millis(threshold_ms)),
- Err(err) => {
- error!("Problem with config: {}; using default value", err);
- Ok(default_threshold_ms())
- },
- }
-}
-
-#[derive(Clone, Debug, Deserialize)]
-pub struct Mouse {
- #[serde(default, deserialize_with = "failure_default")]
- pub double_click: ClickHandler,
- #[serde(default, deserialize_with = "failure_default")]
- pub triple_click: ClickHandler,
- #[serde(default, deserialize_with = "failure_default")]
- pub hide_when_typing: bool,
- #[serde(default, deserialize_with = "failure_default")]
- pub url: Url,
-
- // TODO: DEPRECATED
- #[serde(default)]
- pub faux_scrollback_lines: Option<usize>,
-}
-
-#[derive(Default, Clone, Debug, Deserialize)]
-pub struct Url {
- // Program for opening links
- #[serde(default, deserialize_with = "failure_default")]
- pub launcher: Option<CommandWrapper>,
-
- // Modifier used to open links
- #[serde(default, deserialize_with = "deserialize_modifiers")]
- pub modifiers: ModifiersState,
-}
-
-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)]
-pub enum VisualBellAnimation {
- Ease, // CSS
- EaseOut, // CSS
- EaseOutSine, // Penner
- EaseOutQuad, // Penner
- EaseOutCubic, // Penner
- EaseOutQuart, // Penner
- EaseOutQuint, // Penner
- EaseOutExpo, // Penner
- EaseOutCirc, // Penner
- Linear,
-}
-
-impl Default for VisualBellAnimation {
- fn default() -> Self {
- VisualBellAnimation::EaseOutExpo
- }
-}
-
-#[derive(Debug, Deserialize)]
-pub struct VisualBellConfig {
- /// Visual bell animation function
- #[serde(default, deserialize_with = "failure_default")]
- animation: VisualBellAnimation,
-
- /// Visual bell duration in milliseconds
- #[serde(default, deserialize_with = "deserialize_visual_bell_duration")]
- duration: u16,
-
- /// Visual bell flash color
- #[serde(default="default_visual_bell_color", 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)
- },
- }
-}
-
-fn default_visual_bell_color() -> Rgb {
- Rgb { r: 255, g: 255, b: 255 }
-}
-
-impl VisualBellConfig {
- /// Visual bell animation
- #[inline]
- pub fn animation(&self) -> VisualBellAnimation {
- self.animation
- }
-
- /// Visual bell duration in milliseconds
- #[inline]
- pub fn duration(&self) -> Duration {
- Duration::from_millis(u64::from(self.duration))
- }
-
- /// Visual bell flash color
- #[inline]
- pub fn color(&self) -> Rgb {
- self.color
- }
-}
-
-impl Default for VisualBellConfig {
- fn default() -> VisualBellConfig {
- VisualBellConfig {
- animation: VisualBellAnimation::default(),
- color: default_visual_bell_color(),
- duration: 0,
- }
- }
-}
-
-#[derive(Debug, Deserialize)]
-pub struct Shell<'a> {
- program: Cow<'a, str>,
-
- #[serde(default, deserialize_with = "failure_default")]
- args: Vec<String>,
-}
-
-impl<'a> Shell<'a> {
- pub fn new<S>(program: S) -> Shell<'a>
- where S: Into<Cow<'a, str>>
- {
- Shell {
- program: program.into(),
- args: Vec::new(),
- }
- }
-
- pub fn new_with_args<S>(program: S, args: Vec<String>) -> Shell<'a>
- where S: Into<Cow<'a, str>>
- {
- Shell {
- program: program.into(),
- args,
- }
- }
-
- pub fn program(&self) -> &str {
- &*self.program
- }
-
- pub fn args(&self) -> &[String] {
- self.args.as_slice()
- }
-}
-
-/// Wrapper around f32 that represents an alpha value between 0.0 and 1.0
-#[derive(Clone, Copy, Debug)]
-pub struct Alpha(f32);
-
-impl Alpha {
- pub fn new(value: f32) -> Self {
- Alpha(Self::clamp_to_valid_range(value))
- }
-
- pub fn set(&mut self, value: f32) {
- self.0 = Self::clamp_to_valid_range(value);
- }
-
- #[inline]
- pub fn get(self) -> f32 {
- self.0
- }
-
- fn clamp_to_valid_range(value: f32) -> f32 {
- if value < 0.0 {
- 0.0
- } else if value > 1.0 {
- 1.0
- } else {
- value
- }
- }
-}
-
-impl Default for Alpha {
- fn default() -> Self {
- Alpha(1.0)
- }
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum Decorations {
- Full,
- Transparent,
- Buttonless,
- None,
-}
-
-impl Default for Decorations {
- fn default() -> Decorations {
- Decorations::Full
- }
-}
-
-impl<'de> Deserialize<'de> for Decorations {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Decorations, D::Error>
- where D: de::Deserializer<'de>
- {
-
- struct DecorationsVisitor;
-
- impl<'de> Visitor<'de> for DecorationsVisitor {
- type Value = Decorations;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("Some subset of full|transparent|buttonless|none")
- }
-
- #[cfg(target_os = "macos")]
- fn visit_str<E>(self, value: &str) -> ::std::result::Result<Decorations, E>
- where E: de::Error
- {
- match value.to_lowercase().as_str() {
- "transparent" => Ok(Decorations::Transparent),
- "buttonless" => Ok(Decorations::Buttonless),
- "none" => Ok(Decorations::None),
- "full" => Ok(Decorations::Full),
- "true" => {
- error!("Deprecated decorations boolean value, \
- use one of transparent|buttonless|none|full instead; \
- falling back to \"full\"");
- Ok(Decorations::Full)
- },
- "false" => {
- error!("Deprecated decorations boolean value, \
- use one of transparent|buttonless|none|full instead; \
- falling back to \"none\"");
- Ok(Decorations::None)
- },
- _ => {
- error!("Invalid decorations value: {}; using default value", value);
- Ok(Decorations::Full)
- }
- }
- }
-
- #[cfg(not(target_os = "macos"))]
- fn visit_str<E>(self, value: &str) -> ::std::result::Result<Decorations, E>
- where E: de::Error
- {
- match value.to_lowercase().as_str() {
- "none" => Ok(Decorations::None),
- "full" => Ok(Decorations::Full),
- "true" => {
- error!("Deprecated decorations boolean value, \
- use one of none|full instead; \
- falling back to \"full\"");
- Ok(Decorations::Full)
- },
- "false" => {
- error!("Deprecated decorations boolean value, \
- use one of none|full instead; \
- falling back to \"none\"");
- Ok(Decorations::None)
- },
- "transparent" | "buttonless" => {
- error!("macOS-only decorations value: {}; using default value", value);
- Ok(Decorations::Full)
- },
- _ => {
- error!("Invalid decorations value: {}; using default value", value);
- Ok(Decorations::Full)
- }
- }
- }
- }
-
- deserializer.deserialize_str(DecorationsVisitor)
- }
-}
-
-#[derive(Debug, Copy, Clone, Deserialize)]
-pub struct WindowConfig {
- /// Initial dimensions
- #[serde(default, deserialize_with = "failure_default")]
- dimensions: Dimensions,
-
- /// Pixel padding
- #[serde(default="default_padding", deserialize_with = "deserialize_padding")]
- padding: Delta<u8>,
-
- /// Draw the window with title bar / borders
- #[serde(default)]
- decorations: Decorations,
-
- /// Spread out additional padding evenly
- #[serde(default, deserialize_with = "failure_default")]
- dynamic_padding: bool,
-
- /// Start maximized
- #[serde(default, deserialize_with = "failure_default")]
- start_maximized: bool,
-}
-
-fn default_padding() -> Delta<u8> {
- Delta { x: 2, y: 2 }
-}
-
-fn deserialize_padding<'a, D>(deserializer: D) -> ::std::result::Result<Delta<u8>, D::Error>
- where D: de::Deserializer<'a>
-{
- match Delta::deserialize(deserializer) {
- Ok(delta) => Ok(delta),
- Err(err) => {
- error!("Problem with config: {}; using default value", err);
- Ok(default_padding())
- },
- }
-}
-
-impl WindowConfig {
- pub fn decorations(&self) -> Decorations {
- self.decorations
- }
-
- pub fn dynamic_padding(&self) -> bool {
- self.dynamic_padding
- }
-
- pub fn start_maximized(&self) -> bool {
- self.start_maximized
- }
-}
-
-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)]
-pub struct Config {
- /// Initial dimensions
- #[serde(default, deserialize_with = "failure_default")]
- dimensions: Option<Dimensions>,
-
- /// Pixel padding
- #[serde(default, deserialize_with = "failure_default")]
- padding: Option<Delta<u8>>,
-
- /// TERM env variable
- #[serde(default, deserialize_with = "failure_default")]
- env: HashMap<String, String>,
-
- /// Font configuration
- #[serde(default, deserialize_with = "failure_default")]
- font: Font,
-
- /// Should show render timer
- #[serde(default, deserialize_with = "failure_default")]
- render_timer: bool,
-
- /// Should draw bold text with brighter colors instead of bold font
- #[serde(default="true_bool", deserialize_with = "default_true_bool")]
- draw_bold_text_with_bright_colors: bool,
-
- #[serde(default, deserialize_with = "failure_default")]
- colors: Colors,
-
- /// Background opacity from 0.0 to 1.0
- #[serde(default, deserialize_with = "failure_default")]
- background_opacity: Alpha,
-
- /// Window configuration
- #[serde(default, deserialize_with = "failure_default")]
- window: WindowConfig,
-
- /// Keybindings
- #[serde(default, deserialize_with = "failure_default_vec")]
- key_bindings: Vec<KeyBinding>,
-
- /// Bindings for the mouse
- #[serde(default, deserialize_with = "failure_default_vec")]
- mouse_bindings: Vec<MouseBinding>,
-
- #[serde(default, deserialize_with = "failure_default")]
- selection: Selection,
-
- #[serde(default, deserialize_with = "failure_default")]
- mouse: Mouse,
-
- /// Path to a shell program to run on startup
- #[serde(default, deserialize_with = "failure_default")]
- shell: Option<Shell<'static>>,
-
- /// Path where config was loaded from
- #[serde(default, deserialize_with = "failure_default")]
- config_path: Option<PathBuf>,
-
- /// Visual bell configuration
- #[serde(default, deserialize_with = "failure_default")]
- visual_bell: VisualBellConfig,
-
- /// Use dynamic title
- #[serde(default="true_bool", deserialize_with = "default_true_bool")]
- dynamic_title: bool,
-
- /// Live config reload
- #[serde(default="true_bool", deserialize_with = "default_true_bool")]
- live_config_reload: bool,
-
- /// Number of spaces in one tab
- #[serde(default="default_tabspaces", deserialize_with = "deserialize_tabspaces")]
- tabspaces: usize,
-
- /// How much scrolling history to keep
- #[serde(default, deserialize_with="failure_default")]
- scrolling: Scrolling,
-
- /// Cursor configuration
- #[serde(default, deserialize_with="failure_default")]
- cursor: Cursor,
-
- /// Keep the log file after quitting
- #[serde(default, deserialize_with="failure_default")]
- persistent_logging: bool,
-
- // TODO: DEPRECATED
- #[serde(default, deserialize_with = "failure_default")]
- 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
-}
-
-fn failure_default_vec<'a, D, T>(deserializer: D) -> ::std::result::Result<Vec<T>, D::Error>
- where D: de::Deserializer<'a>,
- T: Deserialize<'a>
-{
- // Deserialize as generic vector
- let vec = match Vec::<serde_yaml::Value>::deserialize(deserializer) {
- Ok(vec) => vec,
- Err(err) => {
- error!("Problem with config: {}; using empty vector", err);
- return Ok(Vec::new());
- },
- };
-
- // Move to lossy vector
- let mut bindings: Vec<T> = Vec::new();
- for value in vec {
- match T::deserialize(value) {
- Ok(binding) => bindings.push(binding),
- Err(err) => {
- error!("Problem with config: {}; skipping value", err);
- },
- }
- }
-
- Ok(bindings)
-}
-
-fn default_tabspaces() -> usize {
- 8
-}
-
-fn deserialize_tabspaces<'a, D>(deserializer: D) -> ::std::result::Result<usize, D::Error>
- where D: de::Deserializer<'a>
-{
- match usize::deserialize(deserializer) {
- Ok(value) => Ok(value),
- Err(err) => {
- error!("Problem with config: {}; using 8", err);
- Ok(default_tabspaces())
- },
- }
-}
-
-fn default_true_bool<'a, D>(deserializer: D) -> ::std::result::Result<bool, D::Error>
- where D: de::Deserializer<'a>
-{
- match bool::deserialize(deserializer) {
- Ok(value) => Ok(value),
- Err(err) => {
- error!("Problem with config: {}; using true", err);
- Ok(true)
- },
- }
-}
-
-fn failure_default<'a, D, T>(deserializer: D)
- -> ::std::result::Result<T, D::Error>
- where D: de::Deserializer<'a>,
- T: Deserialize<'a> + Default
-{
- match T::deserialize(deserializer) {
- Ok(value) => Ok(value),
- Err(err) => {
- error!("Problem with config: {}; using default value", err);
- Ok(T::default())
- },
- }
-}
-
-#[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)]
-pub struct Scrolling {
- #[serde(deserialize_with="deserialize_scrolling_history")]
- #[serde(default="default_scrolling_history")]
- pub history: u32,
- #[serde(deserialize_with="deserialize_scrolling_multiplier")]
- #[serde(default="default_scrolling_multiplier")]
- pub multiplier: u8,
- #[serde(deserialize_with="deserialize_scrolling_multiplier")]
- #[serde(default="default_scrolling_multiplier")]
- pub faux_multiplier: u8,
- #[serde(default, 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,
- }
- }
-}
-
-fn deserialize_scrolling_history<'a, D>(deserializer: D) -> ::std::result::Result<u32, D::Error>
- where D: de::Deserializer<'a>
-{
- match u32::deserialize(deserializer) {
- Ok(lines) => {
- if lines > MAX_SCROLLBACK_LINES {
- error!(
- "Problem with config: scrollback size is {}, but expected a maximum of {}; \
- using {1} instead",
- lines, MAX_SCROLLBACK_LINES,
- );
- Ok(MAX_SCROLLBACK_LINES)
- } else {
- Ok(lines)
- }
- },
- Err(err) => {
- error!("Problem with config: {}; using default value", err);
- Ok(default_scrolling_history())
- },
- }
-}
-
-fn deserialize_scrolling_multiplier<'a, D>(deserializer: D) -> ::std::result::Result<u8, D::Error>
- where D: de::Deserializer<'a>
-{
- match u8::deserialize(deserializer) {
- Ok(lines) => Ok(lines),
- Err(err) => {
- error!("Problem with config: {}; using default value", err);
- Ok(default_scrolling_multiplier())
- },
- }
-}
-
-/// Newtype for implementing deserialize on glutin Mods
-///
-/// Our deserialize impl wouldn't be covered by a derive(Deserialize); see the
-/// impl below.
-#[derive(Debug, Copy, Clone, Hash, Default, Eq, PartialEq)]
-struct ModsWrapper(ModifiersState);
-
-impl ModsWrapper {
- fn into_inner(self) -> ModifiersState {
- self.0
- }
-}
-
-impl<'a> de::Deserialize<'a> for ModsWrapper {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: de::Deserializer<'a>
- {
- struct ModsVisitor;
-
- impl<'a> Visitor<'a> for ModsVisitor {
- type Value = ModsWrapper;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("Some subset of Command|Shift|Super|Alt|Option|Control")
- }
-
- fn visit_str<E>(self, value: &str) -> ::std::result::Result<ModsWrapper, E>
- where E: de::Error,
- {
- let mut res = ModifiersState::default();
- for modifier in value.split('|') {
- match modifier.trim() {
- "Command" | "Super" => res.logo = true,
- "Shift" => res.shift = true,
- "Alt" | "Option" => res.alt = true,
- "Control" => res.ctrl = true,
- _ => error!("Unknown modifier {:?}", modifier),
- }
- }
-
- Ok(ModsWrapper(res))
- }
- }
-
- deserializer.deserialize_str(ModsVisitor)
- }
-}
-
-struct ActionWrapper(crate::input::Action);
-
-impl ActionWrapper {
- fn into_inner(self) -> crate::input::Action {
- self.0
- }
-}
-
-impl<'a> de::Deserialize<'a> for ActionWrapper {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: de::Deserializer<'a>
- {
- struct ActionVisitor;
-
- impl<'a> Visitor<'a> for ActionVisitor {
- type Value = 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")
- }
-
- fn visit_str<E>(self, value: &str) -> ::std::result::Result<ActionWrapper, E>
- where E: de::Error,
- {
- Ok(ActionWrapper(match value {
- "Paste" => Action::Paste,
- "Copy" => Action::Copy,
- "PasteSelection" => Action::PasteSelection,
- "IncreaseFontSize" => Action::IncreaseFontSize,
- "DecreaseFontSize" => Action::DecreaseFontSize,
- "ResetFontSize" => Action::ResetFontSize,
- "ScrollPageUp" => Action::ScrollPageUp,
- "ScrollPageDown" => Action::ScrollPageDown,
- "ScrollToTop" => Action::ScrollToTop,
- "ScrollToBottom" => Action::ScrollToBottom,
- "ClearHistory" => Action::ClearHistory,
- "Hide" => Action::Hide,
- "Quit" => Action::Quit,
- "ClearLogNotice" => Action::ClearLogNotice,
- "SpawnNewInstance" => Action::SpawnNewInstance,
- _ => return Err(E::invalid_value(Unexpected::Str(value), &self)),
- }))
- }
- }
- deserializer.deserialize_str(ActionVisitor)
- }
-}
-
-#[derive(Debug, Deserialize, Clone)]
-#[serde(untagged)]
-pub enum CommandWrapper {
- Just(String),
- WithArgs {
- program: String,
- #[serde(default)]
- args: Vec<String>,
- },
-}
-
-impl CommandWrapper {
- pub fn program(&self) -> &str {
- match self {
- CommandWrapper::Just(program) => program,
- CommandWrapper::WithArgs { program, .. } => program,
- }
- }
-
- pub fn args(&self) -> &[String] {
- match self {
- CommandWrapper::Just(_) => &[],
- CommandWrapper::WithArgs { args, .. } => args,
- }
- }
-}
-
-use crate::term::{mode, TermMode};
-
-struct ModeWrapper {
- pub mode: TermMode,
- pub not_mode: TermMode,
-}
-
-impl<'a> de::Deserialize<'a> for ModeWrapper {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: de::Deserializer<'a>
- {
- struct ModeVisitor;
-
- impl<'a> Visitor<'a> for ModeVisitor {
- type Value = ModeWrapper;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("Combination of AppCursor | AppKeypad, possibly with negation (~)")
- }
-
- fn visit_str<E>(self, value: &str) -> ::std::result::Result<ModeWrapper, E>
- where E: de::Error,
- {
- let mut res = ModeWrapper {
- mode: TermMode::empty(),
- not_mode: TermMode::empty()
- };
-
- for modifier in value.split('|') {
- match modifier.trim() {
- "AppCursor" => res.mode |= mode::TermMode::APP_CURSOR,
- "~AppCursor" => res.not_mode |= mode::TermMode::APP_CURSOR,
- "AppKeypad" => res.mode |= mode::TermMode::APP_KEYPAD,
- "~AppKeypad" => res.not_mode |= mode::TermMode::APP_KEYPAD,
- _ => error!("Unknown mode {:?}", modifier),
- }
- }
-
- Ok(res)
- }
- }
- deserializer.deserialize_str(ModeVisitor)
- }
-}
-
-struct MouseButton(::glutin::MouseButton);
-
-impl MouseButton {
- fn into_inner(self) -> ::glutin::MouseButton {
- self.0
- }
-}
-
-impl<'a> de::Deserialize<'a> for MouseButton {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: de::Deserializer<'a>
- {
- struct MouseButtonVisitor;
-
- impl<'a> Visitor<'a> for MouseButtonVisitor {
- type Value = MouseButton;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("Left, Right, Middle, or a number")
- }
-
- fn visit_str<E>(self, value: &str) -> ::std::result::Result<MouseButton, E>
- where E: de::Error,
- {
- match value {
- "Left" => Ok(MouseButton(::glutin::MouseButton::Left)),
- "Right" => Ok(MouseButton(::glutin::MouseButton::Right)),
- "Middle" => Ok(MouseButton(::glutin::MouseButton::Middle)),
- _ => {
- if let Ok(index) = u8::from_str(value) {
- Ok(MouseButton(::glutin::MouseButton::Other(index)))
- } else {
- Err(E::invalid_value(Unexpected::Str(value), &self))
- }
- }
- }
- }
- }
-
- deserializer.deserialize_str(MouseButtonVisitor)
- }
-}
-
-/// Bindings are deserialized into a `RawBinding` before being parsed as a
-/// `KeyBinding` or `MouseBinding`.
-struct RawBinding {
- key: Option<Key>,
- mouse: Option<::glutin::MouseButton>,
- mods: ModifiersState,
- mode: TermMode,
- notmode: TermMode,
- action: Action,
-}
-
-impl RawBinding {
- fn into_mouse_binding(self) -> ::std::result::Result<MouseBinding, Self> {
- if let Some(mouse) = self.mouse {
- Ok(Binding {
- trigger: mouse,
- mods: self.mods,
- action: self.action,
- mode: self.mode,
- notmode: self.notmode,
- })
- } else {
- Err(self)
- }
- }
-
- fn into_key_binding(self) -> ::std::result::Result<KeyBinding, Self> {
- if let Some(key) = self.key {
- Ok(KeyBinding {
- trigger: key,
- mods: self.mods,
- action: self.action,
- mode: self.mode,
- notmode: self.notmode,
- })
- } else {
- Err(self)
- }
- }
-}
-
-impl<'a> de::Deserialize<'a> for RawBinding {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: de::Deserializer<'a>
- {
- enum Field {
- Key,
- Mods,
- Mode,
- Action,
- Chars,
- Mouse,
- Command,
- }
-
- impl<'a> de::Deserialize<'a> for Field {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Field, D::Error>
- where D: de::Deserializer<'a>
- {
- struct FieldVisitor;
-
- static FIELDS: &'static [&'static str] = &[
- "key", "mods", "mode", "action", "chars", "mouse", "command",
- ];
-
- impl<'a> Visitor<'a> for FieldVisitor {
- type Value = Field;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("binding fields")
- }
-
- fn visit_str<E>(self, value: &str) -> ::std::result::Result<Field, E>
- where E: de::Error,
- {
- match value {
- "key" => Ok(Field::Key),
- "mods" => Ok(Field::Mods),
- "mode" => Ok(Field::Mode),
- "action" => Ok(Field::Action),
- "chars" => Ok(Field::Chars),
- "mouse" => Ok(Field::Mouse),
- "command" => Ok(Field::Command),
- _ => Err(E::unknown_field(value, FIELDS)),
- }
- }
- }
-
- deserializer.deserialize_str(FieldVisitor)
- }
- }
-
- struct RawBindingVisitor;
- impl<'a> Visitor<'a> for RawBindingVisitor {
- type Value = RawBinding;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("binding specification")
- }
-
- fn visit_map<V>(
- self,
- mut map: V
- ) -> ::std::result::Result<RawBinding, V::Error>
- where V: MapAccess<'a>,
- {
- let mut mods: Option<ModifiersState> = None;
- let mut key: Option<Key> = None;
- let mut chars: Option<String> = None;
- let mut action: Option<crate::input::Action> = None;
- let mut mode: Option<TermMode> = None;
- let mut not_mode: Option<TermMode> = None;
- let mut mouse: Option<::glutin::MouseButton> = None;
- let mut command: Option<CommandWrapper> = None;
-
- use ::serde::de::Error;
-
- while let Some(struct_key) = map.next_key::<Field>()? {
- match struct_key {
- Field::Key => {
- if key.is_some() {
- return Err(<V::Error as Error>::duplicate_field("key"));
- }
-
- let val = map.next_value::<serde_yaml::Value>()?;
- if val.is_u64() {
- let scancode = val.as_u64().unwrap();
- if scancode > u64::from(::std::u32::MAX) {
- return Err(<V::Error as Error>::custom(format!(
- "Invalid key binding, scancode too big: {}",
- scancode
- )));
- }
- key = Some(Key::Scancode(scancode as u32));
- } else {
- let k = Key::deserialize(val)
- .map_err(V::Error::custom)?;
- key = Some(k);
- }
- },
- Field::Mods => {
- if mods.is_some() {
- return Err(<V::Error as Error>::duplicate_field("mods"));
- }
-
- mods = Some(map.next_value::<ModsWrapper>()?.into_inner());
- },
- Field::Mode => {
- if mode.is_some() {
- return Err(<V::Error as Error>::duplicate_field("mode"));
- }
-
- let mode_deserializer = map.next_value::<ModeWrapper>()?;
- mode = Some(mode_deserializer.mode);
- not_mode = Some(mode_deserializer.not_mode);
- },
- Field::Action => {
- if action.is_some() {
- return Err(<V::Error as Error>::duplicate_field("action"));
- }
-
- action = Some(map.next_value::<ActionWrapper>()?.into_inner());
- },
- Field::Chars => {
- if chars.is_some() {
- return Err(<V::Error as Error>::duplicate_field("chars"));
- }
-
- chars = Some(map.next_value()?);
- },
- Field::Mouse => {
- if chars.is_some() {
- return Err(<V::Error as Error>::duplicate_field("mouse"));
- }
-
- mouse = Some(map.next_value::<MouseButton>()?.into_inner());
- },
- Field::Command => {
- if command.is_some() {
- return Err(<V::Error as Error>::duplicate_field("command"));
- }
-
- command = Some(map.next_value::<CommandWrapper>()?);
- },
- }
- }
-
- let action = match (action, chars, command) {
- (Some(action), None, None) => action,
- (None, Some(chars), None) => Action::Esc(chars),
- (None, None, Some(cmd)) => {
- match cmd {
- CommandWrapper::Just(program) => {
- Action::Command(program, vec![])
- },
- CommandWrapper::WithArgs { program, args } => {
- Action::Command(program, args)
- },
- }
- },
- (None, None, None) => return Err(V::Error::custom("must specify chars, action or command")),
- _ => return Err(V::Error::custom("must specify only chars, action or command")),
- };
-
- let mode = mode.unwrap_or_else(TermMode::empty);
- let not_mode = not_mode.unwrap_or_else(TermMode::empty);
- let mods = mods.unwrap_or_else(ModifiersState::default);
-
- if mouse.is_none() && key.is_none() {
- return Err(V::Error::custom("bindings require mouse button or key"));
- }
-
- Ok(RawBinding {
- mode,
- notmode: not_mode,
- action,
- key,
- mouse,
- mods,
- })
- }
- }
-
- const FIELDS: &[&str] = &[
- "key", "mods", "mode", "action", "chars", "mouse", "command",
- ];
-
- deserializer.deserialize_struct("RawBinding", FIELDS, RawBindingVisitor)
- }
-}
-
-
-impl<'a> de::Deserialize<'a> for Alpha {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: de::Deserializer<'a>
- {
- let value = f32::deserialize(deserializer)?;
- Ok(Alpha::new(value))
- }
-}
-
-impl<'a> de::Deserialize<'a> for MouseBinding {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: de::Deserializer<'a>
- {
- let raw = RawBinding::deserialize(deserializer)?;
- raw.into_mouse_binding()
- .map_err(|_| D::Error::custom("expected mouse binding"))
- }
-}
-
-impl<'a> de::Deserialize<'a> for KeyBinding {
- fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: de::Deserializer<'a>
- {
- let raw = RawBinding::deserialize(deserializer)?;
- raw.into_key_binding()
- .map_err(|_| D::Error::custom("expected key binding"))
- }
-}
-
-/// Errors occurring during config loading
-#[derive(Debug)]
-pub enum Error {
- /// Config file not found
- NotFound,
-
- /// Config file empty
- Empty,
-
- /// Couldn't read $HOME environment variable
- ReadingEnvHome(env::VarError),
-
- /// io error reading file
- Io(io::Error),
-
- /// Not valid yaml or missing parameters
- Yaml(serde_yaml::Error),
-}
-
-#[derive(Debug, Deserialize)]
-pub struct Colors {
- #[serde(default, deserialize_with = "failure_default")]
- pub primary: PrimaryColors,
- #[serde(default, deserialize_with = "failure_default")]
- pub cursor: CursorColors,
- pub normal: AnsiColors,
- pub bright: AnsiColors,
- #[serde(default, deserialize_with = "failure_default")]
- pub dim: Option<AnsiColors>,
- #[serde(default, deserialize_with = "failure_default_vec")]
- pub indexed_colors: Vec<IndexedColor>,
-}
-
-#[derive(Debug, Deserialize)]
-pub struct IndexedColor {
- #[serde(deserialize_with = "deserialize_color_index")]
- pub index: u8,
- #[serde(deserialize_with = "rgb_from_hex")]
- pub color: Rgb,
-}
-
-fn deserialize_color_index<'a, D>(deserializer: D) -> ::std::result::Result<u8, D::Error>
- where D: de::Deserializer<'a>
-{
- match u8::deserialize(deserializer) {
- Ok(index) => {
- if index < 16 {
- error!(
- "Problem with config: indexed_color's index is {}, \
- but a value bigger than 15 was expected; \
- ignoring setting",
- index
- );
-
- // Return value out of range to ignore this color
- Ok(0)
- } else {
- Ok(index)
- }
- },
- Err(err) => {
- error!("Problem with config: {}; ignoring setting", err);
-
- // Return value out of range to ignore this color
- Ok(0)
- },
- }
-}
-
-#[derive(Copy, Clone, Debug, Deserialize)]
-pub struct Cursor {
- #[serde(default, deserialize_with = "failure_default")]
- pub style: CursorStyle,
- #[serde(default="true_bool", deserialize_with = "default_true_bool")]
- pub unfocused_hollow: bool,
-}
-
-impl Default for Cursor {
- fn default() -> Self {
- Self {
- style: Default::default(),
- unfocused_hollow: true,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Default, Deserialize)]
-pub struct CursorColors {
- #[serde(default, deserialize_with = "deserialize_optional_color")]
- pub text: Option<Rgb>,
- #[serde(default, deserialize_with = "deserialize_optional_color")]
- pub cursor: Option<Rgb>,
-}
-
-#[derive(Debug, Deserialize)]
-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")]
- pub bright_foreground: Option<Rgb>,
- #[serde(default, deserialize_with = "deserialize_optional_color")]
- pub dim_foreground: Option<Rgb>,
-}
-
-fn deserialize_optional_color<'a, D>(deserializer: D) -> ::std::result::Result<Option<Rgb>, D::Error>
- where D: de::Deserializer<'a>
-{
- match Option::deserialize(deserializer) {
- Ok(Some(color)) => {
- let color: serde_yaml::Value = color;
- Ok(Some(rgb_from_hex(color).unwrap()))
- },
- Ok(None) => Ok(None),
- Err(err) => {
- error!("Problem with config: {}; using standard foreground color", err);
- Ok(None)
- },
- }
-}
-
-impl Default for PrimaryColors {
- fn default() -> Self {
- PrimaryColors {
- background: Rgb { r: 0, g: 0, b: 0 },
- foreground: Rgb { r: 0xea, g: 0xea, b: 0xea },
- bright_foreground: None,
- dim_foreground: None,
- }
- }
-}
-
-impl Default for Colors {
- fn default() -> Colors {
- Colors {
- primary: PrimaryColors::default(),
- cursor: CursorColors::default(),
- normal: 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},
- },
- bright: 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},
- },
- dim: None,
- indexed_colors: Vec::new(),
- }
- }
-}
-
-/// The 8-colors sections of config
-#[derive(Debug, Deserialize)]
-pub struct AnsiColors {
- #[serde(deserialize_with = "rgb_from_hex")]
- pub black: Rgb,
- #[serde(deserialize_with = "rgb_from_hex")]
- pub red: Rgb,
- #[serde(deserialize_with = "rgb_from_hex")]
- pub green: Rgb,
- #[serde(deserialize_with = "rgb_from_hex")]
- pub yellow: Rgb,
- #[serde(deserialize_with = "rgb_from_hex")]
- pub blue: Rgb,
- #[serde(deserialize_with = "rgb_from_hex")]
- pub magenta: Rgb,
- #[serde(deserialize_with = "rgb_from_hex")]
- pub cyan: Rgb,
- #[serde(deserialize_with = "rgb_from_hex")]
- pub white: Rgb,
-}
-
-/// Deserialize an Rgb from a hex string
-///
-/// This is *not* the deserialize impl for Rgb since we want a symmetric
-/// serialize/deserialize impl for ref tests.
-fn rgb_from_hex<'a, D>(deserializer: D) -> ::std::result::Result<Rgb, D::Error>
- where D: de::Deserializer<'a>
-{
- struct RgbVisitor;
-
- impl<'a> Visitor<'a> for RgbVisitor {
- type Value = Rgb;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("hex color like 0xff00ff")
- }
-
- fn visit_str<E>(self, value: &str) -> ::std::result::Result<Rgb, E>
- where E: ::serde::de::Error
- {
- Rgb::from_str(&value[..])
- .map_err(|_| E::custom("failed to parse rgb; expected hex color like 0xff00ff"))
- }
- }
-
- let rgb = deserializer.deserialize_str(RgbVisitor);
-
- // Use #ff00ff as fallback color
- match rgb {
- Ok(rgb) => Ok(rgb),
- Err(err) => {
- error!("Problem with config: {}; using color #ff00ff", err);
- Ok(Rgb { r: 255, g: 0, b: 255 })
- },
- }
-}
-
-impl FromStr for Rgb {
- type Err = ();
- fn from_str(s: &str) -> ::std::result::Result<Rgb, ()> {
- let mut chars = s.chars();
- let mut rgb = Rgb::default();
-
- macro_rules! component {
- ($($c:ident),*) => {
- $(
- match chars.next().and_then(|c| c.to_digit(16)) {
- Some(val) => rgb.$c = (val as u8) << 4,
- None => return Err(())
- }
-
- match chars.next().and_then(|c| c.to_digit(16)) {
- Some(val) => rgb.$c |= val as u8,
- None => return Err(())
- }
- )*
- }
- }
-
- match chars.next() {
- Some('0') => if chars.next() != Some('x') { return Err(()); },
- Some('#') => (),
- _ => return Err(()),
- }
-
- component!(r, g, b);
-
- Ok(rgb)
- }
-}
-
-impl ::std::error::Error for Error {
- fn cause(&self) -> Option<&dyn (::std::error::Error)> {
- match *self {
- Error::NotFound | Error::Empty => None,
- Error::ReadingEnvHome(ref err) => Some(err),
- Error::Io(ref err) => Some(err),
- Error::Yaml(ref err) => Some(err),
- }
- }
-
- fn description(&self) -> &str {
- match *self {
- Error::NotFound => "Couldn't locate config file",
- Error::Empty => "Empty config file",
- Error::ReadingEnvHome(ref err) => err.description(),
- Error::Io(ref err) => err.description(),
- Error::Yaml(ref err) => err.description(),
- }
- }
-}
-
-impl ::std::fmt::Display for Error {
- fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
- match *self {
- Error::NotFound | Error::Empty => write!(f, "{}", ::std::error::Error::description(self)),
- Error::ReadingEnvHome(ref err) => {
- write!(f, "Couldn't read $HOME environment variable: {}", err)
- },
- Error::Io(ref err) => write!(f, "Error reading config file: {}", err),
- Error::Yaml(ref err) => write!(f, "Problem with config: {}", err),
- }
- }
-}
-
-impl From<env::VarError> for Error {
- fn from(val: env::VarError) -> Error {
- Error::ReadingEnvHome(val)
- }
-}
-
-impl From<io::Error> for Error {
- fn from(val: io::Error) -> Error {
- if val.kind() == io::ErrorKind::NotFound {
- Error::NotFound
- } else {
- Error::Io(val)
- }
- }
-}
-
-impl From<serde_yaml::Error> for Error {
- fn from(val: serde_yaml::Error) -> Error {
- Error::Yaml(val)
- }
-}
-
-/// Result from config loading
-pub type Result<T> = ::std::result::Result<T, Error>;
-
-impl Config {
- /// Get the location of the first found default config file paths
- /// according to the following order:
- ///
- /// 1. $XDG_CONFIG_HOME/alacritty/alacritty.yml
- /// 2. $XDG_CONFIG_HOME/alacritty.yml
- /// 3. $HOME/.config/alacritty/alacritty.yml
- /// 4. $HOME/.alacritty.yml
- #[cfg(not(windows))]
- pub fn installed_config<'a>() -> Option<Cow<'a, Path>> {
- // Try using XDG location by default
- ::xdg::BaseDirectories::with_prefix("alacritty")
- .ok()
- .and_then(|xdg| xdg.find_config_file("alacritty.yml"))
- .or_else(|| {
- ::xdg::BaseDirectories::new().ok().and_then(|fallback| {
- fallback.find_config_file("alacritty.yml")
- })
- })
- .or_else(|| {
- if let Ok(home) = env::var("HOME") {
- // Fallback path: $HOME/.config/alacritty/alacritty.yml
- let fallback = PathBuf::from(&home).join(".config/alacritty/alacritty.yml");
- if fallback.exists() {
- return Some(fallback);
- }
- // Fallback path: $HOME/.alacritty.yml
- let fallback = PathBuf::from(&home).join(".alacritty.yml");
- if fallback.exists() {
- return Some(fallback);
- }
- }
- None
- })
- .map(|path| path.into())
- }
-
- // TODO: Remove old configuration location warning (Deprecated 03/12/2018)
- #[cfg(windows)]
- pub fn installed_config<'a>() -> Option<Cow<'a, Path>> {
- let old = dirs::home_dir()
- .map(|path| path.join("alacritty.yml"));
- let new = dirs::config_dir()
- .map(|path| path.join("alacritty\\alacritty.yml"));
-
- if let Some(old_path) = old.as_ref().filter(|old| old.exists()) {
- warn!(
- "Found configuration at: {}; this file should be moved to the new location: {}",
- old_path.to_string_lossy(),
- new.as_ref().map(|new| new.to_string_lossy()).unwrap(),
- );
-
- old.map(Cow::from)
- } else {
- new.filter(|new| new.exists()).map(Cow::from)
- }
- }
-
- #[cfg(not(windows))]
- pub fn write_defaults() -> io::Result<Cow<'static, Path>> {
- let path = xdg::BaseDirectories::with_prefix("alacritty")
- .map_err(|err| io::Error::new(io::ErrorKind::NotFound, err.to_string().as_str()))
- .and_then(|p| p.place_config_file("alacritty.yml"))?;
-
- File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?;
-
- Ok(path.into())
- }
-
- #[cfg(windows)]
- pub fn write_defaults() -> io::Result<Cow<'static, Path>> {
- let mut path = dirs::config_dir()
- .ok_or_else(|| {
- io::Error::new(io::ErrorKind::NotFound, "Couldn't find profile directory")
- }
- )?;
-
- path = path.join("alacritty/alacritty.yml");
-
- fs::create_dir_all(path.parent().unwrap())?;
-
- File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?;
-
- Ok(path.into())
- }
-
- /// Get list of colors
- ///
- /// The ordering returned here is expected by the terminal. Colors are simply indexed in this
- /// array for performance.
- pub fn colors(&self) -> &Colors {
- &self.colors
- }
-
- #[inline]
- pub fn background_opacity(&self) -> Alpha {
- self.background_opacity
- }
-
- pub fn key_bindings(&self) -> &[KeyBinding] {
- &self.key_bindings[..]
- }
-
- pub fn mouse_bindings(&self) -> &[MouseBinding] {
- &self.mouse_bindings[..]
- }
-
- pub fn mouse(&self) -> &Mouse {
- &self.mouse
- }
-
- pub fn selection(&self) -> &Selection {
- &self.selection
- }
-
- pub fn tabspaces(&self) -> usize {
- self.tabspaces
- }
-
- pub fn padding(&self) -> &Delta<u8> {
- self.padding.as_ref()
- .unwrap_or(&self.window.padding)
- }
-
- #[inline]
- pub fn draw_bold_text_with_bright_colors(&self) -> bool {
- self.draw_bold_text_with_bright_colors
- }
-
- /// Get font config
- #[inline]
- pub fn font(&self) -> &Font {
- &self.font
- }
-
- /// Get window dimensions
- #[inline]
- pub fn dimensions(&self) -> Dimensions {
- self.dimensions.unwrap_or(self.window.dimensions)
- }
-
- /// Get window config
- #[inline]
- pub fn window(&self) -> &WindowConfig {
- &self.window
- }
-
- /// Get visual bell config
- #[inline]
- pub fn visual_bell(&self) -> &VisualBellConfig {
- &self.visual_bell
- }
-
- /// Should show render timer
- #[inline]
- pub fn render_timer(&self) -> bool {
- self.render_timer
- }
-
- #[inline]
- pub fn use_thin_strokes(&self) -> bool {
- self.font.use_thin_strokes
- }
-
- pub fn path(&self) -> Option<&Path> {
- self.config_path
- .as_ref()
- .map(|p| p.as_path())
- }
-
- pub fn shell(&self) -> Option<&Shell<'_>> {
- self.shell.as_ref()
- }
-
- pub fn env(&self) -> &HashMap<String, String> {
- &self.env
- }
-
- /// Should hide mouse cursor when typing
- #[inline]
- pub fn hide_mouse_when_typing(&self) -> bool {
- self.hide_cursor_when_typing.unwrap_or(self.mouse.hide_when_typing)
- }
-
- /// Style of the cursor
- #[inline]
- pub fn cursor_style(&self) -> CursorStyle {
- self.cursor_style.unwrap_or(self.cursor.style)
- }
-
- /// Use hollow block cursor when unfocused
- #[inline]
- pub fn unfocused_hollow_cursor(&self) -> bool {
- self.unfocused_hollow_cursor.unwrap_or(self.cursor.unfocused_hollow)
- }
-
- /// Live config reload
- #[inline]
- pub fn live_config_reload(&self) -> bool {
- self.live_config_reload
- }
-
- #[inline]
- pub fn dynamic_title(&self) -> bool {
- self.dynamic_title
- }
-
- /// Scrolling settings
- #[inline]
- pub fn scrolling(&self) -> Scrolling {
- self.scrolling
- }
-
- /// Cursor foreground color
- #[inline]
- pub fn cursor_text_color(&self) -> Option<Color> {
- self.colors.cursor.text.map(|_| Color::Named(NamedColor::CursorText))
- }
-
- /// Cursor background color
- #[inline]
- pub fn cursor_cursor_color(&self) -> Option<Color> {
- self.colors.cursor.cursor.map(|_| Color::Named(NamedColor::Cursor))
- }
-
- /// Enable experimental conpty backend (Windows only)
- #[cfg(windows)]
- #[inline]
- pub fn enable_experimental_conpty_backend(&self) -> bool {
- self.enable_experimental_conpty_backend
- }
-
- // Update the history size, used in ref tests
- pub fn set_history(&mut self, history: u32) {
- self.scrolling.history = history;
- }
-
- /// Keep the log file after quitting Alacritty
- #[inline]
- pub fn persistent_logging(&self) -> bool {
- self.persistent_logging
- }
-
- pub fn load_from<P: Into<PathBuf>>(path: P) -> Result<Config> {
- let path = path.into();
- let raw = Config::read_file(path.as_path())?;
- let mut config: Config = serde_yaml::from_str(&raw)?;
- config.config_path = Some(path);
- config.print_deprecation_warnings();
-
- Ok(config)
- }
-
- /// Overrides the `dynamic_title` configuration based on `--title`.
- pub fn update_dynamic_title(mut self, options: &Options) -> Self {
- if options.title.is_some() {
- self.dynamic_title = false;
- }
- self
- }
-
- fn read_file<P: AsRef<Path>>(path: P) -> Result<String> {
- let mut f = fs::File::open(path)?;
- let mut contents = String::new();
- f.read_to_string(&mut contents)?;
- if contents.is_empty() {
- return Err(Error::Empty);
- }
-
- Ok(contents)
- }
-
- fn print_deprecation_warnings(&mut self) {
- if self.dimensions.is_some() {
- warn!("Config dimensions is deprecated; \
- please use window.dimensions instead");
- }
-
- if self.padding.is_some() {
- warn!("Config padding is deprecated; \
- please use window.padding instead");
- }
-
- if self.mouse.faux_scrollback_lines.is_some() {
- warn!("Config mouse.faux_scrollback_lines is deprecated; \
- please use mouse.faux_scrolling_lines instead");
- }
-
- if let Some(custom_cursor_colors) = self.custom_cursor_colors {
- warn!("Config custom_cursor_colors is deprecated");
-
- if !custom_cursor_colors {
- self.colors.cursor.cursor = None;
- self.colors.cursor.text = None;
- }
- }
-
- if self.cursor_style.is_some() {
- warn!("Config cursor_style is deprecated; \
- please use cursor.style instead");
- }
-
- if self.hide_cursor_when_typing.is_some() {
- warn!("Config hide_cursor_when_typing is deprecated; \
- please use mouse.hide_when_typing instead");
- }
-
- if self.unfocused_hollow_cursor.is_some() {
- warn!("Config unfocused_hollow_cursor is deprecated; \
- please use cursor.unfocused_hollow instead");
- }
- }
-}
-
-/// Window Dimensions
-///
-/// Newtype to avoid passing values incorrectly
-#[derive(Debug, Copy, Clone, Deserialize)]
-pub struct Dimensions {
- /// Window width in character columns
- columns: Column,
-
- /// Window Height in character lines
- lines: Line,
-}
-
-impl Default for Dimensions {
- fn default() -> Dimensions {
- Dimensions::new(Column(80), Line(24))
- }
-}
-
-impl Dimensions {
- pub fn new(columns: Column, lines: Line) -> Self {
- Dimensions {
- columns,
- lines,
- }
- }
-
- /// Get lines
- #[inline]
- pub fn lines_u32(&self) -> u32 {
- self.lines.0 as u32
- }
-
- /// Get columns
- #[inline]
- pub fn columns_u32(&self) -> u32 {
- self.columns.0 as u32
- }
-}
-
-/// A delta for a point in a 2 dimensional plane
-#[derive(Clone, Copy, Debug, Default, Deserialize)]
-#[serde(bound(deserialize = "T: Deserialize<'de> + Default"))]
-pub struct Delta<T: Default> {
- /// Horizontal change
- #[serde(default, deserialize_with = "failure_default")]
- pub x: T,
- /// Vertical change
- #[serde(default, deserialize_with = "failure_default")]
- pub y: T,
-}
-
-trait DeserializeSize : Sized {
- fn deserialize<'a, D>(_: D) -> ::std::result::Result<Self, D::Error>
- where D: serde::de::Deserializer<'a>;
-}
-
-impl DeserializeSize for Size {
- fn deserialize<'a, D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
- where D: serde::de::Deserializer<'a>
- {
- use std::marker::PhantomData;
-
- struct NumVisitor<__D> {
- _marker: PhantomData<__D>,
- }
-
- impl<'a, __D> Visitor<'a> for NumVisitor<__D>
- where __D: serde::de::Deserializer<'a>
- {
- type Value = f64;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("f64 or u64")
- }
-
- fn visit_f64<E>(self, value: f64) -> ::std::result::Result<Self::Value, E>
- where E: ::serde::de::Error
- {
- Ok(value)
- }
-
- fn visit_u64<E>(self, value: u64) -> ::std::result::Result<Self::Value, E>
- where E: ::serde::de::Error
- {
- Ok(value as f64)
- }
- }
-
- let size = deserializer
- .deserialize_any(NumVisitor::<D>{ _marker: PhantomData })
- .map(|v| Size::new(v as _));
-
- // Use font size 12 as fallback
- match size {
- Ok(size) => Ok(size),
- Err(err) => {
- error!("Problem with config: {}; using size 12", err);
- Ok(Size::new(12.))
- },
- }
- }
-}
-
-/// Font config
-///
-/// Defaults are provided at the level of this struct per platform, but not per
-/// field in this struct. It might be nice in the future to have defaults for
-/// each value independently. Alternatively, maybe erroring when the user
-/// doesn't provide complete config is Ok.
-#[derive(Debug, Deserialize, Clone)]
-pub struct Font {
- /// Font family
- pub normal: FontDescription,
-
- #[serde(default="default_italic_desc")]
- pub italic: FontDescription,
-
- #[serde(default="default_bold_desc")]
- pub bold: FontDescription,
-
- // Font size in points
- #[serde(deserialize_with="DeserializeSize::deserialize")]
- pub size: Size,
-
- /// Extra spacing per character
- #[serde(default, deserialize_with = "failure_default")]
- offset: Delta<i8>,
-
- /// Glyph offset within character cell
- #[serde(default, deserialize_with = "failure_default")]
- glyph_offset: Delta<i8>,
-
- #[serde(default="true_bool", deserialize_with = "default_true_bool")]
- use_thin_strokes: bool,
-
- // TODO: Deprecated
- #[serde(default, deserialize_with = "deserialize_scale_with_dpi")]
- scale_with_dpi: Option<()>,
-}
-
-fn deserialize_scale_with_dpi<'a, D>(deserializer: D) -> ::std::result::Result<Option<()>, D::Error>
-where
- D: de::Deserializer<'a>,
-{
- // This is necessary in order to get serde to complete deserialization of the configuration
- let _ignored = bool::deserialize(deserializer);
- error!("The scale_with_dpi setting has been removed, \
- on X11 the WINIT_HIDPI_FACTOR environment variable can be used instead.");
- Ok(None)
-}
-
-fn default_bold_desc() -> FontDescription {
- Font::default().bold
-}
-
-fn default_italic_desc() -> FontDescription {
- Font::default().italic
-}
-
-/// Description of a single font
-#[derive(Debug, Deserialize, Clone)]
-pub struct FontDescription {
- pub family: String,
- pub style: Option<String>,
-}
-
-impl FontDescription {
- fn new_with_family<S: Into<String>>(family: S) -> FontDescription {
- FontDescription {
- family: family.into(),
- style: None,
- }
- }
-}
-
-impl Font {
- /// Get the font size in points
- #[inline]
- pub fn size(&self) -> Size {
- self.size
- }
-
- /// Get offsets to font metrics
- #[inline]
- pub fn offset(&self) -> &Delta<i8> {
- &self.offset
- }
-
- /// Get cell offsets for glyphs
- #[inline]
- pub fn glyph_offset(&self) -> &Delta<i8> {
- &self.glyph_offset
- }
-
- /// Get a font clone with a size modification
- pub fn with_size(self, size: Size) -> Font {
- Font {
- size,
- .. self
- }
- }
-}
-
-#[cfg(target_os = "macos")]
-impl Default for Font {
- fn default() -> Font {
- Font {
- normal: FontDescription::new_with_family("Menlo"),
- bold: FontDescription::new_with_family("Menlo"),
- italic: FontDescription::new_with_family("Menlo"),
- size: Size::new(11.0),
- use_thin_strokes: true,
- scale_with_dpi: None,
- glyph_offset: Default::default(),
- offset: Default::default(),
- }
- }
-}
-
-#[cfg(any(target_os = "linux",target_os = "freebsd",target_os = "openbsd"))]
-impl Default for Font {
- fn default() -> Font {
- Font {
- normal: FontDescription::new_with_family("monospace"),
- bold: FontDescription::new_with_family("monospace"),
- italic: FontDescription::new_with_family("monospace"),
- size: Size::new(11.0),
- use_thin_strokes: false,
- scale_with_dpi: None,
- glyph_offset: Default::default(),
- offset: Default::default(),
- }
- }
-}
-
-#[cfg(windows)]
-impl Default for Font {
- fn default() -> Font {
- Font {
- normal: FontDescription::new_with_family("Consolas"),
- bold: FontDescription::new_with_family("Consolas"),
- italic: FontDescription::new_with_family("Consolas"),
- size: Size::new(11.0),
- use_thin_strokes: false,
- scale_with_dpi: None,
- glyph_offset: Default::default(),
- offset: Default::default(),
- }
- }
-}
-
-pub struct Monitor {
- _thread: ::std::thread::JoinHandle<()>,
- rx: mpsc::Receiver<Config>,
-}
-
-pub trait OnConfigReload {
- fn on_config_reload(&mut self);
-}
-
-impl OnConfigReload for crate::display::Notifier {
- fn on_config_reload(&mut self) {
- self.notify();
- }
-}
-
-impl Monitor {
- /// Get pending config changes
- pub fn pending_config(&self) -> Option<Config> {
- let mut config = None;
- while let Ok(new) = self.rx.try_recv() {
- config = Some(new);
- }
-
- config
- }
- pub fn new<H, P>(path: P, mut handler: H) -> Monitor
- where H: OnConfigReload + Send + 'static,
- P: Into<PathBuf>
- {
- let path = path.into();
-
- let (config_tx, config_rx) = mpsc::channel();
-
- Monitor {
- _thread: crate::util::thread::spawn_named("config watcher", move || {
- let (tx, rx) = mpsc::channel();
- // The Duration argument is a debouncing period.
- let mut watcher = watcher(tx, Duration::from_millis(10))
- .expect("Unable to spawn file watcher");
- let config_path = ::std::fs::canonicalize(path)
- .expect("canonicalize config path");
-
- // Get directory of config
- let mut parent = config_path.clone();
- parent.pop();
-
- // Watch directory
- watcher.watch(&parent, RecursiveMode::NonRecursive)
- .expect("watch alacritty.yml dir");
-
- loop {
- match rx.recv().expect("watcher event") {
- DebouncedEvent::Rename(_, _) => continue,
- DebouncedEvent::Write(path) | DebouncedEvent::Create(path)
- | DebouncedEvent::Chmod(path) => {
- // Reload file
- if path == config_path {
- match Config::load_from(path) {
- Ok(config) => {
- let _ = config_tx.send(config);
- handler.on_config_reload();
- },
- Err(err) => error!("Ignoring invalid config: {}", err),
- }
- }
- }
- _ => {}
- }
- }
- }),
- rx: config_rx,
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::cli::Options;
- use super::Config;
-
- #[cfg(target_os="macos")]
- static ALACRITTY_YML: &'static str =
- include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty_macos.yml"));
- #[cfg(windows)]
- static ALACRITTY_YML: &'static str =
- include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty_windows.yml"));
- #[cfg(not(any(target_os="macos", windows)))]
- static ALACRITTY_YML: &'static str =
- include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml"));
-
- #[test]
- fn parse_config() {
- let config: Config = ::serde_yaml::from_str(ALACRITTY_YML)
- .expect("deserialize config");
-
- // Sanity check that mouse bindings are being parsed
- assert!(!config.mouse_bindings.is_empty());
-
- // Sanity check that key bindings are being parsed
- assert!(!config.key_bindings.is_empty());
- }
-
- #[test]
- fn dynamic_title_ignoring_options_by_default() {
- let config: Config = ::serde_yaml::from_str(ALACRITTY_YML)
- .expect("deserialize config");
- let old_dynamic_title = config.dynamic_title;
- let options = Options::default();
- let config = config.update_dynamic_title(&options);
- assert_eq!(old_dynamic_title, config.dynamic_title);
- }
-
- #[test]
- fn dynamic_title_overridden_by_options() {
- let config: Config = ::serde_yaml::from_str(ALACRITTY_YML)
- .expect("deserialize config");
- let mut options = Options::default();
- options.title = Some("foo".to_owned());
- let config = config.update_dynamic_title(&options);
- assert!(!config.dynamic_title);
- }
-}
-
-#[derive(Deserialize, Copy, Clone, Debug, Eq, PartialEq)]
-pub enum Key {
- Scancode(u32),
- Key1,
- Key2,
- Key3,
- Key4,
- Key5,
- Key6,
- Key7,
- Key8,
- Key9,
- Key0,
- A,
- B,
- C,
- D,
- E,
- F,
- G,
- H,
- I,
- J,
- K,
- L,
- M,
- N,
- O,
- P,
- Q,
- R,
- S,
- T,
- U,
- V,
- W,
- X,
- Y,
- Z,
- Escape,
- F1,
- F2,
- F3,
- F4,
- F5,
- F6,
- F7,
- F8,
- F9,
- F10,
- F11,
- F12,
- F13,
- F14,
- F15,
- F16,
- F17,
- F18,
- F19,
- F20,
- F21,
- F22,
- F23,
- F24,
- Snapshot,
- Scroll,
- Pause,
- Insert,
- Home,
- Delete,
- End,
- PageDown,
- PageUp,
- Left,
- Up,
- Right,
- Down,
- Back,
- Return,
- Space,
- Compose,
- Numlock,
- Numpad0,
- Numpad1,
- Numpad2,
- Numpad3,
- Numpad4,
- Numpad5,
- Numpad6,
- Numpad7,
- Numpad8,
- Numpad9,
- AbntC1,
- AbntC2,
- Add,
- Apostrophe,
- Apps,
- At,
- Ax,
- Backslash,
- Calculator,
- Capital,
- Colon,
- Comma,
- Convert,
- Decimal,
- Divide,
- Equals,
- Grave,
- Kana,
- Kanji,
- LAlt,
- LBracket,
- LControl,
- LShift,
- LWin,
- Mail,
- MediaSelect,
- MediaStop,
- Minus,
- Multiply,
- Mute,
- MyComputer,
- NavigateForward,
- NavigateBackward,
- NextTrack,
- NoConvert,
- NumpadComma,
- NumpadEnter,
- NumpadEquals,
- OEM102,
- Period,
- PlayPause,
- Power,
- PrevTrack,
- RAlt,
- RBracket,
- RControl,
- RShift,
- RWin,
- Semicolon,
- Slash,
- Sleep,
- Stop,
- Subtract,
- Sysrq,
- Tab,
- Underline,
- Unlabeled,
- VolumeDown,
- VolumeUp,
- Wake,
- WebBack,
- WebFavorites,
- WebForward,
- WebHome,
- WebRefresh,
- WebSearch,
- WebStop,
- Yen,
- Caret,
- Copy,
- Paste,
- Cut,
-}
-
-impl Key {
- pub fn from_glutin_input(key: ::glutin::VirtualKeyCode) -> Self {
- use glutin::VirtualKeyCode::*;
- // Thank you, vim macros and regex!
- match key {
- Key1 => Key::Key1,
- Key2 => Key::Key2,
- Key3 => Key::Key3,
- Key4 => Key::Key4,
- Key5 => Key::Key5,
- Key6 => Key::Key6,
- Key7 => Key::Key7,
- Key8 => Key::Key8,
- Key9 => Key::Key9,
- Key0 => Key::Key0,
- A => Key::A,
- B => Key::B,
- C => Key::C,
- D => Key::D,
- E => Key::E,
- F => Key::F,
- G => Key::G,
- H => Key::H,
- I => Key::I,
- J => Key::J,
- K => Key::K,
- L => Key::L,
- M => Key::M,
- N => Key::N,
- O => Key::O,
- P => Key::P,
- Q => Key::Q,
- R => Key::R,
- S => Key::S,
- T => Key::T,
- U => Key::U,
- V => Key::V,
- W => Key::W,
- X => Key::X,
- Y => Key::Y,
- Z => Key::Z,
- Escape => Key::Escape,
- F1 => Key::F1,
- F2 => Key::F2,
- F3 => Key::F3,
- F4 => Key::F4,
- F5 => Key::F5,
- F6 => Key::F6,
- F7 => Key::F7,
- F8 => Key::F8,
- F9 => Key::F9,
- F10 => Key::F10,
- F11 => Key::F11,
- F12 => Key::F12,
- F13 => Key::F13,
- F14 => Key::F14,
- F15 => Key::F15,
- F16 => Key::F16,
- F17 => Key::F17,
- F18 => Key::F18,
- F19 => Key::F19,
- F20 => Key::F20,
- F21 => Key::F21,
- F22 => Key::F22,
- F23 => Key::F23,
- F24 => Key::F24,
- Snapshot => Key::Snapshot,
- Scroll => Key::Scroll,
- Pause => Key::Pause,
- Insert => Key::Insert,
- Home => Key::Home,
- Delete => Key::Delete,
- End => Key::End,
- PageDown => Key::PageDown,
- PageUp => Key::PageUp,
- Left => Key::Left,
- Up => Key::Up,
- Right => Key::Right,
- Down => Key::Down,
- Back => Key::Back,
- Return => Key::Return,
- Space => Key::Space,
- Compose => Key::Compose,
- Numlock => Key::Numlock,
- Numpad0 => Key::Numpad0,
- Numpad1 => Key::Numpad1,
- Numpad2 => Key::Numpad2,
- Numpad3 => Key::Numpad3,
- Numpad4 => Key::Numpad4,
- Numpad5 => Key::Numpad5,
- Numpad6 => Key::Numpad6,
- Numpad7 => Key::Numpad7,
- Numpad8 => Key::Numpad8,
- Numpad9 => Key::Numpad9,
- AbntC1 => Key::AbntC1,
- AbntC2 => Key::AbntC2,
- Add => Key::Add,
- Apostrophe => Key::Apostrophe,
- Apps => Key::Apps,
- At => Key::At,
- Ax => Key::Ax,
- Backslash => Key::Backslash,
- Calculator => Key::Calculator,
- Capital => Key::Capital,
- Colon => Key::Colon,
- Comma => Key::Comma,
- Convert => Key::Convert,
- Decimal => Key::Decimal,
- Divide => Key::Divide,
- Equals => Key::Equals,
- Grave => Key::Grave,
- Kana => Key::Kana,
- Kanji => Key::Kanji,
- LAlt => Key::LAlt,
- LBracket => Key::LBracket,
- LControl => Key::LControl,
- LShift => Key::LShift,
- LWin => Key::LWin,
- Mail => Key::Mail,
- MediaSelect => Key::MediaSelect,
- MediaStop => Key::MediaStop,
- Minus => Key::Minus,
- Multiply => Key::Multiply,
- Mute => Key::Mute,
- MyComputer => Key::MyComputer,
- NavigateForward => Key::NavigateForward,
- NavigateBackward => Key::NavigateBackward,
- NextTrack => Key::NextTrack,
- NoConvert => Key::NoConvert,
- NumpadComma => Key::NumpadComma,
- NumpadEnter => Key::NumpadEnter,
- NumpadEquals => Key::NumpadEquals,
- OEM102 => Key::OEM102,
- Period => Key::Period,
- PlayPause => Key::PlayPause,
- Power => Key::Power,
- PrevTrack => Key::PrevTrack,
- RAlt => Key::RAlt,
- RBracket => Key::RBracket,
- RControl => Key::RControl,
- RShift => Key::RShift,
- RWin => Key::RWin,
- Semicolon => Key::Semicolon,
- Slash => Key::Slash,
- Sleep => Key::Sleep,
- Stop => Key::Stop,
- Subtract => Key::Subtract,
- Sysrq => Key::Sysrq,
- Tab => Key::Tab,
- Underline => Key::Underline,
- Unlabeled => Key::Unlabeled,
- VolumeDown => Key::VolumeDown,
- VolumeUp => Key::VolumeUp,
- Wake => Key::Wake,
- WebBack => Key::WebBack,
- WebFavorites => Key::WebFavorites,
- WebForward => Key::WebForward,
- WebHome => Key::WebHome,
- WebRefresh => Key::WebRefresh,
- WebSearch => Key::WebSearch,
- WebStop => Key::WebStop,
- Yen => Key::Yen,
- Caret => Key::Caret,
- Copy => Key::Copy,
- Paste => Key::Paste,
- Cut => Key::Cut,
- }
- }
-}