blob: 2d3ae310d30cba1dbc6e08f97053c958d0065ee8 [file] [log] [blame]
// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use serde_yaml;
use serde::{de, Deserialize};
use config::{Delta, failure_default};
use font::{Size, FontKey, Slant};
// Global and local font configuration
#[derive(Deserialize, Debug)]
pub struct FontConfiguration {
#[serde(default, deserialize_with="failure_default")]
options: GlobalOptions,
#[serde(default, deserialize_with="deserialize_font_collection")]
fonts: Vec<Font>,
}
impl FontConfiguration {
pub fn font_by_char(&self, c: char, weight: Slant) -> FontKey {
for font in fonts {
let options = font.options();
// Skip font if font slant does not match requested slant
if options.unwrap_or(self.options as Options).style.unwrap_or(self.options.style) != weight {
continue;
}
let is_match = match options {
Some(options) => {
for range in options.ranges {
if range.start < c && range.end > c {
return true;
}
}
false
},
None => {
true
},
};
if is_match {
// TODO: Check if this font contains the char
}
}
}
}
impl Default for FontConfiguration {
fn default() -> Self {
Self {
fonts: vec!(Font::default()),
..Default::default()
}
}
}
// Information about a font
#[derive(Deserialize, Debug)]
pub struct Font {
family: String,
#[serde(deserialize_with="failure_default")]
options: Option<Options>,
}
// Default font config in case of failure or missing config
impl Default for Font {
#[cfg(target_os = "macos")]
fn default() -> Self {
Font {
family: "Menlo".into(),
options: None,
}
}
#[cfg(not(target_os = "macos"))]
fn default() -> Self {
Font {
family: "monospace".into(),
options: None,
}
}
}
// Options for a font
#[derive(Deserialize, Debug)]
pub struct Options {
#[serde(deserialize_with="deserialize_size")]
size: Option<Size>,
#[serde(deserialize_with="failure_default")]
thin_strokes: Option<bool>,
#[serde(deserialize_with="failure_default")]
antialias: Option<AntiAlias>,
#[serde(deserialize_with="failure_default")]
hinting: Option<bool>,
#[serde(deserialize_with="failure_default")]
style: Option<String>,
#[serde(deserialize_with="failure_default")]
offset: Option<Delta>,
#[serde(deserialize_with="failure_default")]
ranges: Vec<FontRange>,
}
impl Default for Options {
fn default() -> Self {
Options {
size: None,
thin_strokes: None,
antialias: None,
hinting: None,
style: None,
offset: None,
ranges: Vec::new(),
}
}
}
#[derive(Deserialize, Debug)]
pub struct GlobalOptions(Options);
impl Default for GlobalOptions {
fn default() -> Self {
GlobalOptions(Options {
size: Some(Size::new(12.0)),
thin_strokes: Some(true),
antialias: Some(AntiAlias::LCD),
hinting: Some(true),
style: Some("normal".into()),
offset: Some(Delta::default()),
ranges: Vec::new(),
})
}
}
// AntiAliasing settings for fonts
#[derive(Deserialize, Debug)]
pub enum AntiAlias {
LCD,
LCDV,
GRAY,
DISABLED,
}
// Range for which a specific font should be used
#[derive(Deserialize, Debug)]
pub struct FontRange {
#[serde(deserialize_with="failure_default")]
start: char,
#[serde(deserialize_with="failure_default")]
end: char,
}
// Deserialize the font vector
fn deserialize_font_collection<'a, D>(deserializer: D)
-> ::std::result::Result<Vec<Font>, D::Error>
where D: de::Deserializer<'a>,
{
// Deserialize vector as generic yaml value
let mut value = match serde_yaml::Value::deserialize(deserializer) {
Ok(value) => value,
Err(err) => {
eprintln!("problem with config: {}; Using default fonts", err);
return Ok(vec!(Font::default()));
},
};
// Get value as sequence
let sequence = match value.as_sequence_mut() {
Some(sequence) => sequence,
None => return Ok(vec!(Font::default())),
};
// Deserialize each element in the sequence
let mut font_collection = Vec::new();
for i in 0..sequence.len() {
match Font::deserialize(sequence.remove(i)) {
Ok(font) => font_collection.push(font),
// TODO: Print line or something like that?
Err(err) => eprintln!("problem with config: Malformed font; Skipping"),
}
}
// Return defaults if collection contains no font
if font_collection.is_empty() {
Ok(vec!(Font::default()))
} else {
Ok(font_collection)
}
}
// Deserialize font size
fn deserialize_size<'a, D>(deserializer: D)
-> ::std::result::Result<Option<Size>, D::Error>
where D: de::Deserializer<'a>,
{
match f32::deserialize(deserializer) {
Ok(value) => Ok(Some(Size::new(value))),
_ => {
Ok(None)
},
}
}