WIP
diff --git a/src/config/font.rs b/src/config/font.rs
new file mode 100644
index 0000000..2d3ae31
--- /dev/null
+++ b/src/config/font.rs
@@ -0,0 +1,212 @@
+// 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)
+        },
+    }
+}
diff --git a/src/config.rs b/src/config/mod.rs
similarity index 90%
rename from src/config.rs
rename to src/config/mod.rs
index be96715..b3400b7 100644
--- a/src/config.rs
+++ b/src/config/mod.rs
@@ -3,6 +3,8 @@
 //! 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.
+pub mod font;
+
 use std::borrow::Cow;
 use std::{env, fmt};
 use std::fs::{self, File};
@@ -14,15 +16,15 @@
 use std::collections::HashMap;
 
 use ::Rgb;
-use font::Size;
 use serde_yaml;
-use serde::{self, de, Deserialize};
+use serde::{de, Deserialize};
 use serde::de::Error as SerdeError;
 use serde::de::{Visitor, MapAccess, Unexpected};
 use notify::{Watcher, watcher, DebouncedEvent, RecursiveMode};
 
 use glutin::ModifiersState;
 
+use self::font::FontConfiguration;
 use input::{Action, Binding, MouseBinding, KeyBinding};
 use index::{Line, Column};
 use ansi::CursorStyle;
@@ -326,7 +328,7 @@
 
     /// Font configuration
     #[serde(default, deserialize_with = "failure_default")]
-    font: Font,
+    font: FontConfiguration,
 
     /// Should show render timer
     #[serde(default, deserialize_with = "failure_default")]
@@ -453,7 +455,7 @@
     }
 }
 
-fn failure_default<'a, D, T>(deserializer: D)
+pub fn failure_default<'a, D, T>(deserializer: D)
     -> ::std::result::Result<T, D::Error>
     where D: de::Deserializer<'a>,
           T: Deserialize<'a> + Default
@@ -467,10 +469,8 @@
     }
 }
 
-#[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");
+static DEFAULT_ALACRITTY_CONFIG: &'static str =
+    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml"));
 
 impl Default for Config {
     fn default() -> Self {
@@ -1295,12 +1295,6 @@
         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 {
@@ -1325,11 +1319,6 @@
         self.render_timer
     }
 
-    #[inline]
-    pub fn use_thin_strokes(&self) -> bool {
-        self.font.use_thin_strokes
-    }
-
     /// show cursor as inverted
     #[inline]
     pub fn custom_cursor_colors(&self) -> bool {
@@ -1464,173 +1453,6 @@
     }
 }
 
-trait DeserializeSize : Sized {
-    fn deserialize<'a, D>(D) -> ::std::result::Result<Self, D::Error>
-        where D: serde::de::Deserializer<'a>;
-}
-
-impl DeserializeSize for Size {
-    fn deserialize<'a, D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
-        where D: serde::de::Deserializer<'a>
-    {
-        use std::marker::PhantomData;
-
-        struct NumVisitor<__D> {
-            _marker: PhantomData<__D>,
-        }
-
-        impl<'a, __D> Visitor<'a> for NumVisitor<__D>
-            where __D: serde::de::Deserializer<'a>
-        {
-            type Value = f64;
-
-            fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
-                f.write_str("f64 or u64")
-            }
-
-            fn visit_f64<E>(self, value: f64) -> ::std::result::Result<Self::Value, E>
-                where E: ::serde::de::Error
-            {
-                Ok(value)
-            }
-
-            fn visit_u64<E>(self, value: u64) -> ::std::result::Result<Self::Value, E>
-                where E: ::serde::de::Error
-            {
-                Ok(value as f64)
-            }
-        }
-
-        let size = deserializer
-            .deserialize_any(NumVisitor::<D>{ _marker: PhantomData })
-            .map(|v| Size::new(v as _));
-
-        // Use font size 12 as fallback
-        match size {
-            Ok(size) => Ok(size),
-            Err(err) => {
-                eprintln!("problem with config: {}; Using size 12", err);
-                Ok(Size::new(12.))
-            },
-        }
-    }
-}
-
-/// Font config
-///
-/// Defaults are provided at the level of this struct per platform, but not per
-/// field in this struct. It might be nice in the future to have defaults for
-/// each value independently. Alternatively, maybe erroring when the user
-/// doesn't provide complete config is Ok.
-#[derive(Debug, Deserialize, Clone)]
-pub struct Font {
-    /// Font family
-    pub normal: FontDescription,
-
-    #[serde(default="default_italic_desc")]
-    pub italic: FontDescription,
-
-    #[serde(default="default_bold_desc")]
-    pub bold: FontDescription,
-
-    // Font size in points
-    #[serde(deserialize_with="DeserializeSize::deserialize")]
-    pub size: Size,
-
-    /// Extra spacing per character
-    #[serde(default, deserialize_with = "failure_default")]
-    offset: Delta,
-
-    /// Glyph offset within character cell
-    #[serde(default, deserialize_with = "failure_default")]
-    glyph_offset: Delta,
-
-    #[serde(default="true_bool", deserialize_with = "default_true_bool")]
-    use_thin_strokes: bool
-}
-
-fn default_bold_desc() -> FontDescription {
-    Font::default().bold
-}
-
-fn default_italic_desc() -> FontDescription {
-    Font::default().italic
-}
-
-/// Description of a single font
-#[derive(Debug, Deserialize, Clone)]
-pub struct FontDescription {
-    pub family: String,
-    pub style: Option<String>,
-}
-
-impl FontDescription {
-    fn new_with_family<S: Into<String>>(family: S) -> FontDescription {
-        FontDescription {
-            family: family.into(),
-            style: None,
-        }
-    }
-}
-
-impl Font {
-    /// Get the font size in points
-    #[inline]
-    pub fn size(&self) -> Size {
-        self.size
-    }
-
-    /// Get offsets to font metrics
-    #[inline]
-    pub fn offset(&self) -> &Delta {
-        &self.offset
-    }
-
-    /// Get cell offsets for glyphs
-    #[inline]
-    pub fn glyph_offset(&self) -> &Delta {
-        &self.glyph_offset
-    }
-
-    /// Get a font clone with a size modification
-    pub fn with_size(self, size: Size) -> Font {
-        Font {
-            size,
-            .. self
-        }
-    }
-}
-
-#[cfg(target_os = "macos")]
-impl Default for Font {
-    fn default() -> Font {
-        Font {
-            normal: FontDescription::new_with_family("Menlo"),
-            bold: FontDescription::new_with_family("Menlo"),
-            italic: FontDescription::new_with_family("Menlo"),
-            size: Size::new(11.0),
-            use_thin_strokes: true,
-            offset: Default::default(),
-            glyph_offset: Default::default()
-        }
-    }
-}
-
-#[cfg(any(target_os = "linux",target_os = "freebsd"))]
-impl Default for Font {
-    fn default() -> Font {
-        Font {
-            normal: FontDescription::new_with_family("monospace"),
-            bold: FontDescription::new_with_family("monospace"),
-            italic: FontDescription::new_with_family("monospace"),
-            size: Size::new(11.0),
-            use_thin_strokes: false,
-            offset: Default::default(),
-            glyph_offset: Default::default()
-        }
-    }
-}
-
 pub struct Monitor {
     _thread: ::std::thread::JoinHandle<()>,
     rx: mpsc::Receiver<Config>,
diff --git a/src/font.rs b/src/font.rs
new file mode 100644
index 0000000..5d80b97
--- /dev/null
+++ b/src/font.rs
@@ -0,0 +1,43 @@
+// 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 config::Delta;
+use font::Size;
+
+struct Font {
+    family: String,
+    options: Option<Options>,
+}
+
+enum AntiAlias {
+    LCD,
+    LCDV,
+    GRAY,
+    // TODO: Maybe change the name so it's not confused with Rust's None?
+    NONE,
+}
+
+struct Options {
+    size: Option<Size>,
+    thin_strokes: Option<bool>,
+    antialias: Option<AntiAlias>,
+    hinting: Option<bool>,
+    style: Option<String>,
+    offset: Option<Delta>,
+    range: Option<FontRange>,
+}
+
+struct FontRange {
+    start: char,
+    end: char,
+}
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index c0e4a9f..9119802 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -30,6 +30,7 @@
 use notify::{Watcher, watcher, RecursiveMode, DebouncedEvent};
 
 use config::{self, Config, Delta};
+use config::font::FontConfiguration;
 use term::{self, cell, RenderableCell};
 use window::{Size, Pixels};
 
@@ -152,124 +153,47 @@
     /// Rasterizer for loading new glyphs
     rasterizer: Rasterizer,
 
-    /// regular font
-    font_key: FontKey,
+    /// Font configuration with all fonts
+    font_config: FontConfiguration,
 
-    /// italic font
-    italic_key: FontKey,
-
-    /// bold font
-    bold_key: FontKey,
-
-    /// font size
-    font_size: font::Size,
-
-    /// glyph offset
-    glyph_offset: Delta,
-
+    /// Font metrics like glyph width/height
     metrics: ::font::Metrics,
 }
 
 impl GlyphCache {
     pub fn new<L>(
         mut rasterizer: Rasterizer,
-        font: &config::Font,
+        font_config: FontConfiguration,
         loader: &mut L
     ) -> Result<GlyphCache, font::Error>
         where L: LoadGlyph
     {
-        let (regular, bold, italic) = Self::compute_font_keys(font, &mut rasterizer)?;
-
         // Need to load at least one glyph for the face before calling metrics.
-        // The glyph requested here ('m' at the time of writing) has no special
+        // The glyph requested here ('0' at the time of writing) has no special
         // meaning.
-        rasterizer.get_glyph(&GlyphKey { font_key: regular, c: 'm', size: font.size() })?;
+        let primary_font = font_config.font_by_char('0');
+        rasterizer.get_glyph(&GlyphKey { font_key: primary_font, c: '0', size: primary_font.size() })?;
         let metrics = rasterizer.metrics(regular)?;
 
         let mut cache = GlyphCache {
             cache: HashMap::default(),
-            rasterizer: rasterizer,
-            font_size: font.size(),
-            font_key: regular,
-            bold_key: bold,
-            italic_key: italic,
-            glyph_offset: *font.glyph_offset(),
-            metrics: metrics
+            metrics,
+            rasterizer,
+            font_config,
         };
 
-        cache.load_glyphs_for_font(regular, loader);
-        cache.load_glyphs_for_font(bold, loader);
-        cache.load_glyphs_for_font(italic, loader);
+        // TODO: Load set of standard glyphs
+        // cache.load_glyphs_for_font(regular, loader);
+        // cache.load_glyphs_for_font(bold, loader);
+        // cache.load_glyphs_for_font(italic, loader);
 
         Ok(cache)
     }
 
-    fn load_glyphs_for_font<L: LoadGlyph>(
-        &mut self,
-        font: FontKey,
-        loader: &mut L,
-    ) {
-        let size = self.font_size;
-        for i in RangeInclusive::new(32u8, 128u8) {
-            self.get(&GlyphKey {
-                font_key: font,
-                c: i as char,
-                size: size
-            }, loader);
-        }
-    }
-
-    /// Computes font keys for (Regular, Bold, Italic)
-    fn compute_font_keys(
-        font: &config::Font,
-        rasterizer: &mut Rasterizer
-    ) -> Result<(FontKey, FontKey, FontKey), font::Error> {
-        let size = font.size();
-
-        // Load regular font
-        let regular_desc = Self::make_desc(&font.normal, font::Slant::Normal, font::Weight::Normal);
-
-        let regular = rasterizer
-            .load_font(&regular_desc, size)?;
-
-        // helper to load a description if it is not the regular_desc
-        let mut load_or_regular = |desc:FontDesc| {
-            if desc == regular_desc {
-                regular
-            } else {
-                rasterizer.load_font(&desc, size).unwrap_or_else(|_| regular)
-            }
-        };
-
-        // Load bold font
-        let bold_desc = Self::make_desc(&font.bold, font::Slant::Normal, font::Weight::Bold);
-
-        let bold = load_or_regular(bold_desc);
-
-        // Load italic font
-        let italic_desc = Self::make_desc(&font.italic, font::Slant::Italic, font::Weight::Normal);
-
-        let italic = load_or_regular(italic_desc);
-
-        Ok((regular, bold, italic))
-    }
-
-    fn make_desc(
-        desc: &config::FontDescription,
-        slant: font::Slant,
-        weight: font::Weight,
-    ) -> FontDesc {
-        let style = if let Some(ref spec) = desc.style {
-            font::Style::Specific(spec.to_owned())
-        } else {
-            font::Style::Description {slant:slant, weight:weight}
-        };
-        FontDesc::new(&desc.family[..], style)
-    }
-
     pub fn font_metrics(&self) -> font::Metrics {
+        let primary_font = self.font_config.font_by_char('0');
         self.rasterizer
-            .metrics(self.font_key)
+            .metrics(primary_font)
             .expect("metrics load since font is loaded at glyph cache creation")
     }
 
@@ -292,9 +216,11 @@
                 loader.load_glyph(&rasterized)
             })
     }
+
+    // TODO
     pub fn update_font_size<L: LoadGlyph>(
         &mut self,
-        font: &config::Font,
+        font: &FontConfiguration,
         size: font::Size,
         loader: &mut L
     ) -> Result<(), font::Error> {