diff --git a/editor/editor-ideas.md b/editor/editor-ideas.md index e6bcbc10ac..d8b46da0c3 100644 --- a/editor/editor-ideas.md +++ b/editor/editor-ideas.md @@ -51,6 +51,7 @@ These are potentially inspirational resources for the editor's design. * [Blueprints](https://docs.unrealengine.com/en-US/Engine/Blueprints/index.html) visual scripting (not suggesting visual scripting for Roc) * [Live Programing](https://www.microsoft.com/en-us/research/project/live-programming/?from=http%3A%2F%2Fresearch.microsoft.com%2Fen-us%2Fprojects%2Fliveprogramming%2Ftypography.aspx#!publications) by [Microsoft Research] it contains many interesting research papers. +* When refactoring; cutting and pasting code to a new file should automatically add imports to the new file and delete them from the old file. ### Non-Code Related Inspiration diff --git a/editor/src/error.rs b/editor/src/error.rs index 569e62a4e4..23bde669ee 100644 --- a/editor/src/error.rs +++ b/editor/src/error.rs @@ -19,6 +19,14 @@ pub enum EdError { vec_len: usize, backtrace: Backtrace }, + #[snafu(display( + "InvalidSelection: {}", + err_msg + ))] + InvalidSelection { + err_msg: String, + backtrace: Backtrace + }, } pub type EdResult = std::result::Result; diff --git a/editor/src/lib.rs b/editor/src/lib.rs index 35b49096a3..78d36db8b5 100644 --- a/editor/src/lib.rs +++ b/editor/src/lib.rs @@ -12,7 +12,7 @@ use crate::buffer::create_rect_buffers; use crate::text::{build_glyph_brush, Text}; use crate::vertex::Vertex; use crate::rect::{Rect}; -use crate::error::{EdResult, print_err}; +use crate::error::{print_err}; use ortho::{init_ortho, update_ortho_buffer, OrthoResources}; use std::error::Error; use std::io; @@ -20,7 +20,7 @@ use std::path::Path; use winit::event; use winit::event::{Event, ModifiersState}; use winit::event_loop::ControlFlow; -use vec_result::{get_res}; +use selection::{create_selection_rects, RawSelection}; pub mod ast; mod buffer; @@ -39,6 +39,7 @@ mod vertex; mod colors; pub mod error; mod vec_result; +mod selection; /// 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. @@ -206,7 +207,14 @@ fn run_event_loop() -> Result<(), Box> { &mut glyph_brush, ); - let selection_rects_res = create_selection_rects(1, 5, 4, 2, &glyph_bounds_rects); + let selection = + RawSelection { + start_line_indx: 1, + pos_in_start_line: 3, + stop_line_indx: 4, + pos_in_stop_line: 5, + }; + let selection_rects_res = create_selection_rects(selection, &glyph_bounds_rects); match selection_rects_res { Ok(selection_rects) => @@ -269,146 +277,6 @@ fn run_event_loop() -> Result<(), Box> { } -fn create_selection_rects( - start_line_indx: usize, - pos_in_start_line: usize, - stop_line_indx: usize, - pos_in_stop_line: usize, - glyph_bound_rects: &Vec> -) -> EdResult> { - //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_indx == stop_line_indx { - let start_glyph_rect = - get_res( - pos_in_start_line, - get_res(start_line_indx, glyph_bound_rects)?, - )?; - - let stop_glyph_rect = - get_res( - pos_in_stop_line, - get_res(stop_line_indx, 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 { - // first line - let start_line = get_res(start_line_indx, glyph_bound_rects)?; - - let start_glyph_rect = - get_res( - pos_in_start_line, - start_line - )?; - - let start_line_last_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 = (start_line_last_glyph_rect.top_left_coords.x - start_glyph_rect.top_left_coords.x) + start_line_last_glyph_rect.width; - - all_rects.push( - Rect { - top_left_coords, - width, - height, - color: colors::WHITE - } - ); - - //middle lines - let nr_mid_lines = (stop_line_indx - start_line_indx) - 1; - let first_mid_line = start_line_indx + 1; - - for i in first_mid_line..(first_mid_line + nr_mid_lines) { - let mid_line = get_res(i, glyph_bound_rects)?; - - let mid_line_first_glyph_rect = - get_res( - 0, - mid_line - )?; - - let mid_line_last_glyph_rect = - get_res( - mid_line.len() - 1, - mid_line - )?; - - let top_left_coords = - mid_line_first_glyph_rect.top_left_coords; - - let height = mid_line_first_glyph_rect.height; - let width = (mid_line_last_glyph_rect.top_left_coords.x - mid_line_first_glyph_rect.top_left_coords.x) + mid_line_last_glyph_rect.width; - - all_rects.push( - Rect { - top_left_coords, - width, - height, - color: colors::WHITE - } - ); - } - - //last line - let stop_line = get_res(stop_line_indx, glyph_bound_rects)?; - - let stop_line_first_glyph_rect = - get_res( - 0, - stop_line - )?; - - let stop_glyph_rect = - get_res( - pos_in_stop_line, - stop_line - )?; - - let top_left_coords = - stop_line_first_glyph_rect.top_left_coords; - - let height = stop_glyph_rect.height; - let width = (stop_glyph_rect.top_left_coords.x - stop_line_first_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) - } -} - fn make_rect_pipeline( gpu_device: &wgpu::Device, swap_chain_descr: &wgpu::SwapChainDescriptor, diff --git a/editor/src/selection.rs b/editor/src/selection.rs new file mode 100644 index 0000000000..33362d4567 --- /dev/null +++ b/editor/src/selection.rs @@ -0,0 +1,189 @@ + +use crate::rect::{Rect}; +use crate::vec_result::{get_res}; +use crate::error::{EdResult, InvalidSelection}; +use crate::colors; +use snafu::ensure; + +pub struct RawSelection { + pub start_line_indx: usize, + pub pos_in_start_line: usize, + pub stop_line_indx: usize, + pub pos_in_stop_line: usize, +} + +//using the "parse don't validate" pattern +struct ValidSelection { + selection: RawSelection +} + +fn validate_selection( selection: RawSelection) -> EdResult { + let RawSelection {start_line_indx, pos_in_start_line, stop_line_indx, pos_in_stop_line} = selection; + + ensure!( + start_line_indx <= stop_line_indx, + InvalidSelection { err_msg: + format!( + "start_line_indx ({}) should be smaller than or equal to stop_line_indx ({})", + start_line_indx, + stop_line_indx + ) + } + ); + + ensure!( + !(start_line_indx == stop_line_indx && pos_in_start_line > pos_in_stop_line), + InvalidSelection { err_msg: + format!( + "pos_in_start_line ({}) should be smaller than or equal to pos_in_stop_line ({}) when start_line_indx equals stop_line_indx", + pos_in_start_line, + pos_in_stop_line + ) + } + ); + + Ok( + ValidSelection { + selection + } + ) +} + + +pub fn create_selection_rects( + raw_sel: RawSelection, + glyph_bound_rects: &Vec> +) -> EdResult> { + let valid_sel = validate_selection(raw_sel)?; + let RawSelection {start_line_indx, pos_in_start_line, stop_line_indx, pos_in_stop_line} = valid_sel.selection; + + let mut all_rects = Vec::new(); + + if start_line_indx == stop_line_indx { + let start_glyph_rect = + get_res( + pos_in_start_line, + get_res(start_line_indx, glyph_bound_rects)?, + )?; + + let stop_glyph_rect = + get_res( + pos_in_stop_line, + get_res(stop_line_indx, 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 { + // first line + let start_line = get_res(start_line_indx, glyph_bound_rects)?; + + let start_glyph_rect = + get_res( + pos_in_start_line, + start_line + )?; + + let start_line_last_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 = (start_line_last_glyph_rect.top_left_coords.x - start_glyph_rect.top_left_coords.x) + start_line_last_glyph_rect.width; + + all_rects.push( + Rect { + top_left_coords, + width, + height, + color: colors::WHITE + } + ); + + //middle lines + let nr_mid_lines = (stop_line_indx - start_line_indx) - 1; + let first_mid_line = start_line_indx + 1; + + for i in first_mid_line..(first_mid_line + nr_mid_lines) { + let mid_line = get_res(i, glyph_bound_rects)?; + + let mid_line_first_glyph_rect = + get_res( + 0, + mid_line + )?; + + let mid_line_last_glyph_rect = + get_res( + mid_line.len() - 1, + mid_line + )?; + + let top_left_coords = + mid_line_first_glyph_rect.top_left_coords; + + let height = mid_line_first_glyph_rect.height; + let width = (mid_line_last_glyph_rect.top_left_coords.x - mid_line_first_glyph_rect.top_left_coords.x) + mid_line_last_glyph_rect.width; + + all_rects.push( + Rect { + top_left_coords, + width, + height, + color: colors::WHITE + } + ); + } + + //last line + let stop_line = get_res(stop_line_indx, glyph_bound_rects)?; + + let stop_line_first_glyph_rect = + get_res( + 0, + stop_line + )?; + + let stop_glyph_rect = + get_res( + pos_in_stop_line, + stop_line + )?; + + let top_left_coords = + stop_line_first_glyph_rect.top_left_coords; + + let height = stop_glyph_rect.height; + let width = (stop_glyph_rect.top_left_coords.x - stop_line_first_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) + } +} \ No newline at end of file diff --git a/editor/src/vec_result.rs b/editor/src/vec_result.rs index cbd5fef0b5..a06ce22a8b 100644 --- a/editor/src/vec_result.rs +++ b/editor/src/vec_result.rs @@ -6,7 +6,7 @@ use snafu::{OptionExt}; // replace vec methods that return Option with ones that return Result and proper Error -pub fn get_res(index: usize, vec: &Vec) -> EdResult<&>::Output> { +pub fn get_res(index: usize, vec: &[T]) -> EdResult<&>::Output> { let elt_ref = vec.get(index).context(OutOfBounds { index,