support bold and italic text

macos-click-through
Keith Simmons 5 years ago
parent 4297faca63
commit e08ac79b9f

@ -43,7 +43,7 @@ impl Cursor {
Cursor { Cursor {
position: (0, 0), position: (0, 0),
shape: CursorShape::Block, shape: CursorShape::Block,
style: Option::<Style>::default(), style: None,
enabled: true, enabled: true,
mode_list: Vec::new() mode_list: Vec::new()
} }

@ -69,7 +69,8 @@ impl Editor {
RedrawEvent::GridLine { row, column_start, cells, .. } => self.draw_grid_line(row, column_start, cells), RedrawEvent::GridLine { row, column_start, cells, .. } => self.draw_grid_line(row, column_start, cells),
RedrawEvent::Clear { .. } => self.clear(), RedrawEvent::Clear { .. } => self.clear(),
RedrawEvent::CursorGoto { row, column, .. } => self.cursor.position = (row, column), RedrawEvent::CursorGoto { row, column, .. } => self.cursor.position = (row, column),
RedrawEvent::Scroll { top, bottom, left, right, rows, columns, .. } => self.scroll_region(top, bottom, left, right, rows, columns) RedrawEvent::Scroll { top, bottom, left, right, rows, columns, .. } => self.scroll_region(top, bottom, left, right, rows, columns),
_ => {}
}; };
} }

@ -13,6 +13,7 @@ pub enum EventParseError {
InvalidString(Value), InvalidString(Value),
InvalidU64(Value), InvalidU64(Value),
InvalidI64(Value), InvalidI64(Value),
InvalidBool(Value),
InvalidEventFormat InvalidEventFormat
} }
type Result<T> = std::result::Result<T, EventParseError>; type Result<T> = std::result::Result<T, EventParseError>;
@ -25,6 +26,7 @@ impl fmt::Display for EventParseError {
EventParseError::InvalidString(value) => write!(f, "invalid string format {}", value), EventParseError::InvalidString(value) => write!(f, "invalid string format {}", value),
EventParseError::InvalidU64(value) => write!(f, "invalid u64 format {}", value), EventParseError::InvalidU64(value) => write!(f, "invalid u64 format {}", value),
EventParseError::InvalidI64(value) => write!(f, "invalid i64 format {}", value), EventParseError::InvalidI64(value) => write!(f, "invalid i64 format {}", value),
EventParseError::InvalidBool(value) => write!(f, "invalid bool format {}", value),
EventParseError::InvalidEventFormat => write!(f, "invalid event format") EventParseError::InvalidEventFormat => write!(f, "invalid event format")
} }
} }
@ -43,6 +45,42 @@ pub struct GridLineCell {
pub repeat: Option<u64> pub repeat: Option<u64>
} }
pub enum MessageKind {
Unknown,
Confirm,
ConfirmSubstitute,
Error,
Echo,
EchoMessage,
EchoError,
LuaError,
RpcError,
ReturnPrompt,
QuickFix,
SearchCount,
Warning
}
impl MessageKind {
pub fn parse(kind: &str) -> MessageKind {
match kind {
"confirm" => MessageKind::Confirm,
"confirm_sub" => MessageKind::ConfirmSubstitute,
"emsg" => MessageKind::Error,
"echo" => MessageKind::Echo,
"echomsg" => MessageKind::EchoMessage,
"echoerr" => MessageKind::EchoError,
"lua_error" => MessageKind::LuaError,
"rpc_error" => MessageKind::RpcError,
"return_prompt" => MessageKind::ReturnPrompt,
"quickfix" => MessageKind::QuickFix,
"search_count" => MessageKind::SearchCount,
"wmsg" => MessageKind::Warning,
_ => MessageKind::Unknown
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum RedrawEvent { pub enum RedrawEvent {
SetTitle { title: String }, SetTitle { title: String },
@ -57,7 +95,14 @@ pub enum RedrawEvent {
GridLine { grid: u64, row: u64, column_start: u64, cells: Vec<GridLineCell> }, GridLine { grid: u64, row: u64, column_start: u64, cells: Vec<GridLineCell> },
Clear { grid: u64 }, Clear { grid: u64 },
CursorGoto { grid: u64, row: u64, column: u64 }, CursorGoto { grid: u64, row: u64, column: u64 },
Scroll { grid: u64, top: u64, bottom: u64, left: u64, right: u64, rows: i64, columns: i64 } Scroll { grid: u64, top: u64, bottom: u64, left: u64, right: u64, rows: i64, columns: i64 },
CommandLineShow { content: Vec<(Style, String)>, position: u64, first_character: String, prompt: String, indent: u64, level: u64 },
CommandLinePosition { position: u64, level: u64 },
CommandLineSpecialCharacter { character: String, shift: bool, level: u64 },
CommandLineHide,
CommandLineBlockShow { lines: Vec<Vec<(Style, String)>> },
CommandLineBlockAppend { line: Vec<(Style, String)> },
CommandLineBlockHide
} }
fn unpack_color(packed_color: u64) -> Color4f { fn unpack_color(packed_color: u64) -> Color4f {
@ -113,6 +158,14 @@ fn parse_i64(i64_value: &Value) -> Result<i64> {
} }
} }
fn parse_bool(bool_value: &Value) -> Result<bool> {
if let Value::Boolean(content) = bool_value.clone() {
Ok(content)
} else {
Err(EventParseError::InvalidBool(bool_value.clone()))
}
}
fn parse_set_title(set_title_arguments: Vec<Value>) -> Result<RedrawEvent> { fn parse_set_title(set_title_arguments: Vec<Value>) -> Result<RedrawEvent> {
if let [title] = set_title_arguments.as_slice() { if let [title] = set_title_arguments.as_slice() {
Ok(RedrawEvent::SetTitle { Ok(RedrawEvent::SetTitle {
@ -188,10 +241,8 @@ fn parse_default_colors(default_colors_arguments: Vec<Value>) -> Result<RedrawEv
} }
} }
fn parse_hl_attr_define(hl_attr_define_arguments: Vec<Value>) -> Result<RedrawEvent> { fn parse_style(style_map: &Value) -> Result<Style> {
if let [ if let Value::Map(attributes) = style_map {
id, Value::Map(attributes), _terminal_attributes, _info
] = hl_attr_define_arguments.as_slice() {
let mut style = Style::new(Colors::new(None, None, None)); let mut style = Style::new(Colors::new(None, None, None));
for attribute in attributes { for attribute in attributes {
if let (Value::String(name), value) = attribute { if let (Value::String(name), value) = attribute {
@ -212,6 +263,17 @@ fn parse_hl_attr_define(hl_attr_define_arguments: Vec<Value>) -> Result<RedrawEv
println!("Invalid attribute format"); println!("Invalid attribute format");
} }
} }
Ok(style)
} else {
Err(EventParseError::InvalidMap(style_map.clone()))
}
}
fn parse_hl_attr_define(hl_attr_define_arguments: Vec<Value>) -> Result<RedrawEvent> {
if let [
id, attributes, _terminal_attributes, _info
] = hl_attr_define_arguments.as_slice() {
let style = parse_style(attributes)?;
Ok(RedrawEvent::HighlightAttributesDefine { id: parse_u64(&id)?, style }) Ok(RedrawEvent::HighlightAttributesDefine { id: parse_u64(&id)?, style })
} else { } else {
Err(EventParseError::InvalidEventFormat) Err(EventParseError::InvalidEventFormat)
@ -274,6 +336,77 @@ fn parse_grid_scroll(grid_scroll_arguments: Vec<Value>) -> Result<RedrawEvent> {
} }
} }
fn parse_commandline_chunks(line: &Value) -> Result<Vec<(Style, String)>> {
parse_array(line)?.iter().map(|tuple| {
if let [attributes, text] = parse_array(tuple)?.as_slice() {
Ok((parse_style(attributes)?, parse_string(text)?))
} else {
Err(EventParseError::InvalidEventFormat)
}
}).collect::<Result<Vec<(Style, String)>>>()
}
fn parse_cmdline_show(cmdline_show_arguments: Vec<Value>) -> Result<RedrawEvent> {
if let [content, position, first_character, prompt, indent, level] = cmdline_show_arguments.as_slice() {
Ok(RedrawEvent::CommandLineShow {
content: parse_commandline_chunks(&content)?,
position: parse_u64(&position)?,
first_character: parse_string(&first_character)?,
prompt: parse_string(&prompt)?,
indent: parse_u64(&indent)?,
level: parse_u64(&level)?
})
} else {
Err(EventParseError::InvalidEventFormat)
}
}
fn parse_cmdline_pos(cmdline_pos_arguments: Vec<Value>) -> Result<RedrawEvent> {
if let [position, level] = cmdline_pos_arguments.as_slice() {
Ok(RedrawEvent::CommandLinePosition {
position: parse_u64(&position)?,
level: parse_u64(&level)?
})
} else {
Err(EventParseError::InvalidEventFormat)
}
}
fn parse_cmdline_special_char(cmdline_special_char_arguments: Vec<Value>) -> Result<RedrawEvent> {
if let [character, shift, level] = cmdline_special_char_arguments.as_slice() {
Ok(RedrawEvent::CommandLineSpecialCharacter {
character: parse_string(&character)?,
shift: parse_bool(&shift)?,
level: parse_u64(&level)?
})
} else {
Err(EventParseError::InvalidEventFormat)
}
}
fn parse_cmdline_block_show(cmdline_block_show_arguments: Vec<Value>) -> Result<RedrawEvent> {
if let [lines] = cmdline_block_show_arguments.as_slice() {
Ok(RedrawEvent::CommandLineBlockShow {
lines: parse_array(&lines)?
.iter()
.map(parse_commandline_chunks)
.collect::<Result<Vec<Vec<(Style, String)>>>>()?
})
} else {
Err(EventParseError::InvalidEventFormat)
}
}
fn parse_cmdline_block_append(cmdline_block_append_arguments: Vec<Value>) -> Result<RedrawEvent> {
if let [line] = cmdline_block_append_arguments.as_slice() {
Ok(RedrawEvent::CommandLineBlockAppend {
line: parse_commandline_chunks(&line)?
})
} else {
Err(EventParseError::InvalidEventFormat)
}
}
pub fn parse_redraw_event(event_value: Value) -> Result<Vec<RedrawEvent>> { pub fn parse_redraw_event(event_value: Value) -> Result<Vec<RedrawEvent>> {
let event_contents = parse_array(&event_value)?.to_vec(); let event_contents = parse_array(&event_value)?.to_vec();
let name_value = event_contents.get(0).ok_or(EventParseError::InvalidEventFormat)?; let name_value = event_contents.get(0).ok_or(EventParseError::InvalidEventFormat)?;
@ -299,6 +432,19 @@ pub fn parse_redraw_event(event_value: Value) -> Result<Vec<RedrawEvent>> {
"grid_clear" => Some(parse_clear(event_parameters)?), "grid_clear" => Some(parse_clear(event_parameters)?),
"grid_cursor_goto" => Some(parse_cursor_goto(event_parameters)?), "grid_cursor_goto" => Some(parse_cursor_goto(event_parameters)?),
"grid_scroll" => Some(parse_grid_scroll(event_parameters)?), "grid_scroll" => Some(parse_grid_scroll(event_parameters)?),
"cmdline_show" => Some(parse_cmdline_show(event_parameters)?),
"cmdline_pos" => Some(parse_cmdline_pos(event_parameters)?),
"cmdline_special_char" => Some(parse_cmdline_special_char(event_parameters)?),
"cmdline_hide" => Some(RedrawEvent::CommandLineHide),
"cmdline_block_show" => Some(parse_cmdline_block_show(event_parameters)?),
"cmdline_block_append" => Some(parse_cmdline_block_append(event_parameters)?),
"cmdline_block_hide" => Some(RedrawEvent::CommandLineBlockHide),
// "msg_show" => Some(parse_msg_show(event_parameters)?),
// "msg_clear" => Some(parse_msg_clear(event_parameters)?),
// "msg_showmode" => Some(parse_msg_showmode(event_parameters)?),
// "msg_showcmd" => Some(parse_msg_showcmd(event_parameters)?),
// "msg_ruler" => Some(parse_msg_ruler(event_parameters)?),
// "msg_history_show" => Some(parse_msg_history_show(event_parameters)?),
_ => None _ => None
}; };

@ -1,4 +1,4 @@
// #![windows_subsystem = "windows"] #![windows_subsystem = "windows"]
mod editor; mod editor;
mod events; mod events;

@ -12,12 +12,51 @@ use crate::editor::{Editor, CursorShape, Style, Colors};
const FONT_NAME: &str = "Delugia Nerd Font"; const FONT_NAME: &str = "Delugia Nerd Font";
const FONT_SIZE: f32 = 14.0; const FONT_SIZE: f32 = 14.0;
struct Fonts {
pub name: String,
pub size: f32,
pub normal: Font,
pub bold: Font,
pub italic: Font,
pub bold_italic: Font
}
impl Fonts {
fn new(name: &str, size: f32) -> Fonts {
Fonts {
name: name.to_string(),
size,
normal: Font::from_typeface(
Typeface::new(name, FontStyle::normal()).expect("Could not load normal font file"),
size),
bold: Font::from_typeface(
Typeface::new(name, FontStyle::bold()).expect("Could not load bold font file"),
size),
italic: Font::from_typeface(
Typeface::new(name, FontStyle::italic()).expect("Could not load italic font file"),
size),
bold_italic: Font::from_typeface(
Typeface::new(name, FontStyle::bold_italic()).expect("Could not load bold italic font file"),
size)
}
}
fn get(&self, style: &Style) -> &Font {
match (style.bold, style.italic) {
(false, false) => &self.normal,
(true, false) => &self.bold,
(false, true) => &self.italic,
(true, true) => &self.bold_italic
}
}
}
pub struct Renderer { pub struct Renderer {
editor: Arc<Mutex<Editor>>, editor: Arc<Mutex<Editor>>,
surface: Option<Surface>, surface: Option<Surface>,
paint: Paint, paint: Paint,
font: Font, fonts: Fonts,
shaper: CachingShaper, shaper: CachingShaper,
pub font_width: f32, pub font_width: f32,
@ -30,17 +69,16 @@ impl Renderer {
let surface = None; let surface = None;
let mut paint = Paint::new(colors::WHITE, None); let mut paint = Paint::new(colors::WHITE, None);
paint.set_anti_alias(false); paint.set_anti_alias(false);
let typeface = Typeface::new(FONT_NAME, FontStyle::default()).expect("Could not load font file."); let fonts = Fonts::new(FONT_NAME, FONT_SIZE);
let font = Font::from_typeface(typeface, FONT_SIZE);
let shaper = CachingShaper::new(); let shaper = CachingShaper::new();
let (_, bounds) = font.measure_str("_", Some(&paint)); let (_, bounds) = fonts.normal.measure_str("_", Some(&paint));
let font_width = bounds.width(); let font_width = bounds.width();
let (_, metrics) = font.metrics(); let (_, metrics) = fonts.normal.metrics();
let font_height = metrics.descent - metrics.ascent; let font_height = metrics.descent - metrics.ascent;
let cursor_pos = (0.0, 0.0); let cursor_pos = (0.0, 0.0);
Renderer { editor, surface, paint, font, shaper, font_width, font_height, cursor_pos } Renderer { editor, surface, paint, fonts, shaper, font_width, font_height, cursor_pos }
} }
fn draw_background(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), style: &Style, default_colors: &Colors) { fn draw_background(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), style: &Style, default_colors: &Colors) {
@ -61,7 +99,7 @@ impl Renderer {
let width = text.chars().count() as f32 * self.font_width; let width = text.chars().count() as f32 * self.font_width;
if style.underline || style.undercurl { if style.underline || style.undercurl {
let (_, metrics) = self.font.metrics(); let (_, metrics) = self.fonts.get(style).metrics();
let line_position = metrics.underline_position().unwrap(); let line_position = metrics.underline_position().unwrap();
self.paint.set_color(style.special(&default_colors).to_color()); self.paint.set_color(style.special(&default_colors).to_color());
@ -71,7 +109,7 @@ impl Renderer {
self.paint.set_color(style.foreground(&default_colors).to_color()); self.paint.set_color(style.foreground(&default_colors).to_color());
let text = text.trim_end(); let text = text.trim_end();
if text.len() > 0 { if text.len() > 0 {
let blob = self.shaper.shape_cached(text.to_string(), &self.font); let blob = self.shaper.shape_cached(text.to_string(), self.fonts.get(style));
canvas.draw_text_blob(blob, (x, y), &self.paint); canvas.draw_text_blob(blob, (x, y), &self.paint);
} }
} }
@ -91,7 +129,6 @@ impl Renderer {
} }
let mut surface = self.surface.take().unwrap_or_else(|| { let mut surface = self.surface.take().unwrap_or_else(|| {
dbg!("rebuild surface");
let mut context = gpu_canvas.gpu_context().unwrap(); let mut context = gpu_canvas.gpu_context().unwrap();
let budgeted = Budgeted::YES; let budgeted = Budgeted::YES;
let image_info = gpu_canvas.image_info(); let image_info = gpu_canvas.image_info();
@ -150,7 +187,7 @@ impl Renderer {
.map(|(character, _)| character) .map(|(character, _)| character)
.unwrap_or(' '); .unwrap_or(' ');
gpu_canvas.draw_text_blob( gpu_canvas.draw_text_blob(
self.shaper.shape_cached(character.to_string(), &self.font), self.shaper.shape_cached(character.to_string(), &self.fonts.normal),
(cursor_x, cursor_y), &self.paint); (cursor_x, cursor_y), &self.paint);
} }
} }

Loading…
Cancel
Save