alacritty/alacritty_terminal/src/config/mod.rs

2751 lines
78 KiB
Rust
Raw Normal View History

//! 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;
2019-03-30 16:48:36 +00:00
use std::collections::HashMap;
use std::fs::File;
2017-01-06 04:56:05 +00:00
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::mpsc;
use std::time::Duration;
2019-03-30 16:48:36 +00:00
use std::{env, fmt};
use font::Size;
use glutin::ModifiersState;
2019-03-30 16:48:36 +00:00
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
use serde::de::Error as SerdeError;
use serde::de::{MapAccess, Unexpected, Visitor};
use serde::{self, de, Deserialize};
use serde_yaml;
use crate::ansi::CursorStyle;
2019-03-30 16:48:36 +00:00
use crate::index::{Column, Line};
use crate::input::{Action, Binding, KeyBinding, MouseBinding};
use crate::term::color::Rgb;
pub use self::options::Options;
mod options;
mod bindings;
pub const SOURCE_FILE_PATH: &str = file!();
const MAX_SCROLLBACK_LINES: u32 = 100_000;
static DEFAULT_ALACRITTY_CONFIG: &'static str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../alacritty.yml"));
#[serde(default)]
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
pub struct Selection {
#[serde(deserialize_with = "deserialize_escape_chars")]
pub semantic_escape_chars: String,
#[serde(deserialize_with = "failure_default")]
pub save_to_clipboard: bool,
}
impl Default for Selection {
fn default() -> Selection {
Selection {
semantic_escape_chars: default_escape_chars(),
save_to_clipboard: Default::default(),
}
}
}
fn deserialize_escape_chars<'a, D>(deserializer: D) -> ::std::result::Result<String, D::Error>
2019-03-30 16:48:36 +00:00
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")]
pub threshold: Duration,
}
impl Default for ClickHandler {
fn default() -> Self {
ClickHandler { threshold: default_threshold_ms() }
}
}
fn default_threshold_ms() -> Duration {
Duration::from_millis(300)
}
2017-08-30 18:17:27 +00:00
fn deserialize_duration_ms<'a, D>(deserializer: D) -> ::std::result::Result<Duration, D::Error>
2019-03-30 16:48:36 +00:00
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())
},
}
}
#[serde(default)]
#[derive(Default, Clone, Debug, Deserialize, PartialEq, Eq)]
pub struct Mouse {
#[serde(deserialize_with = "failure_default")]
pub double_click: ClickHandler,
#[serde(deserialize_with = "failure_default")]
pub triple_click: ClickHandler,
#[serde(deserialize_with = "failure_default")]
pub hide_when_typing: bool,
#[serde(deserialize_with = "failure_default")]
pub url: Url,
// TODO: DEPRECATED
pub faux_scrollback_lines: Option<usize>,
}
#[serde(default)]
#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
pub struct Url {
// Program for opening links
#[serde(deserialize_with = "deserialize_launcher")]
pub launcher: Option<CommandWrapper>,
// Modifier used to open links
#[serde(deserialize_with = "deserialize_modifiers")]
pub modifiers: ModifiersState,
}
2019-03-30 16:48:36 +00:00
fn deserialize_launcher<'a, D>(
deserializer: D,
) -> ::std::result::Result<Option<CommandWrapper>, D::Error>
where
D: de::Deserializer<'a>,
{
let default = Url::default().launcher;
// Deserialize to generic value
let val = match serde_yaml::Value::deserialize(deserializer) {
Ok(val) => val,
Err(err) => {
error!("Problem with config: {}; using {}", err, default.clone().unwrap().program());
return Ok(default);
},
};
// Accept `None` to disable the launcher
if val.as_str().filter(|v| v.to_lowercase() == "none").is_some() {
return Ok(None);
}
match <Option<CommandWrapper>>::deserialize(val) {
Ok(launcher) => Ok(launcher),
Err(err) => {
error!("Problem with config: {}; using {}", err, default.clone().unwrap().program());
Ok(default)
},
}
}
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>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
ModsWrapper::deserialize(deserializer).map(ModsWrapper::into_inner)
}
/// `VisualBellAnimations` are modeled after a subset of CSS transitions and Robert
/// Penner's Easing Functions.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)]
pub enum VisualBellAnimation {
2019-03-30 16:48:36 +00:00
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
}
}
#[serde(default)]
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub struct VisualBellConfig {
/// Visual bell animation function
#[serde(deserialize_with = "failure_default")]
animation: VisualBellAnimation,
/// Visual bell duration in milliseconds
#[serde(deserialize_with = "failure_default")]
duration: u16,
/// Visual bell flash color
#[serde(deserialize_with = "rgb_from_hex")]
color: Rgb,
}
impl Default for VisualBellConfig {
fn default() -> VisualBellConfig {
VisualBellConfig {
animation: Default::default(),
duration: Default::default(),
color: default_visual_bell_color(),
}
}
}
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
}
}
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub struct Shell<'a> {
program: Cow<'a, str>,
#[serde(default, deserialize_with = "failure_default")]
args: Vec<String>,
}
impl<'a> Shell<'a> {
2017-01-24 23:19:45 +00:00
pub fn new<S>(program: S) -> Shell<'a>
2019-03-30 16:48:36 +00:00
where
S: Into<Cow<'a, str>>,
2017-01-24 23:19:45 +00:00
{
2019-03-30 16:48:36 +00:00
Shell { program: program.into(), args: Vec::new() }
}
2017-01-24 23:19:45 +00:00
pub fn new_with_args<S>(program: S, args: Vec<String>) -> Shell<'a>
2019-03-30 16:48:36 +00:00
where
S: Into<Cow<'a, str>>,
2017-01-24 23:19:45 +00:00
{
2019-03-30 16:48:36 +00:00
Shell { program: program.into(), args }
2017-01-24 23:19:45 +00:00
}
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, PartialEq)]
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, 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)]
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>
2019-03-30 16:48:36 +00:00
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>
2019-03-30 16:48:36 +00:00
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" => {
2019-03-30 16:48:36 +00:00
error!(
"Deprecated decorations boolean value, use one of \
transparent|buttonless|none|full instead; falling back to \"full\""
);
Ok(Decorations::Full)
},
"false" => {
2019-03-30 16:48:36 +00:00
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)
2019-03-30 16:48:36 +00:00
},
}
}
#[cfg(not(target_os = "macos"))]
fn visit_str<E>(self, value: &str) -> ::std::result::Result<Decorations, E>
2019-03-30 16:48:36 +00:00
where
E: de::Error,
{
match value.to_lowercase().as_str() {
"none" => Ok(Decorations::None),
"full" => Ok(Decorations::Full),
"true" => {
2019-03-30 16:48:36 +00:00
error!(
"Deprecated decorations boolean value, use one of none|full instead; \
falling back to \"full\""
);
Ok(Decorations::Full)
},
"false" => {
2019-03-30 16:48:36 +00:00
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)
2019-03-30 16:48:36 +00:00
},
}
}
}
deserializer.deserialize_str(DecorationsVisitor)
}
}
#[serde(default)]
#[derive(Debug, Copy, Clone, Deserialize, PartialEq, Eq)]
pub struct WindowConfig {
/// Initial dimensions
#[serde(default, deserialize_with = "failure_default")]
dimensions: Dimensions,
/// Initial position
#[serde(default, deserialize_with = "failure_default")]
position: Option<Delta<i32>>,
/// Pixel padding
#[serde(deserialize_with = "deserialize_padding")]
padding: Delta<u8>,
/// Draw the window with title bar / borders
#[serde(deserialize_with = "failure_default")]
decorations: Decorations,
/// Spread out additional padding evenly
#[serde(deserialize_with = "failure_default")]
dynamic_padding: bool,
/// Startup mode
#[serde(deserialize_with = "failure_default")]
startup_mode: StartupMode,
/// TODO: DEPRECATED
#[serde(deserialize_with = "failure_default")]
start_maximized: Option<bool>,
}
impl Default for WindowConfig {
fn default() -> Self {
2019-03-30 16:48:36 +00:00
WindowConfig {
dimensions: Default::default(),
position: Default::default(),
padding: default_padding(),
decorations: Default::default(),
dynamic_padding: Default::default(),
start_maximized: Default::default(),
startup_mode: Default::default(),
}
}
}
fn default_padding() -> Delta<u8> {
Delta { x: 2, y: 2 }
}
fn deserialize_padding<'a, D>(deserializer: D) -> ::std::result::Result<Delta<u8>, D::Error>
2019-03-30 16:48:36 +00:00
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 startup_mode(&self) -> StartupMode {
self.startup_mode
}
pub fn position(&self) -> Option<Delta<i32>> {
self.position
}
}
/// Top-level config type
#[derive(Debug, PartialEq, Deserialize)]
pub struct Config {
/// Pixel padding
#[serde(default, deserialize_with = "failure_default")]
padding: Option<Delta<u8>>,
2017-02-14 02:22:59 +00:00
/// TERM env variable
#[serde(default, deserialize_with = "failure_default")]
2017-02-14 02:22:59 +00:00
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,
2017-10-30 15:03:58 +00:00
/// Should draw bold text with brighter colors instead of bold font
#[serde(default = "default_true_bool", deserialize_with = "deserialize_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
2019-03-30 16:48:36 +00:00
#[serde(default = "default_key_bindings", deserialize_with = "deserialize_key_bindings")]
key_bindings: Vec<KeyBinding>,
/// Bindings for the mouse
2019-03-30 16:48:36 +00:00
#[serde(default = "default_mouse_bindings", deserialize_with = "deserialize_mouse_bindings")]
mouse_bindings: Vec<MouseBinding>,
#[serde(default, deserialize_with = "failure_default")]
selection: Selection,
#[serde(default, deserialize_with = "failure_default")]
mouse: Mouse,
2017-01-07 17:07:06 +00:00
/// 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,
2017-02-22 19:52:37 +00:00
/// Use dynamic title
#[serde(default = "default_true_bool", deserialize_with = "deserialize_true_bool")]
dynamic_title: bool,
/// Live config reload
#[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")]
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,
Display errors and warnings To make sure that all error and information reporting to the user is unified, all instances of `print!`, `eprint!`, `println!` and `eprintln!` have been removed and replaced by logging. When `RUST_LOG` is not specified, the default Alacritty logger now also prints to both the stderr and a log file. The log file is only created when a message is written to it and its name is printed to stdout the first time it is used. Whenever a warning or an error has been written to the log file/stderr, a message is now displayed in Alacritty which points to the log file where the full error is documented. The message is cleared whenever the screen is cleared using either the `clear` command or the `Ctrl+L` key binding. To make sure that log files created by root don't prevent normal users from interacting with them, the Alacritty log file is `/tmp/Alacritty-$PID.log`. Since it's still possible that the log file can't be created, the UI error/warning message now informs the user if the message was only written to stderr. The reason why it couldn't be created is then printed to stderr. To make sure the deletion of the log file at runtime doesn't create any issues, the file is re-created if a write is attempted without the file being present. To help with debugging Alacritty issues, a timestamp and the error level are printed in all log messages. All log messages now follow this format: [YYYY-MM-DD HH:MM] [LEVEL] Message Since it's not unusual to spawn a lot of different terminal emulators without restarting, Alacritty can create a ton of different log files. To combat this problem, logfiles are removed by default after Alacritty has been closed. If the user wants to persist the log of a single session, the `--persistent_logging` option can be used. For persisting all log files, the `persistent_logging` option can be set in the configuration file
2018-11-17 14:39:13 +00:00
/// Keep the log file after quitting
#[serde(default, deserialize_with = "failure_default")]
Display errors and warnings To make sure that all error and information reporting to the user is unified, all instances of `print!`, `eprint!`, `println!` and `eprintln!` have been removed and replaced by logging. When `RUST_LOG` is not specified, the default Alacritty logger now also prints to both the stderr and a log file. The log file is only created when a message is written to it and its name is printed to stdout the first time it is used. Whenever a warning or an error has been written to the log file/stderr, a message is now displayed in Alacritty which points to the log file where the full error is documented. The message is cleared whenever the screen is cleared using either the `clear` command or the `Ctrl+L` key binding. To make sure that log files created by root don't prevent normal users from interacting with them, the Alacritty log file is `/tmp/Alacritty-$PID.log`. Since it's still possible that the log file can't be created, the UI error/warning message now informs the user if the message was only written to stderr. The reason why it couldn't be created is then printed to stderr. To make sure the deletion of the log file at runtime doesn't create any issues, the file is re-created if a write is attempted without the file being present. To help with debugging Alacritty issues, a timestamp and the error level are printed in all log messages. All log messages now follow this format: [YYYY-MM-DD HH:MM] [LEVEL] Message Since it's not unusual to spawn a lot of different terminal emulators without restarting, Alacritty can create a ton of different log files. To combat this problem, logfiles are removed by default after Alacritty has been closed. If the user wants to persist the log of a single session, the `--persistent_logging` option can be used. For persisting all log files, the `persistent_logging` option can be set in the configuration file
2018-11-17 14:39:13 +00:00
persistent_logging: 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,
/// Send escape sequences using the alt key.
#[serde(default = "default_true_bool", deserialize_with = "deserialize_true_bool")]
alt_send_esc: bool,
// TODO: DEPRECATED
custom_cursor_colors: Option<bool>,
// TODO: DEPRECATED
hide_cursor_when_typing: Option<bool>,
// TODO: DEPRECATED
cursor_style: Option<CursorStyle>,
// TODO: DEPRECATED
unfocused_hollow_cursor: Option<bool>,
// TODO: DEPRECATED
dimensions: Option<Dimensions>,
}
2018-12-28 16:01:58 +00:00
impl Default for Config {
fn default() -> Self {
2019-03-30 16:48:36 +00:00
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()
}
2019-03-30 16:48:36 +00:00
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())
}
2019-03-30 16:48:36 +00:00
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())
}
2019-03-30 16:48:36 +00:00
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>
2019-03-30 16:48:36 +00:00
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>
2019-03-30 16:48:36 +00:00
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 deserialize_true_bool<'a, D>(deserializer: D) -> ::std::result::Result<bool, D::Error>
2019-03-30 16:48:36 +00:00
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 default_true_bool() -> bool {
true
}
2019-03-30 16:48:36 +00:00
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())
},
}
}
/// Struct for scrolling related settings
#[serde(default)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
pub struct Scrolling {
#[serde(deserialize_with = "deserialize_scrolling_history")]
pub history: u32,
#[serde(deserialize_with = "deserialize_scrolling_multiplier")]
pub multiplier: u8,
#[serde(deserialize_with = "deserialize_scrolling_multiplier")]
pub faux_multiplier: u8,
#[serde(deserialize_with = "failure_default")]
pub auto_scroll: bool,
}
impl Default for Scrolling {
fn default() -> Self {
Self {
history: default_scrolling_history(),
multiplier: default_scrolling_multiplier(),
faux_multiplier: default_scrolling_multiplier(),
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>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
match u32::deserialize(deserializer) {
Ok(lines) => {
if lines > MAX_SCROLLBACK_LINES {
Display errors and warnings To make sure that all error and information reporting to the user is unified, all instances of `print!`, `eprint!`, `println!` and `eprintln!` have been removed and replaced by logging. When `RUST_LOG` is not specified, the default Alacritty logger now also prints to both the stderr and a log file. The log file is only created when a message is written to it and its name is printed to stdout the first time it is used. Whenever a warning or an error has been written to the log file/stderr, a message is now displayed in Alacritty which points to the log file where the full error is documented. The message is cleared whenever the screen is cleared using either the `clear` command or the `Ctrl+L` key binding. To make sure that log files created by root don't prevent normal users from interacting with them, the Alacritty log file is `/tmp/Alacritty-$PID.log`. Since it's still possible that the log file can't be created, the UI error/warning message now informs the user if the message was only written to stderr. The reason why it couldn't be created is then printed to stderr. To make sure the deletion of the log file at runtime doesn't create any issues, the file is re-created if a write is attempted without the file being present. To help with debugging Alacritty issues, a timestamp and the error level are printed in all log messages. All log messages now follow this format: [YYYY-MM-DD HH:MM] [LEVEL] Message Since it's not unusual to spawn a lot of different terminal emulators without restarting, Alacritty can create a ton of different log files. To combat this problem, logfiles are removed by default after Alacritty has been closed. If the user wants to persist the log of a single session, the `--persistent_logging` option can be used. For persisting all log files, the `persistent_logging` option can be set in the configuration file
2018-11-17 14:39:13 +00:00
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>
2019-03-30 16:48:36 +00:00
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
}
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for ModsWrapper {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
struct ModsVisitor;
2017-08-30 18:17:27 +00:00
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>
2019-03-30 16:48:36 +00:00
where
E: de::Error,
{
let mut res = ModifiersState::default();
for modifier in value.split('|') {
2017-01-05 13:33:45 +00:00
match modifier.trim() {
"Command" | "Super" => res.logo = true,
"Shift" => res.shift = true,
"Alt" | "Option" => res.alt = true,
"Control" => res.ctrl = true,
"None" => (),
_ => 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
}
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for ActionWrapper {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
struct ActionVisitor;
2017-08-30 18:17:27 +00:00
impl<'a> Visitor<'a> for ActionVisitor {
type Value = ActionWrapper;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2019-03-30 16:48:36 +00:00
f.write_str(
"Paste, Copy, PasteSelection, IncreaseFontSize, DecreaseFontSize, \
ResetFontSize, ScrollPageUp, ScrollPageDown, ScrollLineUp, ScrollLineDown, \
ScrollToTop, ScrollToBottom, ClearHistory, Hide, ClearLogNotice, \
SpawnNewInstance, ToggleFullscreen, ToggleSimpleFullscreen, None or Quit",
2019-03-30 16:48:36 +00:00
)
}
fn visit_str<E>(self, value: &str) -> ::std::result::Result<ActionWrapper, E>
2019-03-30 16:48:36 +00:00
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,
"ScrollLineUp" => Action::ScrollLineUp,
"ScrollLineDown" => Action::ScrollLineDown,
"ScrollToTop" => Action::ScrollToTop,
"ScrollToBottom" => Action::ScrollToBottom,
"ClearHistory" => Action::ClearHistory,
Merge master into scrollback * Allow disabling DPI scaling This makes it possible to disable DPI scaling completely, instead the the display pixel ration will always be fixed to 1.0. By default nothing has changed and DPI is still enabled, this just seems like a better way than running `WINIT_HIDPI_FACTOR=1.0 alacritty` every time the user wants to start alacritty. It would be possible to allow specifying any DPR, however I've decided against this since I'd assume it's a very rare usecase. It's also still possible to make use of `WINIT_HIDPI_FACTOR` to do this on X11. Currently this is not updated at runtime using the live config update, there is not really much of a technical limitation why this woudn't be possible, however a solution for that issue should be first added in jwilm/alacritty#1346, once a system is established for changing DPI at runtime, porting that functionality to this PR should be simple. * Add working --class and --title CLI parameters * Reduce Increase-/DecreaseFontSize step to 0.5 Until now the Increase-/DecreaseFontSize keybinds hand a step size of 1.0. Since the font size however is multiplied by two to allow more granular font size control, this lead to the bindings skipping one font size (incrementing/decrementing by +-2). To fix this the step size of the Increase-/DecreaseFontSize bindings has been reduced to the minimum step size that exists with the current font configuration (0.5). This should allow users to increment and decrement the font size by a single point instead of two. This also adds a few tests to make sure the methods for increasing/decreasing/resetting font size work properly. * Add Copy/Cut/Paste keys This just adds support for the Copy/Cut/Paste keys and sets up Copy/Paste as alternative defaults for Ctrl+Shift+C/V. * Move to cargo clippy Using clippy as a library has been deprecated, instead the `cargo clippy` command should be used instead. To comply with this change clippy has been removed from the `Cargo.toml` and is now installed with cargo when building in CI. This has also lead to a few new clippy issues to show up, this includes everything in the `font` subdirectory. This has been fixed and `font` should now be covered by clippy CI too. This also upgrades all dependencies, as a result this fixes #1341 and this fixes #1344. * Override dynamic_title when --title is specified * Change green implementation to use the macro * Ignore mouse input if window is unfocused * Make compilation of binary a phony target * Add opensuse zypper install method to readme * Fix clippy issues * Update manpage to document all CLI options The introduction of `--class` has added a flag to the CLI without adding it to the manpage. This has been fixed by updating the manpage. This also adds the default values of `--class` and `--title` to the CLI options. * Remove unnecessary clippy lint annotations We moved to "cargo clippy" in 5ba34d4f9766a55a06ed5e3e44cc384af1b09f65 and removing the clippy lint annotations in `src/lib.rs` does not cause any additional warnings. This also changes `cargo clippy` to use the flags required for checking integration tests. * Enable clippy in font/copypasta crates Enabled clippy in the sub-crates font and copypasta. All issues that were discovered by this change have also been fixed. * Remove outdated comment about NixOS * Replace debug asserts with static_assertions To check that transmutes will work correctly without having to rely on error-prone runtime checking, the `static_assertions` crate has been introduced. This allows comparing the size of types at compile time, preventing potentially silent breakage. This fixes #1417. * Add `cargo deb` build instructions Updated the `Cargo.toml` file and added a `package.metadata.deb` subsection to define how to build a debian "deb" install file using `cargo deb`. This will allow debian/ubuntu users to install `alacritty` using their system's package manager. It also will make it easier to provide pre-built binaries for those systems. Also fixed a stray debug line in the bash autocomplete script that was writting to a tempfile. * Add config for unfocused window cursor change * Add support for cursor shape escape sequence * Add bright foreground color option It was requested in jwilm/alacritty#825 that it should be possible to add an optional bright foreground color. This is now added to the primary colors structure and allows the user to set a foreground color for bold normal text. This has no effect unless the draw_bold_text_with_bright_colors option is also enabled. If the color is not specified, the bright foreground color will fall back to the normal foreground color. This fixes #825. * Fix clone URL in deb install instructions * Fix 'cargo-deb' desktop file name * Remove redundant dependency from deb build * Switch from deprecated `std::env::home_dir` to `dirs::home_dir` * Allow specifying modifiers for mouse bindings * Send newline with NumpadEnter * Add support for LCD-V pixel mode * Add binding action for hiding the window * Switch to rustup clippy component * Add optional dim foreground color Add optional color for the dim foreground (`\e[2m;`) Defaults to 2/3 of the foreground color. (same as other colors). If a bright color is dimmed, it's displayed as the normal color. The exception for this is when the bright foreground is dimmed when no bright foreground color is set. In that case it's treated as a normal foreground color and dimmed to DimForeground. To minimize the surprise for the user, the bright and dim colors have been completely removed from the default configuration file. Some documentation has also been added to make it clear to users what these options can be used for. This fixes #1448. * Fix clippy lints and run font tests on travis This fixes some existing clippy issues and runs the `font` tests through travis. Testing of copypasta crate was omitted due to problens when running on headless travis-ci environment (x11 clipboard would fail). * Ignore errors when logger can't write to output The (e)print macro will panic when there is no output available to write to, however in our scenario where we only log user errors to stderr, the better choice would be to ignore when writing to stdout or stderr is not possible. This changes the (e)print macro to make use of `write` and ignore any potential errors. Since (e)println rely on (e)print, this also solves potential failuers when calling (e)println. With this change implemented, all of logging, (e)println and (e)print should never fail even if the stdout/stderr is not available.
2018-07-28 23:10:13 +00:00
"Hide" => Action::Hide,
"Quit" => Action::Quit,
"ClearLogNotice" => Action::ClearLogNotice,
"SpawnNewInstance" => Action::SpawnNewInstance,
"ToggleFullscreen" => Action::ToggleFullscreen,
#[cfg(target_os = "macos")]
"ToggleSimpleFullscreen" => Action::ToggleSimpleFullscreen,
"None" => Action::None,
_ => return Err(E::invalid_value(Unexpected::Str(value), &self)),
}))
}
}
deserializer.deserialize_str(ActionVisitor)
}
}
#[serde(untagged)]
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
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,
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for ModeWrapper {
2019-03-30 16:48:36 +00:00
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
where
D: de::Deserializer<'a>,
{
struct ModeVisitor;
2017-08-30 18:17:27 +00:00
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>
2019-03-30 16:48:36 +00:00
where
E: de::Error,
{
2019-03-30 16:48:36 +00:00
let mut res = ModeWrapper { mode: TermMode::empty(), not_mode: TermMode::empty() };
for modifier in value.split('|') {
2017-01-05 13:33:45 +00:00
match modifier.trim() {
2017-10-12 01:52:23 +00:00
"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,
"~Alt" => res.not_mode |= mode::TermMode::ALT_SCREEN,
"Alt" => res.mode |= mode::TermMode::ALT_SCREEN,
_ => error!("Unknown mode {:?}", modifier),
}
}
Ok(res)
}
}
deserializer.deserialize_str(ModeVisitor)
}
}
struct MouseButton(::glutin::MouseButton);
impl MouseButton {
fn into_inner(self) -> ::glutin::MouseButton {
self.0
}
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for MouseButton {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
struct MouseButtonVisitor;
2017-08-30 18:17:27 +00:00
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>
2019-03-30 16:48:36 +00:00
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))
}
2019-03-30 16:48:36 +00:00
},
}
}
}
deserializer.deserialize_str(MouseButtonVisitor)
}
}
/// 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>,
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)
}
}
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for RawBinding {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
enum Field {
Key,
Mods,
Mode,
Action,
Chars,
Mouse,
Command,
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for Field {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Field, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
struct FieldVisitor;
2019-03-30 16:48:36 +00:00
static FIELDS: &'static [&'static str] =
&["key", "mods", "mode", "action", "chars", "mouse", "command"];
2017-08-30 18:17:27 +00:00
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>
2019-03-30 16:48:36 +00:00
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;
2017-08-30 18:17:27 +00:00
impl<'a> Visitor<'a> for RawBindingVisitor {
type Value = RawBinding;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("binding specification")
}
2019-03-30 16:48:36 +00:00
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;
2017-08-30 18:17:27 +00:00
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 {
2019-03-30 16:48:36 +00:00
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"));
}
2017-08-30 18:17:27 +00:00
mods = Some(map.next_value::<ModsWrapper>()?.into_inner());
},
Field::Mode => {
if mode.is_some() {
return Err(<V::Error as Error>::duplicate_field("mode"));
}
2017-08-30 18:17:27 +00:00
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"));
}
2017-08-30 18:17:27 +00:00
action = Some(map.next_value::<ActionWrapper>()?.into_inner());
},
Field::Chars => {
if chars.is_some() {
return Err(<V::Error as Error>::duplicate_field("chars"));
}
2017-08-30 18:17:27 +00:00
chars = Some(map.next_value()?);
},
Field::Mouse => {
if chars.is_some() {
return Err(<V::Error as Error>::duplicate_field("mouse"));
}
2017-08-30 18:17:27 +00:00
mouse = Some(map.next_value::<MouseButton>()?.into_inner());
},
Field::Command => {
if command.is_some() {
return Err(<V::Error as Error>::duplicate_field("command"));
}
2017-08-30 18:17:27 +00:00
command = Some(map.next_value::<CommandWrapper>()?);
},
}
}
let action = match (action, chars, command) {
(Some(action), None, None) => action,
(None, Some(chars), None) => Action::Esc(chars),
2019-03-30 16:48:36 +00:00
(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"));
}
2019-03-30 16:48:36 +00:00
Ok(RawBinding { mode, notmode: not_mode, action, key, mouse, mods })
}
}
2019-03-30 16:48:36 +00:00
const FIELDS: &[&str] = &["key", "mods", "mode", "action", "chars", "mouse", "command"];
deserializer.deserialize_struct("RawBinding", FIELDS, RawBindingVisitor)
}
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for Alpha {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
let value = f32::deserialize(deserializer)?;
Ok(Alpha::new(value))
}
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for MouseBinding {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
let raw = RawBinding::deserialize(deserializer)?;
2019-03-30 16:48:36 +00:00
raw.into_mouse_binding().map_err(|_| D::Error::custom("expected mouse binding"))
}
}
2017-08-30 18:17:27 +00:00
impl<'a> de::Deserialize<'a> for KeyBinding {
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
let raw = RawBinding::deserialize(deserializer)?;
2019-03-30 16:48:36 +00:00
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),
}
#[serde(default)]
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub struct Colors {
#[serde(deserialize_with = "failure_default")]
pub primary: PrimaryColors,
#[serde(deserialize_with = "failure_default")]
pub cursor: CursorColors,
#[serde(deserialize_with = "failure_default")]
pub selection: SelectionColors,
#[serde(deserialize_with = "deserialize_normal_colors")]
pub normal: AnsiColors,
#[serde(deserialize_with = "deserialize_bright_colors")]
pub bright: AnsiColors,
#[serde(deserialize_with = "failure_default")]
pub dim: Option<AnsiColors>,
#[serde(deserialize_with = "failure_default_vec")]
pub indexed_colors: Vec<IndexedColor>,
}
impl Default for Colors {
fn default() -> Colors {
Colors {
primary: Default::default(),
cursor: Default::default(),
selection: Default::default(),
normal: default_normal_colors(),
bright: default_bright_colors(),
dim: Default::default(),
indexed_colors: Default::default(),
}
}
}
fn default_normal_colors() -> AnsiColors {
AnsiColors {
2019-03-30 16:48:36 +00:00
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 {
2019-03-30 16:48:36 +00:00
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>
2019-03-30 16:48:36 +00:00
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>
2019-03-30 16:48:36 +00:00
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,
#[serde(deserialize_with = "rgb_from_hex")]
pub color: Rgb,
}
fn deserialize_color_index<'a, D>(deserializer: D) -> ::std::result::Result<u8, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
match u8::deserialize(deserializer) {
Ok(index) => {
if index < 16 {
Display errors and warnings To make sure that all error and information reporting to the user is unified, all instances of `print!`, `eprint!`, `println!` and `eprintln!` have been removed and replaced by logging. When `RUST_LOG` is not specified, the default Alacritty logger now also prints to both the stderr and a log file. The log file is only created when a message is written to it and its name is printed to stdout the first time it is used. Whenever a warning or an error has been written to the log file/stderr, a message is now displayed in Alacritty which points to the log file where the full error is documented. The message is cleared whenever the screen is cleared using either the `clear` command or the `Ctrl+L` key binding. To make sure that log files created by root don't prevent normal users from interacting with them, the Alacritty log file is `/tmp/Alacritty-$PID.log`. Since it's still possible that the log file can't be created, the UI error/warning message now informs the user if the message was only written to stderr. The reason why it couldn't be created is then printed to stderr. To make sure the deletion of the log file at runtime doesn't create any issues, the file is re-created if a write is attempted without the file being present. To help with debugging Alacritty issues, a timestamp and the error level are printed in all log messages. All log messages now follow this format: [YYYY-MM-DD HH:MM] [LEVEL] Message Since it's not unusual to spawn a lot of different terminal emulators without restarting, Alacritty can create a ton of different log files. To combat this problem, logfiles are removed by default after Alacritty has been closed. If the user wants to persist the log of a single session, the `--persistent_logging` option can be used. For persisting all log files, the `persistent_logging` option can be set in the configuration file
2018-11-17 14:39:13 +00:00
error!(
2019-03-30 16:48:36 +00:00
"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)
},
}
}
#[serde(default)]
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq)]
pub struct Cursor {
#[serde(deserialize_with = "failure_default")]
pub style: CursorStyle,
#[serde(deserialize_with = "deserialize_true_bool")]
pub unfocused_hollow: bool,
}
impl Default for Cursor {
fn default() -> Self {
2019-03-30 16:48:36 +00:00
Self { style: Default::default(), unfocused_hollow: true }
}
}
#[serde(default)]
#[derive(Debug, Copy, Clone, Default, Deserialize, PartialEq, Eq)]
pub struct CursorColors {
#[serde(deserialize_with = "deserialize_optional_color")]
pub text: Option<Rgb>,
#[serde(deserialize_with = "deserialize_optional_color")]
pub cursor: Option<Rgb>,
}
#[serde(default)]
#[derive(Debug, Copy, Clone, Default, Deserialize, PartialEq, Eq)]
pub struct SelectionColors {
#[serde(deserialize_with = "deserialize_optional_color")]
pub text: Option<Rgb>,
#[serde(deserialize_with = "deserialize_optional_color")]
pub background: Option<Rgb>,
}
#[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(deserialize_with = "deserialize_optional_color")]
Merge master into scrollback * Allow disabling DPI scaling This makes it possible to disable DPI scaling completely, instead the the display pixel ration will always be fixed to 1.0. By default nothing has changed and DPI is still enabled, this just seems like a better way than running `WINIT_HIDPI_FACTOR=1.0 alacritty` every time the user wants to start alacritty. It would be possible to allow specifying any DPR, however I've decided against this since I'd assume it's a very rare usecase. It's also still possible to make use of `WINIT_HIDPI_FACTOR` to do this on X11. Currently this is not updated at runtime using the live config update, there is not really much of a technical limitation why this woudn't be possible, however a solution for that issue should be first added in jwilm/alacritty#1346, once a system is established for changing DPI at runtime, porting that functionality to this PR should be simple. * Add working --class and --title CLI parameters * Reduce Increase-/DecreaseFontSize step to 0.5 Until now the Increase-/DecreaseFontSize keybinds hand a step size of 1.0. Since the font size however is multiplied by two to allow more granular font size control, this lead to the bindings skipping one font size (incrementing/decrementing by +-2). To fix this the step size of the Increase-/DecreaseFontSize bindings has been reduced to the minimum step size that exists with the current font configuration (0.5). This should allow users to increment and decrement the font size by a single point instead of two. This also adds a few tests to make sure the methods for increasing/decreasing/resetting font size work properly. * Add Copy/Cut/Paste keys This just adds support for the Copy/Cut/Paste keys and sets up Copy/Paste as alternative defaults for Ctrl+Shift+C/V. * Move to cargo clippy Using clippy as a library has been deprecated, instead the `cargo clippy` command should be used instead. To comply with this change clippy has been removed from the `Cargo.toml` and is now installed with cargo when building in CI. This has also lead to a few new clippy issues to show up, this includes everything in the `font` subdirectory. This has been fixed and `font` should now be covered by clippy CI too. This also upgrades all dependencies, as a result this fixes #1341 and this fixes #1344. * Override dynamic_title when --title is specified * Change green implementation to use the macro * Ignore mouse input if window is unfocused * Make compilation of binary a phony target * Add opensuse zypper install method to readme * Fix clippy issues * Update manpage to document all CLI options The introduction of `--class` has added a flag to the CLI without adding it to the manpage. This has been fixed by updating the manpage. This also adds the default values of `--class` and `--title` to the CLI options. * Remove unnecessary clippy lint annotations We moved to "cargo clippy" in 5ba34d4f9766a55a06ed5e3e44cc384af1b09f65 and removing the clippy lint annotations in `src/lib.rs` does not cause any additional warnings. This also changes `cargo clippy` to use the flags required for checking integration tests. * Enable clippy in font/copypasta crates Enabled clippy in the sub-crates font and copypasta. All issues that were discovered by this change have also been fixed. * Remove outdated comment about NixOS * Replace debug asserts with static_assertions To check that transmutes will work correctly without having to rely on error-prone runtime checking, the `static_assertions` crate has been introduced. This allows comparing the size of types at compile time, preventing potentially silent breakage. This fixes #1417. * Add `cargo deb` build instructions Updated the `Cargo.toml` file and added a `package.metadata.deb` subsection to define how to build a debian "deb" install file using `cargo deb`. This will allow debian/ubuntu users to install `alacritty` using their system's package manager. It also will make it easier to provide pre-built binaries for those systems. Also fixed a stray debug line in the bash autocomplete script that was writting to a tempfile. * Add config for unfocused window cursor change * Add support for cursor shape escape sequence * Add bright foreground color option It was requested in jwilm/alacritty#825 that it should be possible to add an optional bright foreground color. This is now added to the primary colors structure and allows the user to set a foreground color for bold normal text. This has no effect unless the draw_bold_text_with_bright_colors option is also enabled. If the color is not specified, the bright foreground color will fall back to the normal foreground color. This fixes #825. * Fix clone URL in deb install instructions * Fix 'cargo-deb' desktop file name * Remove redundant dependency from deb build * Switch from deprecated `std::env::home_dir` to `dirs::home_dir` * Allow specifying modifiers for mouse bindings * Send newline with NumpadEnter * Add support for LCD-V pixel mode * Add binding action for hiding the window * Switch to rustup clippy component * Add optional dim foreground color Add optional color for the dim foreground (`\e[2m;`) Defaults to 2/3 of the foreground color. (same as other colors). If a bright color is dimmed, it's displayed as the normal color. The exception for this is when the bright foreground is dimmed when no bright foreground color is set. In that case it's treated as a normal foreground color and dimmed to DimForeground. To minimize the surprise for the user, the bright and dim colors have been completely removed from the default configuration file. Some documentation has also been added to make it clear to users what these options can be used for. This fixes #1448. * Fix clippy lints and run font tests on travis This fixes some existing clippy issues and runs the `font` tests through travis. Testing of copypasta crate was omitted due to problens when running on headless travis-ci environment (x11 clipboard would fail). * Ignore errors when logger can't write to output The (e)print macro will panic when there is no output available to write to, however in our scenario where we only log user errors to stderr, the better choice would be to ignore when writing to stdout or stderr is not possible. This changes the (e)print macro to make use of `write` and ignore any potential errors. Since (e)println rely on (e)print, this also solves potential failuers when calling (e)println. With this change implemented, all of logging, (e)println and (e)print should never fail even if the stdout/stderr is not available.
2018-07-28 23:10:13 +00:00
pub bright_foreground: Option<Rgb>,
#[serde(deserialize_with = "deserialize_optional_color")]
Merge master into scrollback * Allow disabling DPI scaling This makes it possible to disable DPI scaling completely, instead the the display pixel ration will always be fixed to 1.0. By default nothing has changed and DPI is still enabled, this just seems like a better way than running `WINIT_HIDPI_FACTOR=1.0 alacritty` every time the user wants to start alacritty. It would be possible to allow specifying any DPR, however I've decided against this since I'd assume it's a very rare usecase. It's also still possible to make use of `WINIT_HIDPI_FACTOR` to do this on X11. Currently this is not updated at runtime using the live config update, there is not really much of a technical limitation why this woudn't be possible, however a solution for that issue should be first added in jwilm/alacritty#1346, once a system is established for changing DPI at runtime, porting that functionality to this PR should be simple. * Add working --class and --title CLI parameters * Reduce Increase-/DecreaseFontSize step to 0.5 Until now the Increase-/DecreaseFontSize keybinds hand a step size of 1.0. Since the font size however is multiplied by two to allow more granular font size control, this lead to the bindings skipping one font size (incrementing/decrementing by +-2). To fix this the step size of the Increase-/DecreaseFontSize bindings has been reduced to the minimum step size that exists with the current font configuration (0.5). This should allow users to increment and decrement the font size by a single point instead of two. This also adds a few tests to make sure the methods for increasing/decreasing/resetting font size work properly. * Add Copy/Cut/Paste keys This just adds support for the Copy/Cut/Paste keys and sets up Copy/Paste as alternative defaults for Ctrl+Shift+C/V. * Move to cargo clippy Using clippy as a library has been deprecated, instead the `cargo clippy` command should be used instead. To comply with this change clippy has been removed from the `Cargo.toml` and is now installed with cargo when building in CI. This has also lead to a few new clippy issues to show up, this includes everything in the `font` subdirectory. This has been fixed and `font` should now be covered by clippy CI too. This also upgrades all dependencies, as a result this fixes #1341 and this fixes #1344. * Override dynamic_title when --title is specified * Change green implementation to use the macro * Ignore mouse input if window is unfocused * Make compilation of binary a phony target * Add opensuse zypper install method to readme * Fix clippy issues * Update manpage to document all CLI options The introduction of `--class` has added a flag to the CLI without adding it to the manpage. This has been fixed by updating the manpage. This also adds the default values of `--class` and `--title` to the CLI options. * Remove unnecessary clippy lint annotations We moved to "cargo clippy" in 5ba34d4f9766a55a06ed5e3e44cc384af1b09f65 and removing the clippy lint annotations in `src/lib.rs` does not cause any additional warnings. This also changes `cargo clippy` to use the flags required for checking integration tests. * Enable clippy in font/copypasta crates Enabled clippy in the sub-crates font and copypasta. All issues that were discovered by this change have also been fixed. * Remove outdated comment about NixOS * Replace debug asserts with static_assertions To check that transmutes will work correctly without having to rely on error-prone runtime checking, the `static_assertions` crate has been introduced. This allows comparing the size of types at compile time, preventing potentially silent breakage. This fixes #1417. * Add `cargo deb` build instructions Updated the `Cargo.toml` file and added a `package.metadata.deb` subsection to define how to build a debian "deb" install file using `cargo deb`. This will allow debian/ubuntu users to install `alacritty` using their system's package manager. It also will make it easier to provide pre-built binaries for those systems. Also fixed a stray debug line in the bash autocomplete script that was writting to a tempfile. * Add config for unfocused window cursor change * Add support for cursor shape escape sequence * Add bright foreground color option It was requested in jwilm/alacritty#825 that it should be possible to add an optional bright foreground color. This is now added to the primary colors structure and allows the user to set a foreground color for bold normal text. This has no effect unless the draw_bold_text_with_bright_colors option is also enabled. If the color is not specified, the bright foreground color will fall back to the normal foreground color. This fixes #825. * Fix clone URL in deb install instructions * Fix 'cargo-deb' desktop file name * Remove redundant dependency from deb build * Switch from deprecated `std::env::home_dir` to `dirs::home_dir` * Allow specifying modifiers for mouse bindings * Send newline with NumpadEnter * Add support for LCD-V pixel mode * Add binding action for hiding the window * Switch to rustup clippy component * Add optional dim foreground color Add optional color for the dim foreground (`\e[2m;`) Defaults to 2/3 of the foreground color. (same as other colors). If a bright color is dimmed, it's displayed as the normal color. The exception for this is when the bright foreground is dimmed when no bright foreground color is set. In that case it's treated as a normal foreground color and dimmed to DimForeground. To minimize the surprise for the user, the bright and dim colors have been completely removed from the default configuration file. Some documentation has also been added to make it clear to users what these options can be used for. This fixes #1448. * Fix clippy lints and run font tests on travis This fixes some existing clippy issues and runs the `font` tests through travis. Testing of copypasta crate was omitted due to problens when running on headless travis-ci environment (x11 clipboard would fail). * Ignore errors when logger can't write to output The (e)print macro will panic when there is no output available to write to, however in our scenario where we only log user errors to stderr, the better choice would be to ignore when writing to stdout or stderr is not possible. This changes the (e)print macro to make use of `write` and ignore any potential errors. Since (e)println rely on (e)print, this also solves potential failuers when calling (e)println. With this change implemented, all of logging, (e)println and (e)print should never fail even if the stdout/stderr is not available.
2018-07-28 23:10:13 +00:00
pub dim_foreground: Option<Rgb>,
}
impl Default for PrimaryColors {
fn default() -> Self {
PrimaryColors {
background: default_background(),
foreground: default_foreground(),
bright_foreground: Default::default(),
dim_foreground: Default::default(),
}
}
}
2019-03-30 16:48:36 +00:00
fn deserialize_optional_color<'a, D>(
deserializer: D,
) -> ::std::result::Result<Option<Rgb>, D::Error>
where
D: de::Deserializer<'a>,
Merge master into scrollback * Allow disabling DPI scaling This makes it possible to disable DPI scaling completely, instead the the display pixel ration will always be fixed to 1.0. By default nothing has changed and DPI is still enabled, this just seems like a better way than running `WINIT_HIDPI_FACTOR=1.0 alacritty` every time the user wants to start alacritty. It would be possible to allow specifying any DPR, however I've decided against this since I'd assume it's a very rare usecase. It's also still possible to make use of `WINIT_HIDPI_FACTOR` to do this on X11. Currently this is not updated at runtime using the live config update, there is not really much of a technical limitation why this woudn't be possible, however a solution for that issue should be first added in jwilm/alacritty#1346, once a system is established for changing DPI at runtime, porting that functionality to this PR should be simple. * Add working --class and --title CLI parameters * Reduce Increase-/DecreaseFontSize step to 0.5 Until now the Increase-/DecreaseFontSize keybinds hand a step size of 1.0. Since the font size however is multiplied by two to allow more granular font size control, this lead to the bindings skipping one font size (incrementing/decrementing by +-2). To fix this the step size of the Increase-/DecreaseFontSize bindings has been reduced to the minimum step size that exists with the current font configuration (0.5). This should allow users to increment and decrement the font size by a single point instead of two. This also adds a few tests to make sure the methods for increasing/decreasing/resetting font size work properly. * Add Copy/Cut/Paste keys This just adds support for the Copy/Cut/Paste keys and sets up Copy/Paste as alternative defaults for Ctrl+Shift+C/V. * Move to cargo clippy Using clippy as a library has been deprecated, instead the `cargo clippy` command should be used instead. To comply with this change clippy has been removed from the `Cargo.toml` and is now installed with cargo when building in CI. This has also lead to a few new clippy issues to show up, this includes everything in the `font` subdirectory. This has been fixed and `font` should now be covered by clippy CI too. This also upgrades all dependencies, as a result this fixes #1341 and this fixes #1344. * Override dynamic_title when --title is specified * Change green implementation to use the macro * Ignore mouse input if window is unfocused * Make compilation of binary a phony target * Add opensuse zypper install method to readme * Fix clippy issues * Update manpage to document all CLI options The introduction of `--class` has added a flag to the CLI without adding it to the manpage. This has been fixed by updating the manpage. This also adds the default values of `--class` and `--title` to the CLI options. * Remove unnecessary clippy lint annotations We moved to "cargo clippy" in 5ba34d4f9766a55a06ed5e3e44cc384af1b09f65 and removing the clippy lint annotations in `src/lib.rs` does not cause any additional warnings. This also changes `cargo clippy` to use the flags required for checking integration tests. * Enable clippy in font/copypasta crates Enabled clippy in the sub-crates font and copypasta. All issues that were discovered by this change have also been fixed. * Remove outdated comment about NixOS * Replace debug asserts with static_assertions To check that transmutes will work correctly without having to rely on error-prone runtime checking, the `static_assertions` crate has been introduced. This allows comparing the size of types at compile time, preventing potentially silent breakage. This fixes #1417. * Add `cargo deb` build instructions Updated the `Cargo.toml` file and added a `package.metadata.deb` subsection to define how to build a debian "deb" install file using `cargo deb`. This will allow debian/ubuntu users to install `alacritty` using their system's package manager. It also will make it easier to provide pre-built binaries for those systems. Also fixed a stray debug line in the bash autocomplete script that was writting to a tempfile. * Add config for unfocused window cursor change * Add support for cursor shape escape sequence * Add bright foreground color option It was requested in jwilm/alacritty#825 that it should be possible to add an optional bright foreground color. This is now added to the primary colors structure and allows the user to set a foreground color for bold normal text. This has no effect unless the draw_bold_text_with_bright_colors option is also enabled. If the color is not specified, the bright foreground color will fall back to the normal foreground color. This fixes #825. * Fix clone URL in deb install instructions * Fix 'cargo-deb' desktop file name * Remove redundant dependency from deb build * Switch from deprecated `std::env::home_dir` to `dirs::home_dir` * Allow specifying modifiers for mouse bindings * Send newline with NumpadEnter * Add support for LCD-V pixel mode * Add binding action for hiding the window * Switch to rustup clippy component * Add optional dim foreground color Add optional color for the dim foreground (`\e[2m;`) Defaults to 2/3 of the foreground color. (same as other colors). If a bright color is dimmed, it's displayed as the normal color. The exception for this is when the bright foreground is dimmed when no bright foreground color is set. In that case it's treated as a normal foreground color and dimmed to DimForeground. To minimize the surprise for the user, the bright and dim colors have been completely removed from the default configuration file. Some documentation has also been added to make it clear to users what these options can be used for. This fixes #1448. * Fix clippy lints and run font tests on travis This fixes some existing clippy issues and runs the `font` tests through travis. Testing of copypasta crate was omitted due to problens when running on headless travis-ci environment (x11 clipboard would fail). * Ignore errors when logger can't write to output The (e)print macro will panic when there is no output available to write to, however in our scenario where we only log user errors to stderr, the better choice would be to ignore when writing to stdout or stderr is not possible. This changes the (e)print macro to make use of `write` and ignore any potential errors. Since (e)println rely on (e)print, this also solves potential failuers when calling (e)println. With this change implemented, all of logging, (e)println and (e)print should never fail even if the stdout/stderr is not available.
2018-07-28 23:10:13 +00:00
{
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);
Merge master into scrollback * Allow disabling DPI scaling This makes it possible to disable DPI scaling completely, instead the the display pixel ration will always be fixed to 1.0. By default nothing has changed and DPI is still enabled, this just seems like a better way than running `WINIT_HIDPI_FACTOR=1.0 alacritty` every time the user wants to start alacritty. It would be possible to allow specifying any DPR, however I've decided against this since I'd assume it's a very rare usecase. It's also still possible to make use of `WINIT_HIDPI_FACTOR` to do this on X11. Currently this is not updated at runtime using the live config update, there is not really much of a technical limitation why this woudn't be possible, however a solution for that issue should be first added in jwilm/alacritty#1346, once a system is established for changing DPI at runtime, porting that functionality to this PR should be simple. * Add working --class and --title CLI parameters * Reduce Increase-/DecreaseFontSize step to 0.5 Until now the Increase-/DecreaseFontSize keybinds hand a step size of 1.0. Since the font size however is multiplied by two to allow more granular font size control, this lead to the bindings skipping one font size (incrementing/decrementing by +-2). To fix this the step size of the Increase-/DecreaseFontSize bindings has been reduced to the minimum step size that exists with the current font configuration (0.5). This should allow users to increment and decrement the font size by a single point instead of two. This also adds a few tests to make sure the methods for increasing/decreasing/resetting font size work properly. * Add Copy/Cut/Paste keys This just adds support for the Copy/Cut/Paste keys and sets up Copy/Paste as alternative defaults for Ctrl+Shift+C/V. * Move to cargo clippy Using clippy as a library has been deprecated, instead the `cargo clippy` command should be used instead. To comply with this change clippy has been removed from the `Cargo.toml` and is now installed with cargo when building in CI. This has also lead to a few new clippy issues to show up, this includes everything in the `font` subdirectory. This has been fixed and `font` should now be covered by clippy CI too. This also upgrades all dependencies, as a result this fixes #1341 and this fixes #1344. * Override dynamic_title when --title is specified * Change green implementation to use the macro * Ignore mouse input if window is unfocused * Make compilation of binary a phony target * Add opensuse zypper install method to readme * Fix clippy issues * Update manpage to document all CLI options The introduction of `--class` has added a flag to the CLI without adding it to the manpage. This has been fixed by updating the manpage. This also adds the default values of `--class` and `--title` to the CLI options. * Remove unnecessary clippy lint annotations We moved to "cargo clippy" in 5ba34d4f9766a55a06ed5e3e44cc384af1b09f65 and removing the clippy lint annotations in `src/lib.rs` does not cause any additional warnings. This also changes `cargo clippy` to use the flags required for checking integration tests. * Enable clippy in font/copypasta crates Enabled clippy in the sub-crates font and copypasta. All issues that were discovered by this change have also been fixed. * Remove outdated comment about NixOS * Replace debug asserts with static_assertions To check that transmutes will work correctly without having to rely on error-prone runtime checking, the `static_assertions` crate has been introduced. This allows comparing the size of types at compile time, preventing potentially silent breakage. This fixes #1417. * Add `cargo deb` build instructions Updated the `Cargo.toml` file and added a `package.metadata.deb` subsection to define how to build a debian "deb" install file using `cargo deb`. This will allow debian/ubuntu users to install `alacritty` using their system's package manager. It also will make it easier to provide pre-built binaries for those systems. Also fixed a stray debug line in the bash autocomplete script that was writting to a tempfile. * Add config for unfocused window cursor change * Add support for cursor shape escape sequence * Add bright foreground color option It was requested in jwilm/alacritty#825 that it should be possible to add an optional bright foreground color. This is now added to the primary colors structure and allows the user to set a foreground color for bold normal text. This has no effect unless the draw_bold_text_with_bright_colors option is also enabled. If the color is not specified, the bright foreground color will fall back to the normal foreground color. This fixes #825. * Fix clone URL in deb install instructions * Fix 'cargo-deb' desktop file name * Remove redundant dependency from deb build * Switch from deprecated `std::env::home_dir` to `dirs::home_dir` * Allow specifying modifiers for mouse bindings * Send newline with NumpadEnter * Add support for LCD-V pixel mode * Add binding action for hiding the window * Switch to rustup clippy component * Add optional dim foreground color Add optional color for the dim foreground (`\e[2m;`) Defaults to 2/3 of the foreground color. (same as other colors). If a bright color is dimmed, it's displayed as the normal color. The exception for this is when the bright foreground is dimmed when no bright foreground color is set. In that case it's treated as a normal foreground color and dimmed to DimForeground. To minimize the surprise for the user, the bright and dim colors have been completely removed from the default configuration file. Some documentation has also been added to make it clear to users what these options can be used for. This fixes #1448. * Fix clippy lints and run font tests on travis This fixes some existing clippy issues and runs the `font` tests through travis. Testing of copypasta crate was omitted due to problens when running on headless travis-ci environment (x11 clipboard would fail). * Ignore errors when logger can't write to output The (e)print macro will panic when there is no output available to write to, however in our scenario where we only log user errors to stderr, the better choice would be to ignore when writing to stdout or stderr is not possible. This changes the (e)print macro to make use of `write` and ignore any potential errors. Since (e)println rely on (e)print, this also solves potential failuers when calling (e)println. With this change implemented, all of logging, (e)println and (e)print should never fail even if the stdout/stderr is not available.
2018-07-28 23:10:13 +00:00
Ok(None)
},
}
}
fn default_background() -> Rgb {
Rgb { r: 0, g: 0, b: 0 }
}
fn default_foreground() -> Rgb {
Rgb { r: 0xea, g: 0xea, b: 0xea }
}
/// The 8-colors sections of config
#[derive(Debug, Deserialize, PartialEq, Eq)]
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.
2017-08-30 18:17:27 +00:00
fn rgb_from_hex<'a, D>(deserializer: D) -> ::std::result::Result<Rgb, D::Error>
2019-03-30 16:48:36 +00:00
where
D: de::Deserializer<'a>,
{
struct RgbVisitor;
2017-08-30 18:17:27 +00:00
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>
2019-03-30 16:48:36 +00:00
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 })
},
}
}
2017-01-07 04:44:51 +00:00
impl FromStr for Rgb {
type Err = ();
2019-03-30 16:48:36 +00:00
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() {
2019-03-30 16:48:36 +00:00
Some('0') => {
if chars.next() != Some('x') {
return Err(());
}
},
Some('#') => (),
2017-06-12 10:16:57 +00:00
_ => 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 {
2019-03-30 16:48:36 +00:00
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(|| {
2019-03-30 16:48:36 +00:00
::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(Into::into)
}
// TODO: Remove old configuration location warning (Deprecated 03/12/2018)
#[cfg(windows)]
pub fn installed_config<'a>() -> Option<Cow<'a, Path>> {
2019-03-30 16:48:36 +00:00
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()))
2017-01-06 04:56:05 +00:00
.and_then(|p| p.place_config_file("alacritty.yml"))?;
2017-01-06 04:56:05 +00:00
File::create(&path)?.write_all(DEFAULT_ALACRITTY_CONFIG.as_bytes())?;
Ok(path.into())
2017-01-06 04:56:05 +00:00
}
#[cfg(windows)]
pub fn write_defaults() -> io::Result<Cow<'static, Path>> {
2019-03-30 16:48:36 +00:00
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");
std::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> {
2019-03-30 16:48:36 +00:00
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
}
#[cfg(target_os = "macos")]
#[inline]
pub fn use_thin_strokes(&self) -> bool {
self.font.use_thin_strokes
}
#[cfg(not(target_os = "macos"))]
#[inline]
pub fn use_thin_strokes(&self) -> bool {
false
}
pub fn path(&self) -> Option<&Path> {
2019-03-30 16:48:36 +00:00
self.config_path.as_ref().map(PathBuf::as_path)
}
pub fn shell(&self) -> Option<&Shell<'_>> {
self.shell.as_ref()
}
2017-02-14 02:22:59 +00:00
pub fn env(&self) -> &HashMap<String, String> {
&self.env
}
/// Should hide mouse cursor when typing
2017-02-22 19:52:37 +00:00
#[inline]
pub fn hide_mouse_when_typing(&self) -> bool {
self.hide_cursor_when_typing.unwrap_or(self.mouse.hide_when_typing)
2017-02-22 19:52:37 +00:00
}
/// Style of the cursor
#[inline]
pub fn cursor_style(&self) -> CursorStyle {
self.cursor_style.unwrap_or(self.cursor.style)
}
Merge master into scrollback * Allow disabling DPI scaling This makes it possible to disable DPI scaling completely, instead the the display pixel ration will always be fixed to 1.0. By default nothing has changed and DPI is still enabled, this just seems like a better way than running `WINIT_HIDPI_FACTOR=1.0 alacritty` every time the user wants to start alacritty. It would be possible to allow specifying any DPR, however I've decided against this since I'd assume it's a very rare usecase. It's also still possible to make use of `WINIT_HIDPI_FACTOR` to do this on X11. Currently this is not updated at runtime using the live config update, there is not really much of a technical limitation why this woudn't be possible, however a solution for that issue should be first added in jwilm/alacritty#1346, once a system is established for changing DPI at runtime, porting that functionality to this PR should be simple. * Add working --class and --title CLI parameters * Reduce Increase-/DecreaseFontSize step to 0.5 Until now the Increase-/DecreaseFontSize keybinds hand a step size of 1.0. Since the font size however is multiplied by two to allow more granular font size control, this lead to the bindings skipping one font size (incrementing/decrementing by +-2). To fix this the step size of the Increase-/DecreaseFontSize bindings has been reduced to the minimum step size that exists with the current font configuration (0.5). This should allow users to increment and decrement the font size by a single point instead of two. This also adds a few tests to make sure the methods for increasing/decreasing/resetting font size work properly. * Add Copy/Cut/Paste keys This just adds support for the Copy/Cut/Paste keys and sets up Copy/Paste as alternative defaults for Ctrl+Shift+C/V. * Move to cargo clippy Using clippy as a library has been deprecated, instead the `cargo clippy` command should be used instead. To comply with this change clippy has been removed from the `Cargo.toml` and is now installed with cargo when building in CI. This has also lead to a few new clippy issues to show up, this includes everything in the `font` subdirectory. This has been fixed and `font` should now be covered by clippy CI too. This also upgrades all dependencies, as a result this fixes #1341 and this fixes #1344. * Override dynamic_title when --title is specified * Change green implementation to use the macro * Ignore mouse input if window is unfocused * Make compilation of binary a phony target * Add opensuse zypper install method to readme * Fix clippy issues * Update manpage to document all CLI options The introduction of `--class` has added a flag to the CLI without adding it to the manpage. This has been fixed by updating the manpage. This also adds the default values of `--class` and `--title` to the CLI options. * Remove unnecessary clippy lint annotations We moved to "cargo clippy" in 5ba34d4f9766a55a06ed5e3e44cc384af1b09f65 and removing the clippy lint annotations in `src/lib.rs` does not cause any additional warnings. This also changes `cargo clippy` to use the flags required for checking integration tests. * Enable clippy in font/copypasta crates Enabled clippy in the sub-crates font and copypasta. All issues that were discovered by this change have also been fixed. * Remove outdated comment about NixOS * Replace debug asserts with static_assertions To check that transmutes will work correctly without having to rely on error-prone runtime checking, the `static_assertions` crate has been introduced. This allows comparing the size of types at compile time, preventing potentially silent breakage. This fixes #1417. * Add `cargo deb` build instructions Updated the `Cargo.toml` file and added a `package.metadata.deb` subsection to define how to build a debian "deb" install file using `cargo deb`. This will allow debian/ubuntu users to install `alacritty` using their system's package manager. It also will make it easier to provide pre-built binaries for those systems. Also fixed a stray debug line in the bash autocomplete script that was writting to a tempfile. * Add config for unfocused window cursor change * Add support for cursor shape escape sequence * Add bright foreground color option It was requested in jwilm/alacritty#825 that it should be possible to add an optional bright foreground color. This is now added to the primary colors structure and allows the user to set a foreground color for bold normal text. This has no effect unless the draw_bold_text_with_bright_colors option is also enabled. If the color is not specified, the bright foreground color will fall back to the normal foreground color. This fixes #825. * Fix clone URL in deb install instructions * Fix 'cargo-deb' desktop file name * Remove redundant dependency from deb build * Switch from deprecated `std::env::home_dir` to `dirs::home_dir` * Allow specifying modifiers for mouse bindings * Send newline with NumpadEnter * Add support for LCD-V pixel mode * Add binding action for hiding the window * Switch to rustup clippy component * Add optional dim foreground color Add optional color for the dim foreground (`\e[2m;`) Defaults to 2/3 of the foreground color. (same as other colors). If a bright color is dimmed, it's displayed as the normal color. The exception for this is when the bright foreground is dimmed when no bright foreground color is set. In that case it's treated as a normal foreground color and dimmed to DimForeground. To minimize the surprise for the user, the bright and dim colors have been completely removed from the default configuration file. Some documentation has also been added to make it clear to users what these options can be used for. This fixes #1448. * Fix clippy lints and run font tests on travis This fixes some existing clippy issues and runs the `font` tests through travis. Testing of copypasta crate was omitted due to problens when running on headless travis-ci environment (x11 clipboard would fail). * Ignore errors when logger can't write to output The (e)print macro will panic when there is no output available to write to, however in our scenario where we only log user errors to stderr, the better choice would be to ignore when writing to stdout or stderr is not possible. This changes the (e)print macro to make use of `write` and ignore any potential errors. Since (e)println rely on (e)print, this also solves potential failuers when calling (e)println. With this change implemented, all of logging, (e)println and (e)print should never fail even if the stdout/stderr is not available.
2018-07-28 23:10:13 +00:00
/// Use hollow block cursor when unfocused
#[inline]
pub fn unfocused_hollow_cursor(&self) -> bool {
self.unfocused_hollow_cursor.unwrap_or(self.cursor.unfocused_hollow)
Merge master into scrollback * Allow disabling DPI scaling This makes it possible to disable DPI scaling completely, instead the the display pixel ration will always be fixed to 1.0. By default nothing has changed and DPI is still enabled, this just seems like a better way than running `WINIT_HIDPI_FACTOR=1.0 alacritty` every time the user wants to start alacritty. It would be possible to allow specifying any DPR, however I've decided against this since I'd assume it's a very rare usecase. It's also still possible to make use of `WINIT_HIDPI_FACTOR` to do this on X11. Currently this is not updated at runtime using the live config update, there is not really much of a technical limitation why this woudn't be possible, however a solution for that issue should be first added in jwilm/alacritty#1346, once a system is established for changing DPI at runtime, porting that functionality to this PR should be simple. * Add working --class and --title CLI parameters * Reduce Increase-/DecreaseFontSize step to 0.5 Until now the Increase-/DecreaseFontSize keybinds hand a step size of 1.0. Since the font size however is multiplied by two to allow more granular font size control, this lead to the bindings skipping one font size (incrementing/decrementing by +-2). To fix this the step size of the Increase-/DecreaseFontSize bindings has been reduced to the minimum step size that exists with the current font configuration (0.5). This should allow users to increment and decrement the font size by a single point instead of two. This also adds a few tests to make sure the methods for increasing/decreasing/resetting font size work properly. * Add Copy/Cut/Paste keys This just adds support for the Copy/Cut/Paste keys and sets up Copy/Paste as alternative defaults for Ctrl+Shift+C/V. * Move to cargo clippy Using clippy as a library has been deprecated, instead the `cargo clippy` command should be used instead. To comply with this change clippy has been removed from the `Cargo.toml` and is now installed with cargo when building in CI. This has also lead to a few new clippy issues to show up, this includes everything in the `font` subdirectory. This has been fixed and `font` should now be covered by clippy CI too. This also upgrades all dependencies, as a result this fixes #1341 and this fixes #1344. * Override dynamic_title when --title is specified * Change green implementation to use the macro * Ignore mouse input if window is unfocused * Make compilation of binary a phony target * Add opensuse zypper install method to readme * Fix clippy issues * Update manpage to document all CLI options The introduction of `--class` has added a flag to the CLI without adding it to the manpage. This has been fixed by updating the manpage. This also adds the default values of `--class` and `--title` to the CLI options. * Remove unnecessary clippy lint annotations We moved to "cargo clippy" in 5ba34d4f9766a55a06ed5e3e44cc384af1b09f65 and removing the clippy lint annotations in `src/lib.rs` does not cause any additional warnings. This also changes `cargo clippy` to use the flags required for checking integration tests. * Enable clippy in font/copypasta crates Enabled clippy in the sub-crates font and copypasta. All issues that were discovered by this change have also been fixed. * Remove outdated comment about NixOS * Replace debug asserts with static_assertions To check that transmutes will work correctly without having to rely on error-prone runtime checking, the `static_assertions` crate has been introduced. This allows comparing the size of types at compile time, preventing potentially silent breakage. This fixes #1417. * Add `cargo deb` build instructions Updated the `Cargo.toml` file and added a `package.metadata.deb` subsection to define how to build a debian "deb" install file using `cargo deb`. This will allow debian/ubuntu users to install `alacritty` using their system's package manager. It also will make it easier to provide pre-built binaries for those systems. Also fixed a stray debug line in the bash autocomplete script that was writting to a tempfile. * Add config for unfocused window cursor change * Add support for cursor shape escape sequence * Add bright foreground color option It was requested in jwilm/alacritty#825 that it should be possible to add an optional bright foreground color. This is now added to the primary colors structure and allows the user to set a foreground color for bold normal text. This has no effect unless the draw_bold_text_with_bright_colors option is also enabled. If the color is not specified, the bright foreground color will fall back to the normal foreground color. This fixes #825. * Fix clone URL in deb install instructions * Fix 'cargo-deb' desktop file name * Remove redundant dependency from deb build * Switch from deprecated `std::env::home_dir` to `dirs::home_dir` * Allow specifying modifiers for mouse bindings * Send newline with NumpadEnter * Add support for LCD-V pixel mode * Add binding action for hiding the window * Switch to rustup clippy component * Add optional dim foreground color Add optional color for the dim foreground (`\e[2m;`) Defaults to 2/3 of the foreground color. (same as other colors). If a bright color is dimmed, it's displayed as the normal color. The exception for this is when the bright foreground is dimmed when no bright foreground color is set. In that case it's treated as a normal foreground color and dimmed to DimForeground. To minimize the surprise for the user, the bright and dim colors have been completely removed from the default configuration file. Some documentation has also been added to make it clear to users what these options can be used for. This fixes #1448. * Fix clippy lints and run font tests on travis This fixes some existing clippy issues and runs the `font` tests through travis. Testing of copypasta crate was omitted due to problens when running on headless travis-ci environment (x11 clipboard would fail). * Ignore errors when logger can't write to output The (e)print macro will panic when there is no output available to write to, however in our scenario where we only log user errors to stderr, the better choice would be to ignore when writing to stdout or stderr is not possible. This changes the (e)print macro to make use of `write` and ignore any potential errors. Since (e)println rely on (e)print, this also solves potential failuers when calling (e)println. With this change implemented, all of logging, (e)println and (e)print should never fail even if the stdout/stderr is not available.
2018-07-28 23:10:13 +00:00
}
/// 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<Rgb> {
self.colors.cursor.text
}
/// Cursor background color
#[inline]
pub fn cursor_cursor_color(&self) -> Option<Rgb> {
self.colors.cursor.cursor
}
2018-12-28 16:01:58 +00:00
/// Enable experimental conpty backend (Windows only)
#[cfg(windows)]
#[inline]
pub fn enable_experimental_conpty_backend(&self) -> bool {
self.enable_experimental_conpty_backend
}
/// Send escape sequences using the alt key
#[inline]
pub fn alt_send_esc(&self) -> bool {
self.alt_send_esc
}
// Update the history size, used in ref tests
pub fn set_history(&mut self, history: u32) {
self.scrolling.history = history;
}
Display errors and warnings To make sure that all error and information reporting to the user is unified, all instances of `print!`, `eprint!`, `println!` and `eprintln!` have been removed and replaced by logging. When `RUST_LOG` is not specified, the default Alacritty logger now also prints to both the stderr and a log file. The log file is only created when a message is written to it and its name is printed to stdout the first time it is used. Whenever a warning or an error has been written to the log file/stderr, a message is now displayed in Alacritty which points to the log file where the full error is documented. The message is cleared whenever the screen is cleared using either the `clear` command or the `Ctrl+L` key binding. To make sure that log files created by root don't prevent normal users from interacting with them, the Alacritty log file is `/tmp/Alacritty-$PID.log`. Since it's still possible that the log file can't be created, the UI error/warning message now informs the user if the message was only written to stderr. The reason why it couldn't be created is then printed to stderr. To make sure the deletion of the log file at runtime doesn't create any issues, the file is re-created if a write is attempted without the file being present. To help with debugging Alacritty issues, a timestamp and the error level are printed in all log messages. All log messages now follow this format: [YYYY-MM-DD HH:MM] [LEVEL] Message Since it's not unusual to spawn a lot of different terminal emulators without restarting, Alacritty can create a ton of different log files. To combat this problem, logfiles are removed by default after Alacritty has been closed. If the user wants to persist the log of a single session, the `--persistent_logging` option can be used. For persisting all log files, the `persistent_logging` option can be set in the configuration file
2018-11-17 14:39:13 +00:00
/// Keep the log file after quitting Alacritty
#[inline]
pub fn persistent_logging(&self) -> bool {
self.persistent_logging
}
/// 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
}
pub fn load_from(path: PathBuf) -> Config {
let mut config = Config::reload_from(&path).unwrap_or_else(|_| Config::default());
config.config_path = Some(path);
config
}
pub fn reload_from(path: &PathBuf) -> Result<Config> {
match Config::read_config(path) {
Ok(config) => Ok(config),
Err(err) => {
error!("Unable to load config {:?}: {}", path, err);
Err(err)
2019-03-30 16:48:36 +00:00
},
}
}
fn read_config(path: &PathBuf) -> Result<Config> {
let mut contents = String::new();
File::open(path)?.read_to_string(&mut contents)?;
// Prevent parsing error with empty string
if contents.is_empty() {
return Ok(Config::default());
}
let mut config: Config = serde_yaml::from_str(&contents)?;
config.print_deprecation_warnings();
Ok(config)
}
fn print_deprecation_warnings(&mut self) {
if self.dimensions.is_some() {
2019-03-30 16:48:36 +00:00
warn!("Config dimensions is deprecated; please use window.dimensions instead");
}
if self.padding.is_some() {
2019-03-30 16:48:36 +00:00
warn!("Config padding is deprecated; please use window.padding instead");
}
if self.mouse.faux_scrollback_lines.is_some() {
2019-03-30 16:48:36 +00:00
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() {
2019-03-30 16:48:36 +00:00
warn!("Config cursor_style is deprecated; please use cursor.style instead");
}
if self.hide_cursor_when_typing.is_some() {
2019-03-30 16:48:36 +00:00
warn!(
"Config hide_cursor_when_typing is deprecated; please use mouse.hide_when_typing \
instead"
);
}
if self.unfocused_hollow_cursor.is_some() {
2019-03-30 16:48:36 +00:00
warn!(
"Config unfocused_hollow_cursor is deprecated; please use cursor.unfocused_hollow \
instead"
);
}
if let Some(start_maximized) = self.window.start_maximized {
warn!(
"Config window.start_maximized is deprecated; please use window.startup_mode \
instead"
);
// While `start_maximized` is deprecated its setting takes precedence.
if start_maximized {
self.window.startup_mode = StartupMode::Maximized;
}
}
}
}
/// 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 {
2019-03-30 16:48:36 +00:00
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
#[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,
}
2019-03-30 16:48:36 +00:00
trait DeserializeSize: Sized {
fn deserialize<'a, D>(_: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: serde::de::Deserializer<'a>;
}
impl DeserializeSize for Size {
fn deserialize<'a, D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
2019-03-30 16:48:36 +00:00
where
D: serde::de::Deserializer<'a>,
{
use std::marker::PhantomData;
struct NumVisitor<__D> {
_marker: PhantomData<__D>,
}
impl<'a, __D> Visitor<'a> for NumVisitor<__D>
2019-03-30 16:48:36 +00:00
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>
2019-03-30 16:48:36 +00:00
where
E: ::serde::de::Error,
{
Ok(value)
}
fn visit_u64<E>(self, value: u64) -> ::std::result::Result<Self::Value, E>
2019-03-30 16:48:36 +00:00
where
E: ::serde::de::Error,
{
Ok(value as f64)
}
}
let size = deserializer
2019-03-30 16:48:36 +00:00
.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!("Problem with config: {}; using size {}", err, size.as_f32_pts());
Ok(size)
},
}
}
}
/// 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")]
italic: SecondaryFontDescription,
/// Italic font face
#[serde(deserialize_with = "failure_default")]
bold: SecondaryFontDescription,
/// Font size in points
#[serde(deserialize_with = "DeserializeSize::deserialize")]
pub size: Size,
/// Extra spacing per character
#[serde(deserialize_with = "failure_default")]
offset: Delta<i8>,
/// Glyph offset within character cell
#[serde(deserialize_with = "failure_default")]
glyph_offset: Delta<i8>,
#[cfg(target_os = "macos")]
#[serde(deserialize_with = "deserialize_true_bool")]
use_thin_strokes: bool,
Upgrade Glutin to v0.19.0 Some changes include: • Use the with_hardware_acceleration function on the ContextBuilder to not require the discrete GPU • Remove the LMenu and RMenu virtual key codes (winit 0.16.0 removed these because Windows now generates LAlt and RAlt instead • Replace set_cursor_state with hide_cursor (winit 0.16.0 removed the set_cursor_state function) • Replace GlWindow::hidpi_factor with GlWindow::get_hidpi_factor and change to expecting an f64 • Use the glutin/winit dpi size and position types where possible Glutin's dpi change event has been implemented. All size events now return logical sizes. As a result of that, the logical sizes are translated in the `display::handle_rezize` method so DPI scaling works correctly. When the DPI is changed, the glyph cache is updated to make use of the correct font size again. Moving a window to a different screen which is a different DPI caused a racing condition where the logical size of the event was sent to the `handle_resize` method in `src/display.rs`, however if there was a DPI change event before `handle_resize` is able to process this message, it would incorrectly use the new DPI to scale the resize event. To solve this issue instead of sending the logical size to the `handle_resize` method and then converting it to a physical size in there, the `LogicalSize` of the resize event is transformed into a `PhysicalSize` as soon as it's received. This fixes potential racing conditions since all events are processed in order. The padding has been changed so it's also scaled by DPR. The `scale_with_dpi` config option has been removed. If it's not present a warning will be emitted. The `winit` dependency on Windows has been removed. All interactions with winit in Alacritty are handled through glutin.
2018-11-10 16:08:48 +00:00
// TODO: Deprecated
#[serde(deserialize_with = "deserialize_scale_with_dpi")]
Upgrade Glutin to v0.19.0 Some changes include: • Use the with_hardware_acceleration function on the ContextBuilder to not require the discrete GPU • Remove the LMenu and RMenu virtual key codes (winit 0.16.0 removed these because Windows now generates LAlt and RAlt instead • Replace set_cursor_state with hide_cursor (winit 0.16.0 removed the set_cursor_state function) • Replace GlWindow::hidpi_factor with GlWindow::get_hidpi_factor and change to expecting an f64 • Use the glutin/winit dpi size and position types where possible Glutin's dpi change event has been implemented. All size events now return logical sizes. As a result of that, the logical sizes are translated in the `display::handle_rezize` method so DPI scaling works correctly. When the DPI is changed, the glyph cache is updated to make use of the correct font size again. Moving a window to a different screen which is a different DPI caused a racing condition where the logical size of the event was sent to the `handle_resize` method in `src/display.rs`, however if there was a DPI change event before `handle_resize` is able to process this message, it would incorrectly use the new DPI to scale the resize event. To solve this issue instead of sending the logical size to the `handle_resize` method and then converting it to a physical size in there, the `LogicalSize` of the resize event is transformed into a `PhysicalSize` as soon as it's received. This fixes potential racing conditions since all events are processed in order. The padding has been changed so it's also scaled by DPR. The `scale_with_dpi` config option has been removed. If it's not present a warning will be emitted. The `winit` dependency on Windows has been removed. All interactions with winit in Alacritty are handled through glutin.
2018-11-10 16:08:48 +00:00
scale_with_dpi: Option<()>,
}
impl Default for Font {
fn default() -> Font {
Font {
#[cfg(target_os = "macos")]
use_thin_strokes: true,
size: default_font_size(),
normal: Default::default(),
bold: Default::default(),
italic: Default::default(),
scale_with_dpi: Default::default(),
glyph_offset: Default::default(),
offset: Default::default(),
}
}
}
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 {
2019-03-30 16:48:36 +00:00
Font { size, ..self }
}
// Get normal font description
pub fn normal(&self) -> &FontDescription {
&self.normal
}
// Get italic font description
pub fn italic(&self) -> FontDescription {
self.italic.desc(&self.normal)
}
// Get bold font description
pub fn bold(&self) -> FontDescription {
self.bold.desc(&self.normal)
}
}
fn default_font_size() -> Size {
Size::new(11.)
}
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);
2019-03-30 16:48:36 +00:00
error!(
"The scale_with_dpi setting has been removed, on X11 the WINIT_HIDPI_FACTOR environment \
variable can be used instead."
);
Ok(None)
}
/// 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(),
}
}
}
pub struct Monitor {
_thread: ::std::thread::JoinHandle<()>,
rx: mpsc::Receiver<PathBuf>,
}
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(&self) -> Option<PathBuf> {
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
2019-03-30 16:48:36 +00:00
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.
2019-03-30 16:48:36 +00:00
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
2019-03-30 16:48:36 +00:00
watcher
.watch(&parent, RecursiveMode::NonRecursive)
.expect("watch alacritty.yml dir");
loop {
match rx.recv().expect("watcher event") {
2019-03-30 16:48:36 +00:00
DebouncedEvent::Rename(..) => continue,
DebouncedEvent::Write(path)
2019-03-30 16:48:36 +00:00
| DebouncedEvent::Create(path)
| DebouncedEvent::Chmod(path) => {
if path != config_path {
continue;
}
let _ = config_tx.send(path);
handler.on_config_reload();
2019-03-30 16:48:36 +00:00
},
_ => {},
}
}
}),
rx: config_rx,
}
}
}
#[derive(Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
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,
Upgrade Glutin to v0.19.0 Some changes include: • Use the with_hardware_acceleration function on the ContextBuilder to not require the discrete GPU • Remove the LMenu and RMenu virtual key codes (winit 0.16.0 removed these because Windows now generates LAlt and RAlt instead • Replace set_cursor_state with hide_cursor (winit 0.16.0 removed the set_cursor_state function) • Replace GlWindow::hidpi_factor with GlWindow::get_hidpi_factor and change to expecting an f64 • Use the glutin/winit dpi size and position types where possible Glutin's dpi change event has been implemented. All size events now return logical sizes. As a result of that, the logical sizes are translated in the `display::handle_rezize` method so DPI scaling works correctly. When the DPI is changed, the glyph cache is updated to make use of the correct font size again. Moving a window to a different screen which is a different DPI caused a racing condition where the logical size of the event was sent to the `handle_resize` method in `src/display.rs`, however if there was a DPI change event before `handle_resize` is able to process this message, it would incorrectly use the new DPI to scale the resize event. To solve this issue instead of sending the logical size to the `handle_resize` method and then converting it to a physical size in there, the `LogicalSize` of the resize event is transformed into a `PhysicalSize` as soon as it's received. This fixes potential racing conditions since all events are processed in order. The padding has been changed so it's also scaled by DPR. The `scale_with_dpi` config option has been removed. If it's not present a warning will be emitted. The `winit` dependency on Windows has been removed. All interactions with winit in Alacritty are handled through glutin.
2018-11-10 16:08:48 +00:00
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,
2018-01-04 06:58:19 +00:00
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,
Upgrade Glutin to v0.19.0 Some changes include: • Use the with_hardware_acceleration function on the ContextBuilder to not require the discrete GPU • Remove the LMenu and RMenu virtual key codes (winit 0.16.0 removed these because Windows now generates LAlt and RAlt instead • Replace set_cursor_state with hide_cursor (winit 0.16.0 removed the set_cursor_state function) • Replace GlWindow::hidpi_factor with GlWindow::get_hidpi_factor and change to expecting an f64 • Use the glutin/winit dpi size and position types where possible Glutin's dpi change event has been implemented. All size events now return logical sizes. As a result of that, the logical sizes are translated in the `display::handle_rezize` method so DPI scaling works correctly. When the DPI is changed, the glyph cache is updated to make use of the correct font size again. Moving a window to a different screen which is a different DPI caused a racing condition where the logical size of the event was sent to the `handle_resize` method in `src/display.rs`, however if there was a DPI change event before `handle_resize` is able to process this message, it would incorrectly use the new DPI to scale the resize event. To solve this issue instead of sending the logical size to the `handle_resize` method and then converting it to a physical size in there, the `LogicalSize` of the resize event is transformed into a `PhysicalSize` as soon as it's received. This fixes potential racing conditions since all events are processed in order. The padding has been changed so it's also scaled by DPR. The `scale_with_dpi` config option has been removed. If it's not present a warning will be emitted. The `winit` dependency on Windows has been removed. All interactions with winit in Alacritty are handled through glutin.
2018-11-10 16:08:48 +00:00
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,
}
}
}
#[cfg(test)]
mod tests {
use super::{Config, DEFAULT_ALACRITTY_CONFIG};
use crate::config::Options;
#[test]
fn parse_config() {
2019-03-30 16:48:36 +00:00
let config: Config =
::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).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() {
2019-03-30 16:48:36 +00:00
let config: Config =
::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).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() {
2019-03-30 16:48:36 +00:00
let config: Config =
::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).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);
}
#[test]
fn default_match_empty() {
let default = Config::default();
let empty = serde_yaml::from_str("key: val\n").unwrap();
assert_eq!(default, empty);
}
}