sync commit

This commit is contained in:
Joe Bellus 2022-10-10 10:59:54 -04:00
parent 381721013e
commit 827af45ab9
2 changed files with 81 additions and 52 deletions

View File

@ -1,8 +1,8 @@
use std::ops::Range;
use druid::{
piet::{Text, TextAttribute, TextLayout, TextLayoutBuilder},
Color, Data, Event, FontFamily, Lens, LifeCycle, Rect, RenderContext, Widget,
piet::{CairoTextLayout, Text, TextAttribute, TextLayout, TextLayoutBuilder},
Color, Data, Event, FontFamily, Lens, LifeCycle, PaintCtx, Rect, RenderContext, Widget,
};
use ropey::Rope;
@ -14,10 +14,9 @@ use syntect::parsing::SyntaxSet;
pub enum EditMode {
Normal,
Insert,
Visual,
}
pub struct AbacusEditor;
#[derive(Data, Lens, Clone)]
pub struct EditorData {
#[data(same_fn = "PartialEq::eq")]
@ -155,55 +154,24 @@ impl EditorData {
self.selection_pos = self.content.len_chars();
self.cursor_pos = 0;
}
pub fn select_left(&mut self) {
if self.cursor_pos > 0 {
self.selection_pos = self.cursor_pos - 1;
}
}
pub fn select_right(&mut self) {
if self.cursor_pos < self.content.len_chars() {
self.selection_pos = self.cursor_pos + 1;
}
}
}
impl Widget<EditorData> for AbacusEditor {
fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &EditorData, _env: &druid::Env) {
let size = ctx.size();
let rect = size.to_rect();
pub struct AbacusEditor;
if ctx.is_focused() {
ctx.fill(rect, &Color::rgb8(10, 10, 10));
} else {
ctx.fill(rect, &Color::rgb8(20, 20, 20));
}
if data.content.len_chars() == 0 {
return;
}
let ps = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
let syntax = ps.find_syntax_by_extension("rs").unwrap();
let mut h = HighlightLines::new(syntax, &ts.themes["base16-mocha.dark"]);
let mut layout = ctx
.text()
.new_text_layout(data.content.to_string())
.font(FontFamily::MONOSPACE, 22.0);
let mut pos = 0;
for line in data.content.lines() {
let s = line.to_string();
let ranges: Vec<(Style, &str)> = h.highlight_line(&s, &ps).unwrap();
for (style, txt) in ranges {
layout = layout.range_attribute(
pos..(pos + txt.len()),
TextAttribute::TextColor(Color::rgba8(
style.foreground.r,
style.foreground.g,
style.foreground.b,
style.foreground.a,
)),
);
pos += txt.len();
}
}
let layout = layout.build().unwrap();
// paint cursor
impl AbacusEditor {
fn paint_cursor(&self, ctx: &mut PaintCtx, data: &EditorData, layout: &CairoTextLayout) {
if data.mode == EditMode::Insert {
if let Some(char_rect) = layout
.rects_for_range((data.cursor_pos.max(1) - 1)..data.cursor_pos)
@ -247,6 +215,63 @@ impl Widget<EditorData> for AbacusEditor {
};
}
}
}
pub fn build_highlighted_layout(
&self,
ctx: &mut PaintCtx,
data: &EditorData,
) -> CairoTextLayout {
let ps = SyntaxSet::load_defaults_newlines();
let ts = ThemeSet::load_defaults();
let syntax = ps.find_syntax_by_extension("rs").unwrap();
let mut h = HighlightLines::new(syntax, &ts.themes["base16-mocha.dark"]);
let mut layout = ctx
.text()
.new_text_layout(data.content.to_string())
.font(FontFamily::MONOSPACE, 22.0);
let mut pos = 0;
for line in data.content.lines() {
let s = line.to_string();
let ranges: Vec<(Style, &str)> = h.highlight_line(&s, &ps).unwrap();
for (style, txt) in ranges {
layout = layout.range_attribute(
pos..(pos + txt.len()),
TextAttribute::TextColor(Color::rgba8(
style.foreground.r,
style.foreground.g,
style.foreground.b,
style.foreground.a,
)),
);
pos += txt.len();
}
}
layout.build().unwrap()
}
}
impl Widget<EditorData> for AbacusEditor {
fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &EditorData, _env: &druid::Env) {
let size = ctx.size();
let rect = size.to_rect();
if ctx.is_focused() {
ctx.fill(rect, &Color::rgb8(10, 10, 10));
} else {
ctx.fill(rect, &Color::rgb8(20, 20, 20));
}
if data.content.len_chars() == 0 {
return;
}
let layout = self.build_highlighted_layout(ctx, data);
self.paint_cursor(ctx, data, &layout);
if data.selection_pos != data.cursor_pos {
let rects = layout.rects_for_range(data.select_range());
@ -255,7 +280,7 @@ impl Widget<EditorData> for AbacusEditor {
}
}
ctx.draw_text(&layout, (1.0, 1.0));
ctx.draw_text(&layout, (0.0, 0.0));
}
fn event(
@ -325,6 +350,10 @@ impl Widget<EditorData> for AbacusEditor {
druid::keyboard_types::Key::Escape => {
data.mode = EditMode::Normal;
}
druid::keyboard_types::Key::ArrowLeft if e.mods.shift() => {
data.select_left();
}
druid::keyboard_types::Key::ArrowLeft if !e.mods.shift() => {
data.cursor_left();
}

View File

@ -7,7 +7,7 @@ fn build_ui() -> impl Widget<editor::EditorData> {
Padding::new(
10.0,
Flex::column()
.with_flex_child(Padding::new(10.0, editor::AbacusEditor), 2.0)
.with_flex_child(editor::AbacusEditor, 2.0)
.with_flex_child(editor::AbacusEditor, 1.0),
)
}