mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
rewrite to support multi line selection(unfinished)
This commit is contained in:
parent
fc310cf974
commit
7a70c95bb4
8 changed files with 169 additions and 30 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2649,6 +2649,7 @@ dependencies = [
|
||||||
"indoc",
|
"indoc",
|
||||||
"inkwell",
|
"inkwell",
|
||||||
"inlinable_string",
|
"inlinable_string",
|
||||||
|
"itertools",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"maplit",
|
"maplit",
|
||||||
|
|
|
@ -62,6 +62,7 @@ env_logger = "0.7"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
wgpu_glyph = "0.10"
|
wgpu_glyph = "0.10"
|
||||||
cgmath = "0.17.0"
|
cgmath = "0.17.0"
|
||||||
|
itertools = "0.9.0"
|
||||||
|
|
||||||
[dependencies.bytemuck]
|
[dependencies.bytemuck]
|
||||||
version = "1.4"
|
version = "1.4"
|
||||||
|
|
|
@ -73,8 +73,12 @@ These are potentially inspirational resources for the editor's design.
|
||||||
* Voice input:
|
* Voice input:
|
||||||
* Good for accessibility.
|
* Good for accessibility.
|
||||||
* https://www.youtube.com/watch?v=Ffa3cXM7bjc is interesting for inspiration.
|
* https://www.youtube.com/watch?v=Ffa3cXM7bjc is interesting for inspiration.
|
||||||
* Describe actions instead of using complicated shortcuts.
|
|
||||||
* Could be efficient way to communicate with smart assistant.
|
* Could be efficient way to communicate with smart assistant.
|
||||||
|
* Describe actions to execute them, examples:
|
||||||
|
* Add latest datetime package to dependencies.
|
||||||
|
* Generate unit test for this function.
|
||||||
|
* Show edit history for this function.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## General Thoughts/Ideas
|
## General Thoughts/Ideas
|
||||||
|
|
2
editor/src/colors.rs
Normal file
2
editor/src/colors.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
pub const WHITE: [f32; 3] = [1.0, 1.0, 1.0];
|
12
editor/src/error.rs
Normal file
12
editor/src/error.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use std::{error::Error, fmt};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OutOfBounds;
|
||||||
|
|
||||||
|
impl Error for OutOfBounds {}
|
||||||
|
|
||||||
|
impl fmt::Display for OutOfBounds {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "TODO proper error")
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,8 @@ use std::path::Path;
|
||||||
use winit::event;
|
use winit::event;
|
||||||
use winit::event::{Event, ModifiersState};
|
use winit::event::{Event, ModifiersState};
|
||||||
use winit::event_loop::ControlFlow;
|
use winit::event_loop::ControlFlow;
|
||||||
|
use error::{OutOfBounds};
|
||||||
|
use vec_result::{get_res};
|
||||||
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
mod buffer;
|
mod buffer;
|
||||||
|
@ -34,6 +36,9 @@ pub mod text;
|
||||||
mod types;
|
mod types;
|
||||||
mod util;
|
mod util;
|
||||||
mod vertex;
|
mod vertex;
|
||||||
|
mod colors;
|
||||||
|
pub mod error;
|
||||||
|
mod vec_result;
|
||||||
|
|
||||||
/// The editor is actually launched from the CLI if you pass it zero arguments,
|
/// The editor is actually launched from the CLI if you pass it zero arguments,
|
||||||
/// or if you provide it 1 or more files or directories to open on launch.
|
/// or if you provide it 1 or more files or directories to open on launch.
|
||||||
|
@ -107,7 +112,7 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
|
||||||
let mut glyph_brush = build_glyph_brush(&gpu_device, render_format)?;
|
let mut glyph_brush = build_glyph_brush(&gpu_device, render_format)?;
|
||||||
|
|
||||||
let is_animating = true;
|
let is_animating = true;
|
||||||
let mut text_state = "A".to_owned();
|
let mut text_state = "".to_owned();//String::new();
|
||||||
let mut keyboard_modifiers = ModifiersState::empty();
|
let mut keyboard_modifiers = ModifiersState::empty();
|
||||||
|
|
||||||
// Render loop
|
// Render loop
|
||||||
|
@ -201,11 +206,15 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
|
||||||
&mut glyph_brush,
|
&mut glyph_brush,
|
||||||
);
|
);
|
||||||
|
|
||||||
if !glyph_bounds_rects.is_empty() {
|
let selection_rects_res = create_selection_rects(1, 10, 2, 10, &glyph_bounds_rects);
|
||||||
|
|
||||||
|
match selection_rects_res {
|
||||||
|
Ok(selection_rects) =>
|
||||||
|
if !selection_rects.is_empty() {
|
||||||
let rect_buffers = create_rect_buffers(
|
let rect_buffers = create_rect_buffers(
|
||||||
&gpu_device,
|
&gpu_device,
|
||||||
&mut encoder,
|
&mut encoder,
|
||||||
&glyph_bounds_rects,
|
&selection_rects,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
@ -224,6 +233,8 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
|
||||||
render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1);
|
render_pass.draw_indexed(0..rect_buffers.num_rects, 0, 0..1);
|
||||||
|
|
||||||
drop(render_pass);
|
drop(render_pass);
|
||||||
|
},
|
||||||
|
Err(e) => println!("{:?}", e) //TODO draw error text on screen
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw all text
|
// draw all text
|
||||||
|
@ -257,6 +268,83 @@ fn run_event_loop() -> Result<(), Box<dyn Error>> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn create_selection_rects(
|
||||||
|
start_line: usize,
|
||||||
|
pos_in_start_line: usize,
|
||||||
|
stop_line: usize,
|
||||||
|
pos_in_stop_line: usize,
|
||||||
|
glyph_bound_rects: &Vec<Vec<Rect>>
|
||||||
|
) -> Result<Vec<Rect>, OutOfBounds> {
|
||||||
|
//TODO assert start_line <= stop_line, if start_line == stop_line => pos_in_start_line <= pos_in_stop_line
|
||||||
|
|
||||||
|
let mut all_rects = Vec::new();
|
||||||
|
|
||||||
|
if start_line == stop_line {
|
||||||
|
let start_glyph_rect =
|
||||||
|
get_res(
|
||||||
|
pos_in_start_line,
|
||||||
|
get_res(start_line, glyph_bound_rects)?
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let stop_glyph_rect =
|
||||||
|
get_res(
|
||||||
|
pos_in_stop_line,
|
||||||
|
get_res(stop_line, glyph_bound_rects)?
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let top_left_coords =
|
||||||
|
start_glyph_rect.top_left_coords;
|
||||||
|
|
||||||
|
let height = start_glyph_rect.height;
|
||||||
|
let width = (stop_glyph_rect.top_left_coords.x - start_glyph_rect.top_left_coords.x) + stop_glyph_rect.width;
|
||||||
|
|
||||||
|
all_rects.push(
|
||||||
|
Rect {
|
||||||
|
top_left_coords,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
color: colors::WHITE
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(all_rects)
|
||||||
|
} else {
|
||||||
|
let start_line = get_res(start_line, glyph_bound_rects)?;
|
||||||
|
|
||||||
|
let start_glyph_rect =
|
||||||
|
get_res(
|
||||||
|
pos_in_start_line,
|
||||||
|
start_line
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let stop_glyph_rect =
|
||||||
|
get_res(
|
||||||
|
start_line.len() - 1,
|
||||||
|
start_line
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let top_left_coords =
|
||||||
|
start_glyph_rect.top_left_coords;
|
||||||
|
|
||||||
|
let height = start_glyph_rect.height;
|
||||||
|
let width = (stop_glyph_rect.top_left_coords.x - start_glyph_rect.top_left_coords.x) + stop_glyph_rect.width;
|
||||||
|
|
||||||
|
all_rects.push(
|
||||||
|
Rect {
|
||||||
|
top_left_coords,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
color: colors::WHITE
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO loop rects if necessary and stop line rect
|
||||||
|
|
||||||
|
Ok(all_rects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn make_rect_pipeline(
|
fn make_rect_pipeline(
|
||||||
gpu_device: &wgpu::Device,
|
gpu_device: &wgpu::Device,
|
||||||
swap_chain_descr: &wgpu::SwapChainDescriptor,
|
swap_chain_descr: &wgpu::SwapChainDescriptor,
|
||||||
|
@ -321,11 +409,12 @@ fn create_render_pipeline(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns bounding boxes for every glyph
|
||||||
fn queue_all_text(
|
fn queue_all_text(
|
||||||
size: &winit::dpi::PhysicalSize<u32>,
|
size: &winit::dpi::PhysicalSize<u32>,
|
||||||
text_state: &str,
|
text_state: &str,
|
||||||
glyph_brush: &mut wgpu_glyph::GlyphBrush<()>,
|
glyph_brush: &mut wgpu_glyph::GlyphBrush<()>,
|
||||||
) -> Vec<Rect> {
|
) -> Vec<Vec<Rect>> {
|
||||||
let area_bounds = (size.width as f32, size.height as f32).into();
|
let area_bounds = (size.width as f32, size.height as f32).into();
|
||||||
|
|
||||||
let main_label = Text {
|
let main_label = Text {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// Adapted from https://github.com/sotrh/learn-wgpu
|
// Adapted from https://github.com/sotrh/learn-wgpu
|
||||||
// by Benjamin Hansen, licensed under the MIT license
|
// by Benjamin Hansen, licensed under the MIT license
|
||||||
|
|
||||||
use ab_glyph::{FontArc, InvalidFont};
|
use ab_glyph::{FontArc, InvalidFont, Glyph};
|
||||||
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};
|
||||||
use crate::rect::Rect;
|
use crate::rect::Rect;
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Text {
|
pub struct Text {
|
||||||
|
@ -31,7 +32,8 @@ impl Default for Text {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) -> Vec<Rect> {
|
// returns bounding boxes for every glyph
|
||||||
|
pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) -> Vec<Vec<Rect>> {
|
||||||
let layout = wgpu_glyph::Layout::default().h_align(if text.centered {
|
let layout = wgpu_glyph::Layout::default().h_align(if text.centered {
|
||||||
wgpu_glyph::HorizontalAlign::Center
|
wgpu_glyph::HorizontalAlign::Center
|
||||||
} else {
|
} else {
|
||||||
|
@ -57,17 +59,31 @@ pub fn queue_text_draw(text: &Text, glyph_brush: &mut GlyphBrush<()>) -> Vec<Rec
|
||||||
{
|
{
|
||||||
let position = section_glyph.glyph.position;
|
let position = section_glyph.glyph.position;
|
||||||
let px_scale = section_glyph.glyph.scale;
|
let px_scale = section_glyph.glyph.scale;
|
||||||
let width = px_scale.x * 0.5;
|
let width = glyph_width(§ion_glyph.glyph);
|
||||||
let height = px_scale.y;
|
let height = px_scale.y;
|
||||||
|
let top_y = glyph_top_y(§ion_glyph.glyph);
|
||||||
|
|
||||||
Rect {
|
Rect {
|
||||||
top_left_coords: [position.x, position.y - height * 0.75].into(),
|
top_left_coords: [position.x, top_y].into(),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
color: [1.0, 1.0, 1.0]
|
color: [1.0, 1.0, 1.0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).collect()
|
).group_by(|rect| rect.top_left_coords.y)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(_y_coord, rect_group)| rect_group.collect())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn glyph_top_y(glyph: &Glyph) -> f32 {
|
||||||
|
let height = glyph.scale.y;
|
||||||
|
|
||||||
|
glyph.position.y - height * 0.75
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn glyph_width(glyph: &Glyph) -> f32 {
|
||||||
|
glyph.scale.x * 0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_glyph_brush(
|
pub fn build_glyph_brush(
|
||||||
|
|
14
editor/src/vec_result.rs
Normal file
14
editor/src/vec_result.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
use crate::error::{OutOfBounds};
|
||||||
|
use std::slice::SliceIndex;
|
||||||
|
|
||||||
|
// replace vec methods that return Option with Result and proper Error
|
||||||
|
|
||||||
|
pub fn get_res<T>(indx: usize, vec: &Vec<T>) -> Result<&<usize as SliceIndex<[T]>>::Output, OutOfBounds> {
|
||||||
|
match vec.get(indx) {
|
||||||
|
Some(elt) =>
|
||||||
|
Ok(elt),
|
||||||
|
None =>
|
||||||
|
Err(OutOfBounds {})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue