alacritty/alacritty/src/cursor.rs

113 lines
3.6 KiB
Rust
Raw Normal View History

2020-05-05 22:50:23 +00:00
//! Helpers for creating different cursor glyphs from font metrics.
2020-07-18 01:27:41 +00:00
use crossfont::{BitmapBuffer, Metrics, RasterizedGlyph};
use alacritty_terminal::ansi::CursorShape;
pub fn get_cursor_glyph(
cursor: CursorShape,
metrics: Metrics,
offset_x: i8,
offset_y: i8,
is_wide: bool,
Replace serde's derive with custom proc macro This replaces the existing `Deserialize` derive from serde with a `ConfigDeserialize` derive. The goal of this new proc macro is to allow a more error-friendly deserialization for the Alacritty configuration file without having to manage a lot of boilerplate code inside the configuration modules. The first part of the derive macro is for struct deserialization. This takes structs which have `Default` implemented and will only replace fields which can be successfully deserialized. Otherwise the `log` crate is used for printing errors. Since this deserialization takes the default value from the struct instead of the value, it removes the necessity for creating new types just to implement `Default` on them for deserialization. Additionally, the struct deserialization also checks for `Option` values and makes sure that explicitly specifying `none` as text literal is allowed for all options. The other part of the derive macro is responsible for deserializing enums. While only enums with Unit variants are supported, it will automatically implement a deserializer for these enums which accepts any form of capitalization. Since this custom derive prevents us from using serde's attributes on fields, some of the attributes have been reimplemented for `ConfigDeserialize`. These include `#[config(flatten)]`, `#[config(skip)]` and `#[config(alias = "alias)]`. The flatten attribute is currently limited to at most one per struct. Additionally the `#[config(deprecated = "optional message")]` attribute allows easily defining uniform deprecation messages for fields on structs.
2020-12-21 02:44:38 +00:00
cursor_thickness: f32,
) -> RasterizedGlyph {
2020-05-05 22:50:23 +00:00
// Calculate the cell metrics.
//
// NOTE: With Rust 1.47+ `f64 as usize` is defined to clamp automatically:
// https://github.com/rust-lang/rust/commit/14d608f1d8a0b84da5f3bccecb3efb3d35f980dc
let height = (metrics.line_height + f64::from(offset_y)).max(1.) as usize;
let mut width = (metrics.average_advance + f64::from(offset_x)).max(1.) as usize;
Replace serde's derive with custom proc macro This replaces the existing `Deserialize` derive from serde with a `ConfigDeserialize` derive. The goal of this new proc macro is to allow a more error-friendly deserialization for the Alacritty configuration file without having to manage a lot of boilerplate code inside the configuration modules. The first part of the derive macro is for struct deserialization. This takes structs which have `Default` implemented and will only replace fields which can be successfully deserialized. Otherwise the `log` crate is used for printing errors. Since this deserialization takes the default value from the struct instead of the value, it removes the necessity for creating new types just to implement `Default` on them for deserialization. Additionally, the struct deserialization also checks for `Option` values and makes sure that explicitly specifying `none` as text literal is allowed for all options. The other part of the derive macro is responsible for deserializing enums. While only enums with Unit variants are supported, it will automatically implement a deserializer for these enums which accepts any form of capitalization. Since this custom derive prevents us from using serde's attributes on fields, some of the attributes have been reimplemented for `ConfigDeserialize`. These include `#[config(flatten)]`, `#[config(skip)]` and `#[config(alias = "alias)]`. The flatten attribute is currently limited to at most one per struct. Additionally the `#[config(deprecated = "optional message")]` attribute allows easily defining uniform deprecation messages for fields on structs.
2020-12-21 02:44:38 +00:00
let line_width = (cursor_thickness * width as f32).round().max(1.) as usize;
2020-05-05 22:50:23 +00:00
// Double the cursor width if it's above a double-width glyph.
if is_wide {
width *= 2;
}
match cursor {
CursorShape::HollowBlock => get_box_cursor_glyph(height, width, line_width),
CursorShape::Underline => get_underline_cursor_glyph(width, line_width),
CursorShape::Beam => get_beam_cursor_glyph(height, line_width),
CursorShape::Block => get_block_cursor_glyph(height, width),
CursorShape::Hidden => RasterizedGlyph::default(),
}
}
2020-05-05 22:50:23 +00:00
/// Return a custom underline cursor character.
pub fn get_underline_cursor_glyph(width: usize, line_width: usize) -> RasterizedGlyph {
2020-05-05 22:50:23 +00:00
// Create a new rectangle, the height is relative to the font width.
let buf = vec![255u8; width * line_width * 3];
2020-05-05 22:50:23 +00:00
// Create a custom glyph with the rectangle data attached to it.
RasterizedGlyph {
c: ' ',
top: line_width as i32,
left: 0,
height: line_width as i32,
width: width as i32,
buf: BitmapBuffer::RGB(buf),
}
}
2020-05-05 22:50:23 +00:00
/// Return a custom beam cursor character.
pub fn get_beam_cursor_glyph(height: usize, line_width: usize) -> RasterizedGlyph {
// Create a new rectangle that is at least one pixel wide
let buf = vec![255u8; line_width * height * 3];
// Create a custom glyph with the rectangle data attached to it
RasterizedGlyph {
c: ' ',
top: height as i32,
left: 0,
height: height as i32,
width: line_width as i32,
buf: BitmapBuffer::RGB(buf),
}
}
2020-05-05 22:50:23 +00:00
/// Returns a custom box cursor character.
pub fn get_box_cursor_glyph(height: usize, width: usize, line_width: usize) -> RasterizedGlyph {
2020-05-05 22:50:23 +00:00
// Create a new box outline rectangle.
let mut buf = Vec::with_capacity(width * height * 3);
for y in 0..height {
for x in 0..width {
if y < line_width
|| y >= height - line_width
|| x < line_width
|| x >= width - line_width
{
buf.append(&mut vec![255u8; 3]);
} else {
buf.append(&mut vec![0u8; 3]);
}
}
}
2020-05-05 22:50:23 +00:00
// Create a custom glyph with the rectangle data attached to it.
RasterizedGlyph {
c: ' ',
top: height as i32,
left: 0,
height: height as i32,
width: width as i32,
buf: BitmapBuffer::RGB(buf),
}
}
2020-05-05 22:50:23 +00:00
/// Return a custom block cursor character.
pub fn get_block_cursor_glyph(height: usize, width: usize) -> RasterizedGlyph {
2020-05-05 22:50:23 +00:00
// Create a completely filled glyph.
let buf = vec![255u8; width * height * 3];
2020-05-05 22:50:23 +00:00
// Create a custom glyph with the rectangle data attached to it.
RasterizedGlyph {
c: ' ',
top: height as i32,
left: 0,
height: height as i32,
width: width as i32,
buf: BitmapBuffer::RGB(buf),
}
}