syntax highlight rendering, highlighting demo

This commit is contained in:
Anton-4 2021-01-15 18:13:05 +01:00
parent 729e3e358b
commit 30b87a1c93
7 changed files with 133 additions and 13 deletions

View file

@ -60,6 +60,7 @@ These are potentially inspirational resources for the editor's design.
* Automatically create all "arms" when pattern matching after entering `when var is` based on the type. * Automatically create all "arms" when pattern matching after entering `when var is` based on the type.
- All `when ... is` should be updated if the type is changed, e.g. adding Indigo to the Color type should add an arm everywhere where `when color is` is used. - All `when ... is` should be updated if the type is changed, e.g. adding Indigo to the Color type should add an arm everywhere where `when color is` is used.
* When a function is called like `foo(false)`, the name of the boolean argument should be shown automatically; `foo(`*is_active:*`false)`. This should be done for booleans and numbers. * When a function is called like `foo(false)`, the name of the boolean argument should be shown automatically; `foo(`*is_active:*`false)`. This should be done for booleans and numbers.
* Suggest automatically creating a function if the compiler says it does not exist.
### Non-Code Related Inspiration ### Non-Code Related Inspiration

View file

@ -1,11 +1,14 @@
pub const WHITE: (f32, f32, f32, f32) = (1.0, 1.0, 1.0, 1.0);
pub const TXT_COLOR: (f32, f32, f32, f32) = (1.0, 1.0, 1.0, 1.0);
pub const CODE_COLOR: (f32, f32, f32, f32) = (0.21, 0.55, 0.83, 1.0);
pub const CARET_COLOR: (f32, f32, f32, f32) = WHITE;
pub const SELECT_COLOR: (f32, f32, f32, f32) = (0.45, 0.61, 1.0, 1.0);
pub const BG_COLOR: (f32, f32, f32, f32) = (0.11, 0.11, 0.13, 1.0);
pub fn to_wgpu_color((r, g, b, a): (f32, f32, f32, f32)) -> wgpu::Color { pub type ColorTup = (f32, f32, f32, f32);
pub const WHITE: ColorTup = (1.0, 1.0, 1.0, 1.0);
pub const BLACK: ColorTup = (0.0, 0.0, 0.0, 1.0);
pub const TXT_COLOR: ColorTup = (1.0, 1.0, 1.0, 1.0);
pub const CODE_COLOR: ColorTup = (0.21, 0.55, 0.83, 1.0);
pub const CARET_COLOR: ColorTup = WHITE;
pub const SELECT_COLOR: ColorTup = (0.45, 0.61, 1.0, 1.0);
pub const BG_COLOR: ColorTup = (0.11, 0.11, 0.13, 1.0);
pub fn to_wgpu_color((r, g, b, a): ColorTup) -> wgpu::Color {
wgpu::Color { wgpu::Color {
r: r as f64, r: r as f64,
g: g as f64, g: g as f64,
@ -14,6 +17,6 @@ pub fn to_wgpu_color((r, g, b, a): (f32, f32, f32, f32)) -> wgpu::Color {
} }
} }
pub fn to_slice((r, g, b, a): (f32, f32, f32, f32)) -> [f32; 4] { pub fn to_slice((r, g, b, a): ColorTup) -> [f32; 4] {
[r, g, b, a] [r, g, b, a]
} }

View file

@ -2,3 +2,4 @@ pub mod colors;
pub mod lowlevel; pub mod lowlevel;
pub mod primitives; pub mod primitives;
pub mod style; pub mod style;
mod syntax_highlight;

View file

@ -2,12 +2,15 @@
// by Benjamin Hansen, licensed under the MIT license // by Benjamin Hansen, licensed under the MIT license
use super::rect::Rect; use super::rect::Rect;
use crate::graphics::colors::{CODE_COLOR, WHITE}; use crate::graphics::colors;
use colors::{CODE_COLOR, WHITE, ColorTup};
use crate::graphics::style::{CODE_FONT_SIZE, CODE_TXT_XY}; use crate::graphics::style::{CODE_FONT_SIZE, CODE_TXT_XY};
use crate::graphics::syntax_highlight;
use ab_glyph::{FontArc, Glyph, InvalidFont}; use ab_glyph::{FontArc, Glyph, InvalidFont};
use cgmath::{Vector2, Vector4}; use cgmath::{Vector2, Vector4};
use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section}; use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section};
#[derive(Debug)] #[derive(Debug)]
pub struct Text { pub struct Text {
pub position: Vector2<f32>, pub position: Vector2<f32>,
@ -82,7 +85,28 @@ fn section_from_text(
) )
} }
// returns glyphs per line fn section_from_glyph_text(
text: Vec<wgpu_glyph::Text>,
screen_position: (f32, f32),
area_bounds: (f32, f32),
layout: wgpu_glyph::Layout<wgpu_glyph::BuiltInLineBreaker>,
) -> wgpu_glyph::Section {
Section {
screen_position,
bounds: area_bounds,
layout,
text
}
}
fn colored_text_to_glyph_text<'a>(text_tups: &'a [(String, ColorTup)]) -> Vec<wgpu_glyph::Text<'a>> {
text_tups.iter().map(|(word_string, color_tup)| {
wgpu_glyph::Text::new(&word_string)
.with_color(colors::to_slice(*color_tup))
.with_scale(CODE_FONT_SIZE)
}).collect()
}
pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) { pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) {
let layout = layout_from_text(text); let layout = layout_from_text(text);
@ -91,6 +115,23 @@ pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) {
glyph_brush.queue(section.clone()); glyph_brush.queue(section.clone());
} }
pub fn queue_code_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) {
let layout = layout_from_text(text);
let mut all_text_tups: Vec<(String, ColorTup)> = Vec::new();
syntax_highlight::highlight_code(text, &mut all_text_tups);
let glyph_text_vec = colored_text_to_glyph_text(&all_text_tups);
let section = section_from_glyph_text(
glyph_text_vec,
text.position.into(),
text.area_bounds.into(),
layout
);
glyph_brush.queue(section.clone());
}
fn glyph_to_rect(glyph: &wgpu_glyph::SectionGlyph) -> Rect { fn glyph_to_rect(glyph: &wgpu_glyph::SectionGlyph) -> Rect {
let position = glyph.glyph.position; let position = glyph.glyph.position;
let px_scale = glyph.glyph.scale; let px_scale = glyph.glyph.scale;

View file

@ -1,2 +1,2 @@
pub const CODE_FONT_SIZE: f32 = 30.0; pub const CODE_FONT_SIZE: f32 = 30.0;
pub const CODE_TXT_XY: (f32, f32) = (30.0, 90.0); pub const CODE_TXT_XY: (f32, f32) = (30.0, 30.0);

View file

@ -0,0 +1,74 @@
use crate::graphics::primitives;
use crate::graphics::colors;
use colors::ColorTup;
//TODO optimize memory allocation
//TODO this is a demo function, the AST should be used for highlighting, see #904.
pub fn highlight_code(code_text: &primitives::text::Text, all_text_tups: &mut Vec<(String, ColorTup)>) {
let split_code = split_inclusive(&code_text.text);
let mut active_color = colors::WHITE;
let mut same_type_str = String::new();
for token_seq in split_code {
let new_word_color = if token_seq.contains(&'\"'.to_string()) {
colors::CODE_COLOR
} else if token_seq.contains(&'='.to_string()) {
colors::BLACK
} else {
colors::WHITE
};
if new_word_color != active_color {
all_text_tups.push(
(
same_type_str,
active_color
)
);
active_color = new_word_color;
same_type_str = String::new();
}
same_type_str.push_str(&token_seq);
}
if !same_type_str.is_empty() {
all_text_tups.push(
(
same_type_str,
active_color
)
);
}
}
//TODO use rust's split_inclusive once rust 1.50 is released
fn split_inclusive(code_str: &str) -> Vec<String> {
let mut split_vec: Vec<String> = Vec::new();
let mut temp_str = String::new();
let mut non_space_encountered = false;
for token in code_str.chars() {
if token != ' ' && token != '\n' {
non_space_encountered = true;
temp_str.push(token);
} else if non_space_encountered {
split_vec.push(temp_str);
temp_str = String::new();
temp_str.push(token);
non_space_encountered = false;
} else {
temp_str.push(token);
}
}
if !temp_str.is_empty() {
split_vec.push(temp_str);
}
split_vec
}

View file

@ -19,7 +19,7 @@ use crate::graphics::lowlevel::buffer::create_rect_buffers;
use crate::graphics::lowlevel::ortho::update_ortho_buffer; use crate::graphics::lowlevel::ortho::update_ortho_buffer;
use crate::graphics::lowlevel::pipelines; use crate::graphics::lowlevel::pipelines;
use crate::graphics::primitives::text::{ use crate::graphics::primitives::text::{
build_glyph_brush, example_code_glyph_rect, queue_text_draw, Text, build_glyph_brush, example_code_glyph_rect, queue_text_draw, queue_code_text_draw, Text,
}; };
use crate::graphics::style::CODE_FONT_SIZE; use crate::graphics::style::CODE_FONT_SIZE;
use crate::graphics::style::CODE_TXT_XY; use crate::graphics::style::CODE_TXT_XY;
@ -392,7 +392,7 @@ fn queue_editor_text(
queue_text_draw(&caret_pos_label, glyph_brush); queue_text_draw(&caret_pos_label, glyph_brush);
queue_text_draw(&code_text, glyph_brush); queue_code_text_draw(&code_text, glyph_brush);
} }
fn queue_no_file_text( fn queue_no_file_text(