diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs index b855923..7b22fb0 100644 --- a/font/src/ft/mod.rs +++ b/font/src/ft/mod.rs @@ -24,7 +24,7 @@ use libc::c_uint; pub mod fc; -use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style, UNDERLINE_CURSOR_CHAR}; +use super::{FontDesc, RasterizedGlyph, Metrics, Size, FontKey, GlyphKey, Weight, Slant, Style}; struct FixedSize { pixelsize: f64, @@ -294,37 +294,50 @@ impl FreeTypeRasterizer { let (pixel_width, buf) = Self::normalize_buffer(&glyph.bitmap())?; - // Render a custom symbol for the underline cursor - if glyph_key.c == UNDERLINE_CURSOR_CHAR { - // Get the bottom of the bounding box - let size_metrics = face.ft_face.size_metrics() - .ok_or(Error::MissingSizeMetrics)?; - let descent = (size_metrics.descender / 64) as f32; + // Render a custom symbol for the underline and beam cursor + match glyph_key.c { + super::UNDERLINE_CURSOR_CHAR => { + // Get the bottom of the bounding box + let size_metrics = face.ft_face.size_metrics() + .ok_or(Error::MissingSizeMetrics)?; + let descent = (size_metrics.descender / 64) as i32; - // Create a new rectangle, the height is half the distance between - // bounding box bottom and the baseline - let height = f32::abs(descent / 2.) as i32; - let buf = vec![255u8; (pixel_width * height * 3) as usize]; + // Get the width of the cell + let metrics = glyph.metrics(); + let width = (metrics.vertAdvance as f32 / 128.).round() as i32; - // Create a custom glyph with the rectangle data attached to it - return Ok(RasterizedGlyph { - c: glyph_key.c, - top: descent as i32 + height, - left: glyph.bitmap_left(), - height, - width: pixel_width, - buf: buf, - }); + // Return the new custom glyph + super::get_underline_cursor_glyph(descent, width) + }, + super::BEAM_CURSOR_CHAR => { + // Get the top of the bounding box + let size_metrics = face.ft_face.size_metrics() + .ok_or(Error::MissingSizeMetrics)?; + let ascent = (size_metrics.ascender / 64) as i32 - 1; + + // Get the height of the cell + let descent = (size_metrics.descender / 64) as i32; + let height = ascent - descent; + + // Get the width of the cell + let metrics = glyph.metrics(); + let width = (metrics.vertAdvance as f32 / 128.).round() as i32; + + // Return the new custom glyph + super::get_beam_cursor_glyph(ascent, height, width) + }, + _ => { + // If it's not a special char, return the normal glyph + Ok(RasterizedGlyph { + c: glyph_key.c, + top: glyph.bitmap_top(), + left: glyph.bitmap_left(), + width: pixel_width, + height: glyph.bitmap().rows(), + buf: buf, + }) + } } - - Ok(RasterizedGlyph { - c: glyph_key.c, - top: glyph.bitmap_top(), - left: glyph.bitmap_left(), - width: pixel_width, - height: glyph.bitmap().rows(), - buf: buf, - }) } fn ft_load_flags(pat: &fc::Pattern) -> freetype::face::LoadFlag { diff --git a/font/src/lib.rs b/font/src/lib.rs index 5d35e47..776127e 100644 --- a/font/src/lib.rs +++ b/font/src/lib.rs @@ -65,6 +65,13 @@ pub const UNDERLINE_CURSOR_CHAR: char = '\u{10a3e2}'; #[cfg(target_os = "macos")] pub const UNDERLINE_CURSOR_CHAR: char = '▁'; +/// Character used for the beam cursor +#[cfg(not(target_os = "macos"))] +// This is part of the private use area and should not conflict with any font +pub const BEAM_CURSOR_CHAR: char = '\u{10a3e3}'; +#[cfg(target_os = "macos")] +pub const BEAM_CURSOR_CHAR: char = '▎'; + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FontDesc { name: String, @@ -209,6 +216,41 @@ impl Default for RasterizedGlyph { } } +// Returns a custom underline cursor character +pub fn get_underline_cursor_glyph(descent: i32, width: i32) -> Result { + // Create a new rectangle, the height is half the distance between + // bounding box bottom and the baseline + let height = i32::abs(descent / 2); + let buf = vec![255u8; (width * height * 3) as usize]; + + // Create a custom glyph with the rectangle data attached to it + return Ok(RasterizedGlyph { + c: UNDERLINE_CURSOR_CHAR, + top: descent + height, + left: 0, + height, + width, + buf: buf, + }); +} + +// Returns a custom beam cursor character +pub fn get_beam_cursor_glyph(ascent: i32, height: i32, width: i32) -> Result { + // Create a new rectangle + let beam_width = (f64::from(width) / 5.) as i32; + let buf = vec![255u8; (beam_width * height * 3) as usize]; + + // Create a custom glyph with the rectangle data attached to it + return Ok(RasterizedGlyph { + c: BEAM_CURSOR_CHAR, + top: ascent, + left: 0, + height, + width: beam_width, + buf: buf, + }); +} + struct BufDebugger<'a>(&'a [u8]); impl<'a> fmt::Debug for BufDebugger<'a> { diff --git a/src/term/mod.rs b/src/term/mod.rs index 2e1365f..8611517 100644 --- a/src/term/mod.rs +++ b/src/term/mod.rs @@ -181,7 +181,7 @@ impl<'a> RenderableCellsIter<'a> { }); let cursor_color = self.text_cursor_color(&cursor_cell); - cursor_cell.c = '▎'; + cursor_cell.c = font::BEAM_CURSOR_CHAR; cursor_cell.fg = cursor_color; self.cursor_cells.push_back(Indexed { line: self.cursor.line,