sync commit
This commit is contained in:
parent
381721013e
commit
827af45ab9
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue