more progress toward externalized command bar

macos-click-through
Keith Simmons 5 years ago
parent 1a12766861
commit 22ddb545a9

@ -1,27 +1,101 @@
use crate::events::{GridLineCell, RedrawEvent, StyledContent};
use std::collections::HashMap;
use crate::events::{RedrawEvent, StyledContent};
use crate::editor::{DrawCommand, Style};
pub struct CommandLine {
visible: bool,
prefix: String,
content: StyledContent,
cursor_position: u64,
special_char: (String, bool),
special_char: Option<(String, bool)>,
block: Vec<StyledContent>
}
impl CommandLine {
pub fn new() -> CommandLine {
CommandLine {
visible: false,
prefix: String::new(),
content: Vec::new(),
cursor_position: 0,
special_char: None,
block: Vec::new()
}
}
pub fn draw(&self, window_size: (u64, u64), defined_styles: &HashMap<u64, Style>) -> Vec<DrawCommand> {
let mut draw_commands = Vec::new();
if self.content.len() > 0 {
let (width, height) = window_size;
let text_length: usize = self.content.iter().map(|(_, text)| text.len()).sum();
let x = (width / 2) - (text_length as u64 / 2);
let y = height / 2;
let mut start_x = x;
let mut commands = self.content.iter().map(|(style_id, text)| {
let command_width = text.len();
let style = defined_styles.get(style_id).map(|style| style.clone());
let command = DrawCommand::new(text.clone(), (start_x, y), style);
start_x = start_x + command_width as u64;
command
}).collect::<Vec<DrawCommand>>();
draw_commands.append(&mut commands);
}
draw_commands
}
pub fn handle_command_events(&mut self, event: RedrawEvent) {
match event {
RedrawEvent::CommandLineShow { content, position, first_character, prompt, indent, level } => {},
RedrawEvent::CommandLinePosition { position, level } => {},
RedrawEvent::CommandLineSpecialCharacter { character, shift, level } => {},
RedrawEvent::CommandLineHide => {},
RedrawEvent::CommandLineBlockShow { lines } => {},
RedrawEvent::CommandLineBlockAppend { line } => {},
RedrawEvent::CommandLineBlockHide => {}
RedrawEvent::CommandLineShow { content, position, first_character, prompt, indent, level } => self.show(content, position, first_character, prompt, indent, level),
RedrawEvent::CommandLinePosition { position, level } => self.set_position(position, level),
RedrawEvent::CommandLineSpecialCharacter { character, shift, level } => self.set_special_character(character, shift, level),
RedrawEvent::CommandLineHide => self.hide(),
RedrawEvent::CommandLineBlockShow { lines } => self.show_block(lines),
RedrawEvent::CommandLineBlockAppend { line } => self.append_line_to_block(line),
RedrawEvent::CommandLineBlockHide => self.hide_block(),
_ => {}
}
}
// fn show()
fn show(&mut self, content: StyledContent, position: u64, first_character: String, prompt: String, _indent: u64, _level: u64) {
let prefix;
if first_character.len() > 0 {
prefix = first_character;
} else {
prefix = prompt;
}
self.visible = true;
self.prefix = prefix;
self.content = content;
self.cursor_position = position;
self.block = Vec::new();
}
fn set_position(&mut self, position: u64, level: u64) {
self.cursor_position = position;
}
fn set_special_character(&mut self, character: String, shift: bool, _level: u64) {
self.special_char = Some((character, shift));
}
fn hide(&mut self) {
self.visible = false;
self.special_char = None;
}
fn show_block(&mut self, lines: Vec<StyledContent>) {
self.block = lines;
}
fn append_line_to_block(&mut self, line: StyledContent) {
self.block.push(line);
}
fn hide_block(&mut self) {
self.block.clear();
}
}

@ -9,15 +9,18 @@ mod command_line;
pub use cursor::{Cursor, CursorShape, CursorMode};
pub use style::{Colors, Style};
use command_line::CommandLine;
use crate::events::{GridLineCell, RedrawEvent};
pub type GridCell = Option<(char, Style)>;
pub type GridCell = Option<(char, Option<Style>)>;
#[derive(new, Debug, Clone)]
pub struct DrawCommand {
pub text: String,
pub grid_position: (u64, u64),
pub style: Style
pub style: Option<Style>,
#[new(value = "1")]
pub scale: u16
}
pub struct Editor {
@ -27,6 +30,7 @@ pub struct Editor {
pub window: Option<Arc<Window>>,
pub command_line: CommandLine,
pub title: String,
pub size: (u64, u64),
pub cursor: Cursor,
@ -44,6 +48,7 @@ impl Editor {
window: None,
command_line: CommandLine::new(),
title: "Neovide".to_string(),
cursor: Cursor::new(),
size: (width, height),
@ -71,7 +76,7 @@ impl Editor {
RedrawEvent::Clear { .. } => self.clear(),
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),
_ => {}
event => self.command_line.handle_command_events(event)
};
}
@ -86,14 +91,14 @@ impl Editor {
}
}
fn command_matches(command: &Option<DrawCommand>, style: &Style) -> bool {
fn command_matches(command: &Option<DrawCommand>, style: &Option<Style>) -> bool {
match command {
Some(command) => &command.style == style,
None => true
}
}
fn add_character(command: &mut Option<DrawCommand>, character: &char, row_index: u64, col_index: u64, style: Style) {
fn add_character(command: &mut Option<DrawCommand>, character: &char, row_index: u64, col_index: u64, style: Option<Style>) {
match command {
Some(command) => command.text.push(character.clone()),
None => {
@ -118,7 +123,7 @@ impl Editor {
}
let should_clear = self.should_clear;
let draw_commands = draw_commands.into_iter().filter(|command| {
let mut draw_commands = draw_commands.into_iter().filter(|command| {
let (x, y) = command.grid_position;
let dirty_row = &self.dirty[y as usize];
@ -130,6 +135,9 @@ impl Editor {
return false;
}).collect::<Vec<DrawCommand>>();
let mut command_line_draw_commands = self.command_line.draw(self.size, &self.defined_styles);
draw_commands.append(&mut command_line_draw_commands);
let (width, height) = self.size;
self.dirty = vec![vec![false; width as usize]; height as usize];
self.should_clear = false;
@ -137,11 +145,10 @@ impl Editor {
}
fn draw_grid_line_cell(&mut self, row_index: u64, column_pos: &mut u64, cell: GridLineCell) {
let style = match (cell.highlight_id, self.previous_style.clone()) {
(Some(0), _) => Style::new(self.default_colors.clone()),
(Some(style_id), _) => self.defined_styles.get(&style_id).expect("GridLineCell must use defined color").clone(),
(None, Some(previous_style)) => previous_style,
(None, None) => Style::new(self.default_colors.clone())
let style = match cell.highlight_id {
Some(0) => None,
Some(style_id) => self.defined_styles.get(&style_id).map(|style| style.clone()),
None => self.previous_style.clone()
};
let mut text = cell.text;
@ -160,7 +167,7 @@ impl Editor {
}
*column_pos = *column_pos + text.chars().count() as u64;
self.previous_style = Some(style);
self.previous_style = style;
}
fn draw_grid_line(&mut self, row: u64, column_start: u64, cells: Vec<GridLineCell>) {

@ -45,7 +45,7 @@ pub struct GridLineCell {
pub repeat: Option<u64>
}
pub type StyledContent = Vec<(Style, String)>;
pub type StyledContent = Vec<(u64, String)>;
#[derive(Debug)]
pub enum MessageKind {
@ -347,8 +347,8 @@ fn parse_grid_scroll(grid_scroll_arguments: Vec<Value>) -> Result<RedrawEvent> {
fn parse_styled_content(line: &Value) -> Result<StyledContent> {
parse_array(line)?.iter().map(|tuple| {
if let [attributes, text] = parse_array(tuple)?.as_slice() {
Ok((parse_style(attributes)?, parse_string(text)?))
if let [style_id, text] = parse_array(tuple)?.as_slice() {
Ok((parse_u64(style_id)?, parse_string(text)?))
} else {
Err(EventParseError::InvalidEventFormat)
}
@ -525,8 +525,6 @@ pub fn parse_redraw_event(event_value: Value) -> Result<Vec<RedrawEvent>> {
if let Some(parsed_event) = possible_parsed_event {
parsed_events.push(parsed_event);
} else {
println!("Did not parse {}", event_name);
}
}

@ -1,4 +1,4 @@
#![windows_subsystem = "windows"]
// #![windows_subsystem = "windows"]
mod editor;
mod events;
@ -47,7 +47,7 @@ fn start_nvim(editor: Arc<Mutex<Editor>>) -> Neovim {
let join_handle = session.take_dispatch_guard();
let mut nvim = Neovim::new(session);
let mut options = UiAttachOptions::new();
options.set_cmdline_external(false);
options.set_cmdline_external(true);
options.set_messages_external(false);
options.set_linegrid_external(true);
options.set_rgb(true);

@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use skulpin::CoordinateSystemHelper;
use skulpin::skia_safe::{Canvas, Paint, Surface, Budgeted, Rect, Typeface, Font, FontStyle, colors};
@ -51,12 +52,47 @@ impl Fonts {
}
}
struct FontLookup {
pub name: String,
pub base_size: f32,
pub loaded_fonts: HashMap<u16, Fonts>
}
impl FontLookup {
pub fn new(name: &str, base_size: f32) -> FontLookup {
let lookup = FontLookup {
name: name.to_string(),
base_size,
loaded_fonts: HashMap::new()
};
lookup.size(1);
lookup.size(2);
lookup.size(3);
lookup
}
fn size(&mut self, size_multiplier: u16) -> &Fonts {
match self.loaded_fonts.get(&size_multiplier) {
Some(fonts) => fonts,
None => {
let fonts = Fonts::new(
&self.name,
self.base_size * size_multiplier as f32);
self.loaded_fonts.insert(size_multiplier, fonts);
self.loaded_fonts.get(&size_multiplier).unwrap()
}
}
}
}
pub struct Renderer {
editor: Arc<Mutex<Editor>>,
surface: Option<Surface>,
paint: Paint,
fonts: Fonts,
fonts_lookup: FontLookup,
shaper: CachingShaper,
pub font_width: f32,
@ -69,37 +105,43 @@ impl Renderer {
let surface = None;
let mut paint = Paint::new(colors::WHITE, None);
paint.set_anti_alias(false);
let fonts = Fonts::new(FONT_NAME, FONT_SIZE);
let fonts_lookup = FontLookup::new(FONT_NAME, FONT_SIZE);
let shaper = CachingShaper::new();
let (_, bounds) = fonts.normal.measure_str("_", Some(&paint));
let base_fonts = fonts_lookup.size(1);
let (_, bounds) = base_fonts.normal.measure_str("_", Some(&paint));
let font_width = bounds.width();
let (_, metrics) = fonts.normal.metrics();
let (_, metrics) = base_fonts.normal.metrics();
let font_height = metrics.descent - metrics.ascent;
let cursor_pos = (0.0, 0.0);
Renderer { editor, surface, paint, fonts, shaper, font_width, font_height, cursor_pos }
Renderer { editor, surface, paint, fonts_lookup, 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), size: u16, style: &Option<Style>, default_colors: &Colors) {
let (grid_x, grid_y) = grid_pos;
let x = grid_x as f32 * self.font_width;
let y = grid_y as f32 * self.font_height;
let width = text.chars().count() as f32 * self.font_width;
let height = self.font_height;
let region = Rect::new(x, y, x + width, y + height);
let style = style.clone().unwrap_or(Style::new(default_colors.clone()));
self.paint.set_color(style.background(default_colors).to_color());
canvas.draw_rect(region, &self.paint);
}
fn draw_foreground(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), style: &Style, default_colors: &Colors) {
fn draw_foreground(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), size: u16, style: &Option<Style>, default_colors: &Colors) {
let (grid_x, grid_y) = grid_pos;
let x = grid_x as f32 * self.font_width;
let y = grid_y as f32 * self.font_height;
let width = text.chars().count() as f32 * self.font_width;
let style = style.clone().unwrap_or(Style::new(default_colors.clone()));
if style.underline || style.undercurl {
let (_, metrics) = self.fonts.get(style).metrics();
let (_, metrics) = self.fonts_lookup.size(scale).get(&style).metrics();
let line_position = metrics.underline_position().unwrap();
self.paint.set_color(style.special(&default_colors).to_color());
@ -109,7 +151,7 @@ impl Renderer {
self.paint.set_color(style.foreground(&default_colors).to_color());
let text = text.trim_end();
if text.len() > 0 {
let blob = self.shaper.shape_cached(text.to_string(), self.fonts.get(style));
let blob = self.shaper.shape_cached(text.to_string(), self.fonts.get(&style));
canvas.draw_text_blob(blob, (x, y), &self.paint);
}
}

@ -30,6 +30,8 @@ pub fn ui_loop(editor: Arc<Mutex<Editor>>, nvim: Neovim, initial_size: (u64, u64
.expect("Failed to create window"));
let mut skulpin_renderer = RendererBuilder::new()
.prefer_integrated_gpu()
.use_vulkan_debug_layer(true)
.coordinate_system(CoordinateSystem::Logical)
.build(&window)
.expect("Failed to create renderer");

Loading…
Cancel
Save