Print nice error messages for font loading errors

Resolves #22.
This commit is contained in:
Joe Wilm 2016-12-31 19:49:51 -08:00
parent 2738969f29
commit a86dfd1a11
3 changed files with 83 additions and 24 deletions

View File

@ -30,6 +30,52 @@ use term::{Term, SizeInfo};
use window::{self, Size, Pixels, Window, SetInnerSize}; use window::{self, Size, Pixels, Window, SetInnerSize};
#[derive(Debug)]
pub enum Error {
/// Error with window management
Window(window::Error),
/// Error dealing with fonts
Font(font::Error),
}
impl ::std::error::Error for Error {
fn cause(&self) -> Option<&::std::error::Error> {
match *self {
Error::Window(ref err) => Some(err),
Error::Font(ref err) => Some(err),
}
}
fn description(&self) -> &str {
match *self {
Error::Window(ref err) => err.description(),
Error::Font(ref err) => err.description(),
}
}
}
impl ::std::fmt::Display for Error {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
Error::Window(ref err) => err.fmt(f),
Error::Font(ref err) => err.fmt(f),
}
}
}
impl From<window::Error> for Error {
fn from(val: window::Error) -> Error {
Error::Window(val)
}
}
impl From<font::Error> for Error {
fn from(val: font::Error) -> Error {
Error::Font(val)
}
}
/// The display wraps a window, font rasterizer, and GPU renderer /// The display wraps a window, font rasterizer, and GPU renderer
pub struct Display { pub struct Display {
window: Window, window: Window,
@ -74,26 +120,23 @@ impl Display {
pub fn new( pub fn new(
config: &Config, config: &Config,
options: &cli::Options, options: &cli::Options,
) -> Result<Display, window::Error> { ) -> Result<Display, Error> {
// Extract some properties from config // Extract some properties from config
let font = config.font(); let font = config.font();
let dpi = config.dpi(); let dpi = config.dpi();
let render_timer = config.render_timer(); let render_timer = config.render_timer();
// Create the window where Alacritty will be displayed // Create the window where Alacritty will be displayed
let mut window = match Window::new() { let mut window = Window::new()?;
Ok(window) => window,
Err(err) => die!("{}", err)
};
// get window properties for initializing the other subsytems // get window properties for initializing the other subsytems
let size = window.inner_size_pixels().unwrap(); let size = window.inner_size_pixels()
.expect("glutin returns window size");
let dpr = window.hidpi_factor(); let dpr = window.hidpi_factor();
println!("device_pixel_ratio: {}", dpr); println!("device_pixel_ratio: {}", dpr);
// TODO ERROR HANDLING let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr)?;
let rasterizer = font::Rasterizer::new(dpi.x(), dpi.y(), dpr).unwrap();
// Create renderer // Create renderer
let mut renderer = QuadRenderer::new(config, size); let mut renderer = QuadRenderer::new(config, size);
@ -105,7 +148,7 @@ impl Display {
let cache = renderer.with_loader(|mut api| { let cache = renderer.with_loader(|mut api| {
GlyphCache::new(rasterizer, config, &mut api) GlyphCache::new(rasterizer, config, &mut api)
}); })?;
let stop = init_start.elapsed(); let stop = init_start.elapsed();
let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64; let stop_f = stop.as_secs() as f64 + stop.subsec_nanos() as f64 / 1_000_000_000f64;
@ -247,8 +290,10 @@ impl Display {
} }
} }
// Unlock the terminal mutex // Unlock the terminal mutex; following call to swap_buffers() may block
drop(terminal); drop(terminal);
self.window.swap_buffers().unwrap(); self.window
.swap_buffers()
.expect("swap buffers");
} }
} }

View File

@ -52,12 +52,20 @@ fn main() {
// Run alacritty // Run alacritty
if let Err(err) = run(config, options) { if let Err(err) = run(config, options) {
die!("{}", err); die!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", Red(err));
} }
println!("Goodbye"); println!("Goodbye");
} }
use std::fmt;
struct Red<T>(T);
impl<T: fmt::Display> fmt::Display for Red<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\x1b[31m{}\x1b[0m", self.0)
}
}
/// Run Alacritty /// Run Alacritty
/// ///
/// Creates a window, the terminal state, pty, I/O event loop, input processor, /// Creates a window, the terminal state, pty, I/O event loop, input processor,

View File

@ -119,7 +119,11 @@ pub struct GlyphCache {
} }
impl GlyphCache { impl GlyphCache {
pub fn new<L>(mut rasterizer: Rasterizer, config: &Config, loader: &mut L) -> GlyphCache pub fn new<L>(
mut rasterizer: Rasterizer,
config: &Config,
loader: &mut L
) -> Result<GlyphCache, font::Error>
where L: LoadGlyph where L: LoadGlyph
{ {
let font = config.font(); let font = config.font();
@ -128,8 +132,7 @@ impl GlyphCache {
// Load regular font // Load regular font
let regular_desc = FontDesc::new(font.family(), font.style()); let regular_desc = FontDesc::new(font.family(), font.style());
let regular = rasterizer let regular = rasterizer
.load_font(&regular_desc, size) .load_font(&regular_desc, size)?;
.expect("regular font load ok");
// Load bold font // Load bold font
let bold_style = font.bold_style().unwrap_or("Bold"); let bold_style = font.bold_style().unwrap_or("Bold");
@ -177,21 +180,22 @@ impl GlyphCache {
load_glyphs_for_font!(bold); load_glyphs_for_font!(bold);
load_glyphs_for_font!(italic); load_glyphs_for_font!(italic);
cache Ok(cache)
} }
pub fn font_metrics(&self) -> font::Metrics { pub fn font_metrics(&self) -> font::Metrics {
// TODO ERROR HANDLING self.rasterizer
self.rasterizer.metrics(self.font_key, self.font_size).unwrap() .metrics(self.font_key, self.font_size)
.expect("metrics load since font is loaded at glyph cache creation")
} }
fn load_and_cache_glyph<L>(&mut self, glyph_key: GlyphKey, loader: &mut L) fn load_and_cache_glyph<L>(&mut self, glyph_key: GlyphKey, loader: &mut L)
where L: LoadGlyph where L: LoadGlyph
{ {
// TODO ERROR HANDLING if let Ok(rasterized) = self.rasterizer.get_glyph(&glyph_key) {
let rasterized = self.rasterizer.get_glyph(&glyph_key).unwrap(); let glyph = loader.load_glyph(&rasterized);
let glyph = loader.load_glyph(&rasterized); self.cache.insert(glyph_key, glyph);
self.cache.insert(glyph_key, glyph); }
} }
pub fn get<L>(&mut self, glyph_key: &GlyphKey, loader: &mut L) -> Option<&Glyph> pub fn get<L>(&mut self, glyph_key: &GlyphKey, loader: &mut L) -> Option<&Glyph>
@ -783,7 +787,8 @@ impl<'a> LoadGlyph for LoaderApi<'a> {
/// ///
/// If the current atlas is full, a new one will be created. /// If the current atlas is full, a new one will be created.
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph { fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
// At least one atlas is guaranteed to be in the `self.atlas` list; thus the unwrap. // At least one atlas is guaranteed to be in the `self.atlas` list; thus
// the unwrap should always be ok.
match self.atlas.last_mut().unwrap().insert(rasterized, &mut self.active_tex) { match self.atlas.last_mut().unwrap().insert(rasterized, &mut self.active_tex) {
Ok(glyph) => glyph, Ok(glyph) => glyph,
Err(_) => { Err(_) => {
@ -801,7 +806,8 @@ impl<'a> LoadGlyph for RenderApi<'a> {
/// ///
/// If the current atlas is full, a new one will be created. /// If the current atlas is full, a new one will be created.
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph { fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
// At least one atlas is guaranteed to be in the `self.atlas` list; thus the unwrap. // At least one atlas is guaranteed to be in the `self.atlas` list; thus
// the unwrap.
match self.atlas.last_mut().unwrap().insert(rasterized, &mut self.active_tex) { match self.atlas.last_mut().unwrap().insert(rasterized, &mut self.active_tex) {
Ok(glyph) => glyph, Ok(glyph) => glyph,
Err(_) => { Err(_) => {