aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/config.rs328
-rw-r--r--src/main.rs12
-rw-r--r--src/term/mod.rs11
3 files changed, 236 insertions, 115 deletions
diff --git a/src/config.rs b/src/config.rs
index 2a2ba6db..d9724e61 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -53,20 +53,37 @@ pub struct ClickHandler {
pub threshold: Duration,
}
+impl Default for ClickHandler {
+ fn default() -> Self {
+ ClickHandler { threshold: default_threshold_ms() }
+ }
+}
+
+fn default_threshold_ms() -> Duration {
+ Duration::from_millis(300)
+}
+
fn deserialize_duration_ms<'a, D>(deserializer: D) -> ::std::result::Result<Duration, D::Error>
where D: de::Deserializer<'a>
{
- let threshold_ms = u64::deserialize(deserializer)?;
- Ok(Duration::from_millis(threshold_ms))
+ match u64::deserialize(deserializer) {
+ Ok(threshold_ms) => Ok(Duration::from_millis(threshold_ms)),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using default value", err);
+ Ok(default_threshold_ms())
+ },
+ }
}
-
#[derive(Clone, Debug, Deserialize)]
pub struct Mouse {
+ #[serde(default, deserialize_with = "failure_default")]
pub double_click: ClickHandler,
+ #[serde(default, deserialize_with = "failure_default")]
pub triple_click: ClickHandler,
/// up/down arrows sent when scrolling in alt screen buffer
+ #[serde(deserialize_with = "deserialize_faux_scrollback_lines")]
#[serde(default="default_faux_scrollback_lines")]
pub faux_scrollback_lines: usize,
}
@@ -75,6 +92,18 @@ fn default_faux_scrollback_lines() -> usize {
1
}
+fn deserialize_faux_scrollback_lines<'a, D>(deserializer: D) -> ::std::result::Result<usize, D::Error>
+ where D: de::Deserializer<'a>
+{
+ match usize::deserialize(deserializer) {
+ Ok(lines) => Ok(lines),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using default value", err);
+ Ok(default_faux_scrollback_lines())
+ },
+ }
+}
+
impl Default for Mouse {
fn default() -> Mouse {
Mouse {
@@ -105,25 +134,40 @@ pub enum VisualBellAnimation {
Linear,
}
+impl Default for VisualBellAnimation {
+ fn default() -> Self {
+ VisualBellAnimation::EaseOutExpo
+ }
+}
+
#[derive(Debug, Deserialize)]
pub struct VisualBellConfig {
/// Visual bell animation function
- #[serde(default="default_visual_bell_animation")]
+ #[serde(default, deserialize_with = "failure_default")]
animation: VisualBellAnimation,
/// Visual bell duration in milliseconds
+ #[serde(deserialize_with = "deserialize_visual_bell_duration")]
#[serde(default="default_visual_bell_duration")]
duration: u16,
}
-fn default_visual_bell_animation() -> VisualBellAnimation {
- VisualBellAnimation::EaseOutExpo
-}
-
fn default_visual_bell_duration() -> u16 {
150
}
+fn deserialize_visual_bell_duration<'a, D>(deserializer: D) -> ::std::result::Result<u16, D::Error>
+ where D: de::Deserializer<'a>
+{
+ match u16::deserialize(deserializer) {
+ Ok(duration) => Ok(duration),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using default value", err);
+ Ok(default_visual_bell_duration())
+ },
+ }
+}
+
impl VisualBellConfig {
/// Visual bell animation
#[inline]
@@ -141,7 +185,7 @@ impl VisualBellConfig {
impl Default for VisualBellConfig {
fn default() -> VisualBellConfig {
VisualBellConfig {
- animation: default_visual_bell_animation(),
+ animation: VisualBellAnimation::default(),
duration: default_visual_bell_duration(),
}
}
@@ -151,7 +195,7 @@ impl Default for VisualBellConfig {
pub struct Shell<'a> {
program: Cow<'a, str>,
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
args: Vec<String>,
}
@@ -221,18 +265,34 @@ impl Default for Alpha {
#[derive(Debug, Copy, Clone, Deserialize)]
pub struct WindowConfig {
/// Initial dimensions
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
dimensions: Dimensions,
/// Pixel padding
- #[serde(default="default_padding")]
+ #[serde(default="default_padding", deserialize_with = "deserialize_padding")]
padding: Delta,
/// Draw the window with title bar / borders
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
decorations: bool,
}
+fn default_padding() -> Delta {
+ Delta { x: 2., y: 2. }
+}
+
+fn deserialize_padding<'a, D>(deserializer: D) -> ::std::result::Result<Delta, D::Error>
+ where D: de::Deserializer<'a>
+{
+ match Delta::deserialize(deserializer) {
+ Ok(delta) => Ok(delta),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using default value", err);
+ Ok(default_padding())
+ },
+ }
+}
+
impl WindowConfig {
pub fn decorations(&self) -> bool {
self.decorations
@@ -253,141 +313,169 @@ impl Default for WindowConfig {
#[derive(Debug, Deserialize)]
pub struct Config {
/// Initial dimensions
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
dimensions: Option<Dimensions>,
/// Pixel padding
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
padding: Option<Delta>,
/// TERM env variable
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
env: HashMap<String, String>,
/// Font configuration
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
font: Font,
/// Should show render timer
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
render_timer: bool,
/// Should use custom cursor colors
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
custom_cursor_colors: bool,
/// Should draw bold text with brighter colors instead of bold font
- #[serde(default="true_bool")]
+ #[serde(default="true_bool", deserialize_with = "default_true_bool")]
draw_bold_text_with_bright_colors: bool,
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
colors: Colors,
/// Background opacity from 0.0 to 1.0
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
background_opacity: Alpha,
/// Window configuration
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
window: WindowConfig,
/// Keybindings
- #[serde(default="default_key_bindings")]
+ #[serde(default, deserialize_with = "failure_default_vec")]
key_bindings: Vec<KeyBinding>,
/// Bindings for the mouse
- #[serde(default="default_mouse_bindings")]
+ #[serde(default, deserialize_with = "failure_default_vec")]
mouse_bindings: Vec<MouseBinding>,
- #[serde(default="default_selection")]
+ #[serde(default, deserialize_with = "failure_default")]
selection: Selection,
- #[serde(default="default_mouse")]
+ #[serde(default, deserialize_with = "failure_default")]
mouse: Mouse,
/// Path to a shell program to run on startup
- #[serde(default)]
+ #[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)]
+ #[serde(default, deserialize_with = "failure_default")]
visual_bell: VisualBellConfig,
/// Use dynamic title
- #[serde(default="true_bool")]
+ #[serde(default="true_bool", deserialize_with = "default_true_bool")]
dynamic_title: bool,
/// Hide cursor when typing
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
hide_cursor_when_typing: bool,
/// Style of the cursor
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
cursor_style: CursorStyle,
/// Live config reload
- #[serde(default="true_bool")]
+ #[serde(default="true_bool", deserialize_with = "default_true_bool")]
live_config_reload: bool,
-}
-fn default_padding() -> Delta {
- Delta { x: 2., y: 2. }
+ /// Number of spaces in one tab
+ #[serde(default="default_tabspaces", deserialize_with = "deserialize_tabspaces")]
+ tabspaces: usize,
}
-#[cfg(not(target_os="macos"))]
-static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty.yml");
-#[cfg(target_os="macos")]
-static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty_macos.yml");
+fn failure_default_vec<'a, D, T>(deserializer: D) -> ::std::result::Result<Vec<T>, D::Error>
+ where D: de::Deserializer<'a>,
+ T: Deserialize<'a>
+{
+ // Deserialize as generic vector
+ let vec = match Vec::<serde_yaml::Value>::deserialize(deserializer) {
+ Ok(vec) => vec,
+ Err(err) => {
+ eprintln!("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) => {
+ eprintln!("problem with config: {}; Skipping value", err);
+ },
+ }
+ }
-fn default_config() -> Config {
- serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG)
- .expect("default config is valid")
+ Ok(bindings)
}
-fn default_selection() -> Selection {
- default_config().selection
+fn default_tabspaces() -> usize {
+ 8
}
-fn default_key_bindings() -> Vec<KeyBinding> {
- default_config().key_bindings
+fn deserialize_tabspaces<'a, D>(deserializer: D) -> ::std::result::Result<usize, D::Error>
+ where D: de::Deserializer<'a>
+{
+ match usize::deserialize(deserializer) {
+ Ok(value) => Ok(value),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using `8`", err);
+ Ok(default_tabspaces())
+ },
+ }
}
-fn default_mouse_bindings() -> Vec<MouseBinding> {
- default_config().mouse_bindings
+fn default_true_bool<'a, D>(deserializer: D) -> ::std::result::Result<bool, D::Error>
+ where D: de::Deserializer<'a>
+{
+ match bool::deserialize(deserializer) {
+ Ok(value) => Ok(value),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using `true`", err);
+ Ok(true)
+ },
+ }
}
-fn default_mouse() -> Mouse {
- default_config().mouse
+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) => {
+ eprintln!("problem with config: {}; Using default value", err);
+ Ok(T::default())
+ },
+ }
}
+#[cfg(not(target_os="macos"))]
+static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty.yml");
+#[cfg(target_os="macos")]
+static DEFAULT_ALACRITTY_CONFIG: &'static str = include_str!("../alacritty_macos.yml");
+
impl Default for Config {
- fn default() -> Config {
- Config {
- draw_bold_text_with_bright_colors: true,
- dimensions: None,
- padding: None,
- font: Default::default(),
- render_timer: Default::default(),
- custom_cursor_colors: false,
- colors: Default::default(),
- background_opacity: Default::default(),
- key_bindings: Vec::new(),
- mouse_bindings: Vec::new(),
- selection: Default::default(),
- mouse: Default::default(),
- shell: None,
- config_path: None,
- visual_bell: Default::default(),
- env: Default::default(),
- hide_cursor_when_typing: Default::default(),
- cursor_style: Default::default(),
- dynamic_title: Default::default(),
- live_config_reload: true,
- window: Default::default(),
- }
+ fn default() -> Self {
+ serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG)
+ .expect("default config is invalid")
}
}
@@ -846,19 +934,26 @@ pub enum Error {
#[derive(Debug, Deserialize)]
pub struct Colors {
+ #[serde(default, deserialize_with = "failure_default")]
pub primary: PrimaryColors,
- #[serde(deserialize_with="deserialize_cursor_colors", default="default_cursor_colors")]
+ #[serde(default, deserialize_with = "deserialize_cursor_colors")]
pub cursor: CursorColors,
pub normal: AnsiColors,
pub bright: AnsiColors,
+ #[serde(default, deserialize_with = "failure_default")]
pub dim: Option<AnsiColors>,
}
fn deserialize_cursor_colors<'a, D>(deserializer: D) -> ::std::result::Result<CursorColors, D::Error>
where D: de::Deserializer<'a>
{
- let either = CursorOrPrimaryColors::deserialize(deserializer)?;
- Ok(either.into_cursor_colors())
+ match CursorOrPrimaryColors::deserialize(deserializer) {
+ Ok(either) => Ok(either.into_cursor_colors()),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using default value", err);
+ Ok(CursorColors::default())
+ },
+ }
}
#[derive(Deserialize)]
@@ -901,19 +996,21 @@ impl CursorOrPrimaryColors {
}
}
-fn default_cursor_colors() -> CursorColors {
- CursorColors {
- text: Rgb { r: 0, g: 0, b: 0 },
- cursor: Rgb { r: 0xff, g: 0xff, b: 0xff },
- }
-}
-
#[derive(Debug)]
pub struct CursorColors {
pub text: Rgb,
pub cursor: Rgb,
}
+impl Default for CursorColors {
+ fn default() -> Self {
+ CursorColors {
+ text: Rgb { r: 0, g: 0, b: 0 },
+ cursor: Rgb { r: 0xff, g: 0xff, b: 0xff },
+ }
+ }
+}
+
#[derive(Debug, Deserialize)]
pub struct PrimaryColors {
#[serde(deserialize_with = "rgb_from_hex")]
@@ -922,14 +1019,20 @@ pub struct PrimaryColors {
pub foreground: Rgb,
}
+impl Default for PrimaryColors {
+ fn default() -> Self {
+ PrimaryColors {
+ background: Rgb { r: 0, g: 0, b: 0 },
+ foreground: Rgb { r: 0xea, g: 0xea, b: 0xea },
+ }
+ }
+}
+
impl Default for Colors {
fn default() -> Colors {
Colors {
- primary: PrimaryColors {
- background: Rgb { r: 0, g: 0, b: 0 },
- foreground: Rgb { r: 0xea, g: 0xea, b: 0xea },
- },
- cursor: default_cursor_colors(),
+ primary: PrimaryColors::default(),
+ cursor: CursorColors::default(),
normal: AnsiColors {
black: Rgb {r: 0x00, g: 0x00, b: 0x00},
red: Rgb {r: 0xd5, g: 0x4e, b: 0x53},
@@ -1000,7 +1103,16 @@ fn rgb_from_hex<'a, D>(deserializer: D) -> ::std::result::Result<Rgb, D::Error>
}
}
- deserializer.deserialize_str(RgbVisitor)
+ let rgb = deserializer.deserialize_str(RgbVisitor);
+
+ // Use #ff00ff as fallback color
+ match rgb {
+ Ok(rgb) => Ok(rgb),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using color #ff00ff", err);
+ Ok(Rgb { r: 255, g: 0, b: 255 })
+ },
+ }
}
impl FromStr for Rgb {
@@ -1171,6 +1283,10 @@ impl Config {
&self.selection
}
+ pub fn tabspaces(&self) -> usize {
+ self.tabspaces
+ }
+
pub fn padding(&self) -> &Delta {
self.padding.as_ref()
.unwrap_or(&self.window.padding)
@@ -1337,8 +1453,10 @@ impl Dimensions {
#[derive(Clone, Copy, Debug, Deserialize)]
pub struct Delta {
/// Horizontal change
+ #[serde(default, deserialize_with = "failure_default")]
pub x: f32,
/// Vertical change
+ #[serde(default, deserialize_with = "failure_default")]
pub y: f32,
}
@@ -1385,9 +1503,18 @@ impl DeserializeSize for Size {
}
}
- deserializer
+ let size = deserializer
.deserialize_any(NumVisitor::<D>{ _marker: PhantomData })
- .map(|v| Size::new(v as _))
+ .map(|v| Size::new(v as _));
+
+ // Use font size 12 as fallback
+ match size {
+ Ok(size) => Ok(size),
+ Err(err) => {
+ eprintln!("problem with config: {}; Using size 12", err);
+ Ok(Size::new(12.))
+ },
+ }
}
}
@@ -1413,13 +1540,14 @@ pub struct Font {
pub size: Size,
/// Extra spacing per character
+ #[serde(default, deserialize_with = "failure_default")]
offset: Delta,
/// Glyph offset within character cell
- #[serde(default)]
+ #[serde(default, deserialize_with = "failure_default")]
glyph_offset: Delta,
- #[serde(default="true_bool")]
+ #[serde(default="true_bool", deserialize_with = "default_true_bool")]
use_thin_strokes: bool
}
@@ -1583,6 +1711,10 @@ impl Monitor {
mod tests {
use super::Config;
+ #[cfg(target_os="macos")]
+ static ALACRITTY_YML: &'static str =
+ include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty_macos.yml"));
+ #[cfg(not(target_os="macos"))]
static ALACRITTY_YML: &'static str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml"));
@@ -1597,12 +1729,6 @@ mod tests {
// Sanity check that key bindings are being parsed
assert!(config.key_bindings.len() >= 1);
}
-
- #[test]
- fn defaults_are_ok() {
- super::default_key_bindings();
- super::default_mouse_bindings();
- }
}
#[cfg_attr(feature = "clippy", allow(enum_variant_names))]
diff --git a/src/main.rs b/src/main.rs
index e9ff12d5..42aa9449 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -71,16 +71,8 @@ fn load_config(options: &cli::Options) -> Config {
});
Config::load_from(&*config_path).unwrap_or_else(|err| {
- match err {
- config::Error::NotFound => {
- die!("Config file not found at: {}", config_path.display());
- },
- config::Error::Empty => {
- eprintln!("Empty config; Loading defaults");
- Config::default()
- },
- _ => die!("{}", err),
- }
+ eprintln!("Error: {}; Loading default config", err);
+ Config::default()
})
}
diff --git a/src/term/mod.rs b/src/term/mod.rs
index 7e6ff1e0..72c259f7 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -444,8 +444,6 @@ pub mod mode {
pub use self::mode::TermMode;
-pub const TAB_SPACES: usize = 8;
-
trait CharsetMapping {
fn map(&self, c: char) -> char {
c
@@ -721,6 +719,9 @@ pub struct Term {
default_cursor_style: CursorStyle,
dynamic_title: bool,
+
+ /// Number of spaces in one tab
+ tabspaces: usize,
}
/// Terminal size info
@@ -798,8 +799,9 @@ impl Term {
let grid = Grid::new(num_lines, num_cols, &template);
+ let tabspaces = config.tabspaces();
let tabs = IndexRange::from(Column(0)..grid.num_cols())
- .map(|i| (*i as usize) % TAB_SPACES == 0)
+ .map(|i| (*i as usize) % tabspaces == 0)
.collect::<Vec<bool>>();
let alt = grid.clone();
@@ -832,6 +834,7 @@ impl Term {
cursor_style: None,
default_cursor_style: config.cursor_style(),
dynamic_title: config.dynamic_title(),
+ tabspaces,
}
}
@@ -1072,7 +1075,7 @@ impl Term {
// Recreate tabs list
self.tabs = IndexRange::from(Column(0)..self.grid.num_cols())
- .map(|i| (*i as usize) % TAB_SPACES == 0)
+ .map(|i| (*i as usize) % self.tabspaces == 0)
.collect::<Vec<bool>>();
if num_lines > old_lines {