aboutsummaryrefslogtreecommitdiff
path: root/alacritty/src/config
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty/src/config')
-rw-r--r--alacritty/src/config/debug.rs64
-rw-r--r--alacritty/src/config/font.rs218
-rw-r--r--alacritty/src/config/mod.rs33
-rw-r--r--alacritty/src/config/ui_config.rs97
-rw-r--r--alacritty/src/config/window.rs220
5 files changed, 608 insertions, 24 deletions
diff --git a/alacritty/src/config/debug.rs b/alacritty/src/config/debug.rs
new file mode 100644
index 00000000..62de0500
--- /dev/null
+++ b/alacritty/src/config/debug.rs
@@ -0,0 +1,64 @@
+use log::{error, LevelFilter};
+use serde::{Deserialize, Deserializer};
+
+use alacritty_terminal::config::{failure_default, LOG_TARGET_CONFIG};
+
+/// Debugging options.
+#[serde(default)]
+#[derive(Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Debug {
+ #[serde(default = "default_log_level", deserialize_with = "deserialize_log_level")]
+ pub log_level: LevelFilter,
+
+ #[serde(deserialize_with = "failure_default")]
+ pub print_events: bool,
+
+ /// Keep the log file after quitting.
+ #[serde(deserialize_with = "failure_default")]
+ pub persistent_logging: bool,
+
+ /// Should show render timer.
+ #[serde(deserialize_with = "failure_default")]
+ pub render_timer: bool,
+
+ /// Record ref test.
+ #[serde(skip)]
+ pub ref_test: bool,
+}
+
+impl Default for Debug {
+ fn default() -> Self {
+ Self {
+ log_level: default_log_level(),
+ print_events: Default::default(),
+ persistent_logging: Default::default(),
+ render_timer: Default::default(),
+ ref_test: Default::default(),
+ }
+ }
+}
+
+fn default_log_level() -> LevelFilter {
+ LevelFilter::Warn
+}
+
+fn deserialize_log_level<'a, D>(deserializer: D) -> Result<LevelFilter, D::Error>
+where
+ D: Deserializer<'a>,
+{
+ Ok(match failure_default::<D, String>(deserializer)?.to_lowercase().as_str() {
+ "off" | "none" => LevelFilter::Off,
+ "error" => LevelFilter::Error,
+ "warn" => LevelFilter::Warn,
+ "info" => LevelFilter::Info,
+ "debug" => LevelFilter::Debug,
+ "trace" => LevelFilter::Trace,
+ level => {
+ error!(
+ target: LOG_TARGET_CONFIG,
+ "Problem with config: invalid log level {}; using level Warn", level
+ );
+ default_log_level()
+ },
+ })
+}
diff --git a/alacritty/src/config/font.rs b/alacritty/src/config/font.rs
new file mode 100644
index 00000000..f718587c
--- /dev/null
+++ b/alacritty/src/config/font.rs
@@ -0,0 +1,218 @@
+use std::fmt;
+
+use font::Size;
+use log::error;
+use serde::de::Visitor;
+use serde::{Deserialize, Deserializer};
+
+use alacritty_terminal::config::{failure_default, LOG_TARGET_CONFIG};
+
+#[cfg(target_os = "macos")]
+use crate::config::ui_config::DefaultTrueBool;
+use crate::config::ui_config::Delta;
+
+/// 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.
+#[serde(default)]
+#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
+pub struct Font {
+ /// Normal font face.
+ #[serde(deserialize_with = "failure_default")]
+ normal: FontDescription,
+
+ /// Bold font face.
+ #[serde(deserialize_with = "failure_default")]
+ bold: SecondaryFontDescription,
+
+ /// Italic font face.
+ #[serde(deserialize_with = "failure_default")]
+ italic: SecondaryFontDescription,
+
+ /// Bold italic font face.
+ #[serde(deserialize_with = "failure_default")]
+ bold_italic: SecondaryFontDescription,
+
+ /// Font size in points.
+ #[serde(deserialize_with = "DeserializeSize::deserialize")]
+ pub size: Size,
+
+ /// Extra spacing per character.
+ #[serde(deserialize_with = "failure_default")]
+ pub offset: Delta<i8>,
+
+ /// Glyph offset within character cell.
+ #[serde(deserialize_with = "failure_default")]
+ pub glyph_offset: Delta<i8>,
+
+ #[cfg(target_os = "macos")]
+ #[serde(deserialize_with = "failure_default")]
+ use_thin_strokes: DefaultTrueBool,
+}
+
+impl Default for Font {
+ fn default() -> Font {
+ Font {
+ size: default_font_size(),
+ normal: Default::default(),
+ bold: Default::default(),
+ italic: Default::default(),
+ bold_italic: Default::default(),
+ glyph_offset: Default::default(),
+ offset: Default::default(),
+ #[cfg(target_os = "macos")]
+ use_thin_strokes: Default::default(),
+ }
+ }
+}
+
+impl Font {
+ /// Get a font clone with a size modification.
+ pub fn with_size(self, size: Size) -> Font {
+ Font { size, ..self }
+ }
+
+ /// Get normal font description.
+ pub fn normal(&self) -> &FontDescription {
+ &self.normal
+ }
+
+ /// Get bold font description.
+ pub fn bold(&self) -> FontDescription {
+ self.bold.desc(&self.normal)
+ }
+
+ /// Get italic font description.
+ pub fn italic(&self) -> FontDescription {
+ self.italic.desc(&self.normal)
+ }
+
+ /// Get bold italic font description.
+ pub fn bold_italic(&self) -> FontDescription {
+ self.bold_italic.desc(&self.normal)
+ }
+
+ #[cfg(target_os = "macos")]
+ pub fn use_thin_strokes(&self) -> bool {
+ self.use_thin_strokes.0
+ }
+
+ #[cfg(not(target_os = "macos"))]
+ pub fn use_thin_strokes(&self) -> bool {
+ false
+ }
+}
+
+fn default_font_size() -> Size {
+ Size::new(11.)
+}
+
+/// Description of the normal font.
+#[serde(default)]
+#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
+pub struct FontDescription {
+ #[serde(deserialize_with = "failure_default")]
+ pub family: String,
+ #[serde(deserialize_with = "failure_default")]
+ pub style: Option<String>,
+}
+
+impl Default for FontDescription {
+ fn default() -> FontDescription {
+ FontDescription {
+ #[cfg(not(any(target_os = "macos", windows)))]
+ family: "monospace".into(),
+ #[cfg(target_os = "macos")]
+ family: "Menlo".into(),
+ #[cfg(windows)]
+ family: "Consolas".into(),
+ style: None,
+ }
+ }
+}
+
+/// Description of the italic and bold font.
+#[serde(default)]
+#[derive(Debug, Default, Deserialize, Clone, PartialEq, Eq)]
+pub struct SecondaryFontDescription {
+ #[serde(deserialize_with = "failure_default")]
+ family: Option<String>,
+ #[serde(deserialize_with = "failure_default")]
+ style: Option<String>,
+}
+
+impl SecondaryFontDescription {
+ pub fn desc(&self, fallback: &FontDescription) -> FontDescription {
+ FontDescription {
+ family: self.family.clone().unwrap_or_else(|| fallback.family.clone()),
+ style: self.style.clone(),
+ }
+ }
+}
+
+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 value = serde_yaml::Value::deserialize(deserializer)?;
+ let size = value
+ .deserialize_any(NumVisitor::<D> { _marker: PhantomData })
+ .map(|v| Size::new(v as _));
+
+ // Use default font size as fallback.
+ match size {
+ Ok(size) => Ok(size),
+ Err(err) => {
+ let size = default_font_size();
+ error!(
+ target: LOG_TARGET_CONFIG,
+ "Problem with config: {}; using size {}",
+ err,
+ size.as_f32_pts()
+ );
+ Ok(size)
+ },
+ }
+ }
+}
diff --git a/alacritty/src/config/mod.rs b/alacritty/src/config/mod.rs
index e6437d26..7fffcc39 100644
--- a/alacritty/src/config/mod.rs
+++ b/alacritty/src/config/mod.rs
@@ -11,9 +11,12 @@ use log::{error, warn};
use alacritty_terminal::config::{Config as TermConfig, LOG_TARGET_CONFIG};
mod bindings;
+pub mod debug;
+pub mod font;
pub mod monitor;
mod mouse;
-mod ui_config;
+pub mod ui_config;
+pub mod window;
pub use crate::config::bindings::{Action, Binding, Key, ViAction};
#[cfg(test)]
@@ -172,27 +175,6 @@ fn parse_config(contents: &str) -> Result<Config> {
}
fn print_deprecation_warnings(config: &Config) {
- if config.window.start_maximized.is_some() {
- warn!(
- target: LOG_TARGET_CONFIG,
- "Config window.start_maximized is deprecated; please use window.startup_mode instead"
- );
- }
-
- if config.render_timer.is_some() {
- warn!(
- target: LOG_TARGET_CONFIG,
- "Config render_timer is deprecated; please use debug.render_timer instead"
- );
- }
-
- if config.persistent_logging.is_some() {
- warn!(
- target: LOG_TARGET_CONFIG,
- "Config persistent_logging is deprecated; please use debug.persistent_logging instead"
- );
- }
-
if config.scrolling.faux_multiplier().is_some() {
warn!(
target: LOG_TARGET_CONFIG,
@@ -224,6 +206,13 @@ fn print_deprecation_warnings(config: &Config) {
"Config visual_bell has been deprecated; please use bell instead"
)
}
+
+ if config.ui_config.dynamic_title.is_some() {
+ warn!(
+ target: LOG_TARGET_CONFIG,
+ "Config dynamic_title is deprecated; please use window.dynamic_title instead",
+ )
+ }
}
#[cfg(test)]
diff --git a/alacritty/src/config/ui_config.rs b/alacritty/src/config/ui_config.rs
index 49e54e05..a8b1749f 100644
--- a/alacritty/src/config/ui_config.rs
+++ b/alacritty/src/config/ui_config.rs
@@ -1,13 +1,24 @@
use log::error;
use serde::{Deserialize, Deserializer};
-use alacritty_terminal::config::{failure_default, LOG_TARGET_CONFIG};
+use alacritty_terminal::config::{failure_default, Percentage, LOG_TARGET_CONFIG};
use crate::config::bindings::{self, Binding, KeyBinding, MouseBinding};
+use crate::config::debug::Debug;
+use crate::config::font::Font;
use crate::config::mouse::Mouse;
+use crate::config::window::WindowConfig;
#[derive(Debug, PartialEq, Deserialize)]
pub struct UIConfig {
+ /// Font configuration.
+ #[serde(default, deserialize_with = "failure_default")]
+ pub font: Font,
+
+ /// Window configuration.
+ #[serde(default, deserialize_with = "failure_default")]
+ pub window: WindowConfig,
+
#[serde(default, deserialize_with = "failure_default")]
pub mouse: Mouse,
@@ -18,18 +29,79 @@ pub struct UIConfig {
/// Bindings for the mouse.
#[serde(default = "default_mouse_bindings", deserialize_with = "deserialize_mouse_bindings")]
pub mouse_bindings: Vec<MouseBinding>,
+
+ /// Debug options.
+ #[serde(default, deserialize_with = "failure_default")]
+ pub debug: Debug,
+
+ /// Send escape sequences using the alt key.
+ #[serde(default, deserialize_with = "failure_default")]
+ alt_send_esc: DefaultTrueBool,
+
+ /// Live config reload.
+ #[serde(default, deserialize_with = "failure_default")]
+ live_config_reload: DefaultTrueBool,
+
+ /// Background opacity from 0.0 to 1.0.
+ #[serde(default, deserialize_with = "failure_default")]
+ background_opacity: Percentage,
+
+ // TODO: DEPRECATED
+ #[serde(default, deserialize_with = "failure_default")]
+ pub dynamic_title: Option<bool>,
}
impl Default for UIConfig {
fn default() -> Self {
UIConfig {
- mouse: Mouse::default(),
+ font: Default::default(),
+ window: Default::default(),
+ mouse: Default::default(),
key_bindings: default_key_bindings(),
mouse_bindings: default_mouse_bindings(),
+ debug: Default::default(),
+ alt_send_esc: Default::default(),
+ background_opacity: Default::default(),
+ live_config_reload: Default::default(),
+ dynamic_title: Default::default(),
}
}
}
+impl UIConfig {
+ #[inline]
+ pub fn background_opacity(&self) -> f32 {
+ self.background_opacity.as_f32()
+ }
+
+ #[inline]
+ pub fn dynamic_title(&self) -> bool {
+ self.dynamic_title.unwrap_or_else(|| self.window.dynamic_title())
+ }
+
+ #[inline]
+ pub fn set_dynamic_title(&mut self, dynamic_title: bool) {
+ self.window.set_dynamic_title(dynamic_title);
+ }
+
+ /// Live config reload.
+ #[inline]
+ pub fn live_config_reload(&self) -> bool {
+ self.live_config_reload.0
+ }
+
+ #[inline]
+ pub fn set_live_config_reload(&mut self, live_config_reload: bool) {
+ self.live_config_reload.0 = live_config_reload;
+ }
+
+ /// Send escape sequences using the alt key.
+ #[inline]
+ pub fn alt_send_esc(&self) -> bool {
+ self.alt_send_esc.0
+ }
+}
+
fn default_key_bindings() -> Vec<KeyBinding> {
bindings::default_key_bindings()
}
@@ -83,3 +155,24 @@ where
Ok(bindings)
}
+
+#[derive(Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
+pub struct DefaultTrueBool(pub bool);
+
+impl Default for DefaultTrueBool {
+ fn default() -> Self {
+ DefaultTrueBool(true)
+ }
+}
+
+/// A delta for a point in a 2 dimensional plane.
+#[serde(default, bound(deserialize = "T: Deserialize<'de> + Default"))]
+#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)]
+pub struct Delta<T: Default + PartialEq + Eq> {
+ /// Horizontal change.
+ #[serde(deserialize_with = "failure_default")]
+ pub x: T,
+ /// Vertical change.
+ #[serde(deserialize_with = "failure_default")]
+ pub y: T,
+}
diff --git a/alacritty/src/config/window.rs b/alacritty/src/config/window.rs
new file mode 100644
index 00000000..f866e180
--- /dev/null
+++ b/alacritty/src/config/window.rs
@@ -0,0 +1,220 @@
+use std::os::raw::c_ulong;
+
+use log::error;
+use serde::{Deserialize, Deserializer};
+use serde_yaml::Value;
+
+use alacritty_terminal::config::{failure_default, option_explicit_none, LOG_TARGET_CONFIG};
+use alacritty_terminal::index::{Column, Line};
+
+use crate::config::ui_config::{DefaultTrueBool, Delta};
+
+/// Default Alacritty name, used for window title and class.
+pub const DEFAULT_NAME: &str = "Alacritty";
+
+#[serde(default)]
+#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
+pub struct WindowConfig {
+ /// Initial dimensions.
+ #[serde(deserialize_with = "failure_default")]
+ pub dimensions: Dimensions,
+
+ /// Initial position.
+ #[serde(deserialize_with = "failure_default")]
+ pub position: Option<Delta<i32>>,
+
+ /// Pixel padding.
+ #[serde(deserialize_with = "failure_default")]
+ pub padding: Delta<u8>,
+
+ /// Draw the window with title bar / borders.
+ #[serde(deserialize_with = "failure_default")]
+ pub decorations: Decorations,
+
+ /// Spread out additional padding evenly.
+ #[serde(deserialize_with = "failure_default")]
+ pub dynamic_padding: bool,
+
+ /// Startup mode.
+ #[serde(deserialize_with = "failure_default")]
+ pub startup_mode: StartupMode,
+
+ /// Window title.
+ #[serde(default = "default_title")]
+ pub title: String,
+
+ /// Window class.
+ #[serde(deserialize_with = "deserialize_class")]
+ pub class: Class,
+
+ /// XEmbed parent.
+ #[serde(skip)]
+ pub embed: Option<c_ulong>,
+
+ /// GTK theme variant.
+ #[serde(deserialize_with = "option_explicit_none")]
+ pub gtk_theme_variant: Option<String>,
+
+ /// Use dynamic title.
+ #[serde(default, deserialize_with = "failure_default")]
+ dynamic_title: DefaultTrueBool,
+}
+
+pub fn default_title() -> String {
+ DEFAULT_NAME.to_string()
+}
+
+impl WindowConfig {
+ #[inline]
+ pub fn dynamic_title(&self) -> bool {
+ self.dynamic_title.0
+ }
+
+ #[inline]
+ pub fn set_dynamic_title(&mut self, dynamic_title: bool) {
+ self.dynamic_title.0 = dynamic_title;
+ }
+}
+
+impl Default for WindowConfig {
+ fn default() -> WindowConfig {
+ WindowConfig {
+ dimensions: Default::default(),
+ position: Default::default(),
+ padding: Default::default(),
+ decorations: Default::default(),
+ dynamic_padding: Default::default(),
+ startup_mode: Default::default(),
+ class: Default::default(),
+ embed: Default::default(),
+ gtk_theme_variant: Default::default(),
+ title: default_title(),
+ dynamic_title: Default::default(),
+ }
+ }
+}
+
+#[derive(Debug, Deserialize, Copy, Clone, PartialEq, Eq)]
+pub enum StartupMode {
+ Windowed,
+ Maximized,
+ Fullscreen,
+ #[cfg(target_os = "macos")]
+ SimpleFullscreen,
+}
+
+impl Default for StartupMode {
+ fn default() -> StartupMode {
+ StartupMode::Windowed
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize)]
+pub enum Decorations {
+ #[serde(rename = "full")]
+ Full,
+ #[cfg(target_os = "macos")]
+ #[serde(rename = "transparent")]
+ Transparent,
+ #[cfg(target_os = "macos")]
+ #[serde(rename = "buttonless")]
+ Buttonless,
+ #[serde(rename = "none")]
+ None,
+}
+
+impl Default for Decorations {
+ fn default() -> Decorations {
+ Decorations::Full
+ }
+}
+
+/// Window Dimensions.
+///
+/// Newtype to avoid passing values incorrectly.
+#[serde(default)]
+#[derive(Default, Debug, Copy, Clone, Deserialize, PartialEq, Eq)]
+pub struct Dimensions {
+ /// Window width in character columns.
+ #[serde(deserialize_with = "failure_default")]
+ columns: Column,
+
+ /// Window Height in character lines.
+ #[serde(deserialize_with = "failure_default")]
+ lines: Line,
+}
+
+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
+ }
+}
+
+/// Window class hint.
+#[serde(default)]
+#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
+pub struct Class {
+ #[serde(deserialize_with = "deserialize_class_resource")]
+ pub instance: String,
+
+ #[serde(deserialize_with = "deserialize_class_resource")]
+ pub general: String,
+}
+
+impl Default for Class {
+ fn default() -> Self {
+ Class { instance: DEFAULT_NAME.into(), general: DEFAULT_NAME.into() }
+ }
+}
+
+fn deserialize_class_resource<'a, D>(deserializer: D) -> Result<String, D::Error>
+where
+ D: Deserializer<'a>,
+{
+ let value = Value::deserialize(deserializer)?;
+ match String::deserialize(value) {
+ Ok(value) => Ok(value),
+ Err(err) => {
+ error!(
+ target: LOG_TARGET_CONFIG,
+ "Problem with config: {}, using default value {}", err, DEFAULT_NAME,
+ );
+
+ Ok(DEFAULT_NAME.into())
+ },
+ }
+}
+
+fn deserialize_class<'a, D>(deserializer: D) -> Result<Class, D::Error>
+where
+ D: Deserializer<'a>,
+{
+ let value = Value::deserialize(deserializer)?;
+
+ if let Value::String(instance) = value {
+ return Ok(Class { instance, general: DEFAULT_NAME.into() });
+ }
+
+ match Class::deserialize(value) {
+ Ok(value) => Ok(value),
+ Err(err) => {
+ error!(
+ target: LOG_TARGET_CONFIG,
+ "Problem with config: {}; using class {}", err, DEFAULT_NAME
+ );
+ Ok(Class::default())
+ },
+ }
+}