done with UI refactor, adjusted colors to roc logo

This commit is contained in:
Anton-4 2021-02-19 17:33:27 +01:00
parent 774f723980
commit 7853c41944
30 changed files with 2719 additions and 3173 deletions

View file

@ -1,6 +1,8 @@
use crate::ui::colors::ColorTup; use crate::graphics::colors as gr_colors;
use crate::graphics::colors::ColorTup;
pub const TXT_COLOR: ColorTup = (1.0, 1.0, 1.0, 1.0); use crate::ui::colors as ui_colors;
pub const CODE_COLOR: ColorTup = (0.21, 0.55, 0.83, 1.0);
pub const BG_COLOR: ColorTup = (0.11, 0.11, 0.13, 1.0);
pub const BG_COL: ColorTup = (0.17, 0.17, 0.19, 1.0);
pub const EQUALS_SYNTAX_COL: ColorTup = (0.043, 0.0196, 0.102, 1.0);
pub const STRING_SYNTAX_COL: ColorTup = ui_colors::LIGHT_BRAND_COL;
pub const CODE_COLOR: ColorTup = gr_colors::WHITE;

View file

@ -1,5 +1,5 @@
use colored::*; use colored::*;
use snafu::{Backtrace, ErrorCompat, Snafu, ResultExt, NoneError}; use snafu::{Backtrace, ErrorCompat, NoneError, ResultExt, Snafu};
//import errors as follows: //import errors as follows:
// `use crate::error::OutOfBounds;` // `use crate::error::OutOfBounds;`
@ -35,10 +35,7 @@ pub enum EdError {
}, },
#[snafu(display("UIError: {}", msg))] #[snafu(display("UIError: {}", msg))]
UIErrorBacktrace { UIErrorBacktrace { msg: String, backtrace: Backtrace },
msg: String,
backtrace: Backtrace,
},
} }
pub type EdResult<T, E = EdError> = std::result::Result<T, E>; pub type EdResult<T, E = EdError> = std::result::Result<T, E>;
@ -113,9 +110,7 @@ impl From<UIError> for EdError {
let msg = format!("{}", ui_err); let msg = format!("{}", ui_err);
// hack to handle EdError derive // hack to handle EdError derive
let dummy_res: Result<(), NoneError> = Err(NoneError{}); let dummy_res: Result<(), NoneError> = Err(NoneError {});
dummy_res.context(UIErrorBacktrace { dummy_res.context(UIErrorBacktrace { msg }).unwrap_err()
msg,
}).unwrap_err()
} }
} }

View file

@ -1,6 +1,8 @@
use crate::editor::ed_error::EdResult; use crate::editor::ed_error::EdResult;
use crate::editor::mvc::app_model::AppModel; use crate::editor::mvc::app_model::AppModel;
use crate::editor::mvc::app_update::{handle_copy, handle_cut, handle_paste, pass_keydown_to_focused}; use crate::editor::mvc::app_update::{
handle_copy, handle_cut, handle_paste, pass_keydown_to_focused,
};
use winit::event::VirtualKeyCode::*; use winit::event::VirtualKeyCode::*;
use winit::event::{ElementState, ModifiersState, VirtualKeyCode}; use winit::event::{ElementState, ModifiersState, VirtualKeyCode};
@ -15,7 +17,9 @@ pub fn handle_keydown(
} }
match virtual_keycode { match virtual_keycode {
Left | Up | Right | Down => pass_keydown_to_focused(&modifiers, virtual_keycode, app_model)?, Left | Up | Right | Down => {
pass_keydown_to_focused(&modifiers, virtual_keycode, app_model)?
}
Copy => handle_copy(app_model)?, Copy => handle_copy(app_model)?,
Paste => handle_paste(app_model)?, Paste => handle_paste(app_model)?,

View file

@ -1,43 +1,30 @@
use super::keyboard_input;
use crate::editor::colors::BG_COL;
use crate::editor::colors::CODE_COLOR;
use crate::editor::ed_error::{print_err, print_ui_err}; use crate::editor::ed_error::{print_err, print_ui_err};
use crate::ui::{ use crate::editor::mvc::{app_model::AppModel, app_update, ed_model, ed_model::EdModel, ed_view};
ui_error::UIResult, use crate::graphics::colors::to_wgpu_color;
text::text_pos::{TextPos}, use crate::graphics::primitives::text::{
text::lines::{Lines}, build_glyph_brush, example_code_glyph_rect, queue_code_text_draw, queue_text_draw, Text,
colors::{CODE_COLOR, TXT_COLOR},
}; };
use crate::graphics::{ use crate::graphics::{
lowlevel::buffer::create_rect_buffers, lowlevel::buffer::create_rect_buffers, lowlevel::ortho::update_ortho_buffer,
lowlevel::ortho::update_ortho_buffer, lowlevel::pipelines, style::CODE_FONT_SIZE, style::CODE_TXT_XY,
lowlevel::pipelines,
style::CODE_FONT_SIZE,
style::CODE_TXT_XY,
}; };
use crate::graphics::primitives::text::{ use crate::ui::{
build_glyph_brush, example_code_glyph_rect, queue_code_text_draw, queue_text_draw, colors::TXT_COLOR, text::lines::Lines, text::text_pos::TextPos, ui_error::UIResult,
Text,
}; };
use crate::editor::mvc::{
app_update, ed_model, ed_view,
app_model::AppModel,
ed_model::EdModel,
};
use super::keyboard_input;
//use crate::resources::strings::NOTHING_OPENED; //use crate::resources::strings::NOTHING_OPENED;
use super::util::slice_get; use super::util::slice_get;
use crate::lang::{pool::Pool, scope::Scope}; use crate::lang::{pool::Pool, scope::Scope};
use bumpalo::Bump;
use cgmath::Vector2;
use pipelines::RectResources; use pipelines::RectResources;
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_module::symbol::{IdentIds, ModuleIds}; use roc_module::symbol::{IdentIds, ModuleIds};
use roc_region::all::Region; use roc_region::all::Region;
use roc_types::subs::VarStore; use roc_types::subs::VarStore;
use bumpalo::Bump; use std::{error::Error, io, path::Path};
use cgmath::Vector2;
use std::{
io,
error::Error,
path::Path,
};
use wgpu::{CommandEncoder, RenderPass, TextureView}; use wgpu::{CommandEncoder, RenderPass, TextureView};
use wgpu_glyph::GlyphBrush; use wgpu_glyph::GlyphBrush;
use winit::{ use winit::{
@ -388,17 +375,14 @@ fn begin_render_pass<'a>(
encoder: &'a mut CommandEncoder, encoder: &'a mut CommandEncoder,
texture_view: &'a TextureView, texture_view: &'a TextureView,
) -> RenderPass<'a> { ) -> RenderPass<'a> {
let bg_color = to_wgpu_color(BG_COL);
encoder.begin_render_pass(&wgpu::RenderPassDescriptor { encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: texture_view, attachment: texture_view,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color { load: wgpu::LoadOp::Clear(bg_color),
r: 0.1,
g: 0.2,
b: 0.3,
a: 1.0,
}),
store: true, store: true,
}, },
}], }],

View file

@ -1,8 +1,8 @@
mod colors;
pub mod main;
pub mod mvc;
mod ed_error; mod ed_error;
mod keyboard_input; mod keyboard_input;
pub mod main;
mod mvc;
mod render_ast; mod render_ast;
mod colors; pub mod syntax_highlight;
mod util; mod util; // TODO remove pub once we have ast based syntax highlighting

View file

@ -1,8 +1,8 @@
use super::ed_model::EdModel; use super::ed_model::EdModel;
use crate::editor::ed_error::{ use crate::editor::ed_error::{
print_err, print_err,
EdResult,
EdError::{ClipboardInitFailed, ClipboardReadFailed, ClipboardWriteFailed}, EdError::{ClipboardInitFailed, ClipboardReadFailed, ClipboardWriteFailed},
EdResult,
}; };
use copypasta::{ClipboardContext, ClipboardProvider}; use copypasta::{ClipboardContext, ClipboardProvider};
use std::fmt; use std::fmt;

View file

@ -1,13 +1,12 @@
use super::app_model; use super::app_model;
use super::app_model::AppModel; use super::app_model::AppModel;
use super::ed_update; use crate::editor::ed_error::EdResult;
use winit::event::{ModifiersState, VirtualKeyCode};
use crate::ui::text::{ use crate::ui::text::{
lines::{SelectableLines, MutSelectableLines}, lines::{MutSelectableLines, SelectableLines},
text_pos::TextPos, text_pos::TextPos,
}; };
use crate::ui::ui_error::UIResult; use crate::ui::ui_error::UIResult;
use crate::editor::ed_error::EdResult; use winit::event::{ModifiersState, VirtualKeyCode};
pub fn handle_copy(app_model: &mut AppModel) -> EdResult<()> { pub fn handle_copy(app_model: &mut AppModel) -> EdResult<()> {
if let Some(ref mut ed_model) = app_model.ed_model_opt { if let Some(ref mut ed_model) = app_model.ed_model_opt {
@ -41,48 +40,32 @@ pub fn handle_paste(app_model: &mut AppModel) -> EdResult<()> {
let start_caret_pos = selection.start_pos; let start_caret_pos = selection.start_pos;
ed_model.text.del_selection()?; ed_model.text.del_selection()?;
ed_model ed_model.text.insert_str(&clipboard_content)?;
.text
.insert_str(&clipboard_content)?;
if clipboard_nr_lines > 0 { if clipboard_nr_lines > 0 {
ed_model ed_model.text.set_caret(TextPos {
.text line: start_caret_pos.line + clipboard_nr_lines,
.set_caret( TextPos { column: last_line_nr_chars,
line: start_caret_pos.line + clipboard_nr_lines, })
column: last_line_nr_chars,
})
} else { } else {
ed_model ed_model.text.set_caret(TextPos {
.text line: start_caret_pos.line,
.set_caret( TextPos { column: start_caret_pos.column + last_line_nr_chars,
line: start_caret_pos.line, })
column: start_caret_pos.column + last_line_nr_chars,
})
} }
} else { } else {
ed_model ed_model.text.insert_str(&clipboard_content)?;
.text
.insert_str(&clipboard_content)?;
if clipboard_nr_lines > 0 { if clipboard_nr_lines > 0 {
ed_model ed_model.text.set_caret(TextPos {
.text line: old_caret_pos.line + clipboard_nr_lines,
.set_caret( column: last_line_nr_chars,
TextPos { })
line: old_caret_pos.line + clipboard_nr_lines,
column: last_line_nr_chars,
}
)
} else { } else {
ed_model ed_model.text.set_caret(TextPos {
.text line: old_caret_pos.line,
.set_caret( column: old_caret_pos.column + last_line_nr_chars,
TextPos { })
line: old_caret_pos.line,
column: old_caret_pos.column + last_line_nr_chars,
}
)
} }
} }
} }
@ -115,7 +98,7 @@ pub fn pass_keydown_to_focused(
) -> UIResult<()> { ) -> UIResult<()> {
if let Some(ref mut ed_model) = app_model.ed_model_opt { if let Some(ref mut ed_model) = app_model.ed_model_opt {
if ed_model.has_focus { if ed_model.has_focus {
ed_update::handle_key_down(modifiers, virtual_keycode, ed_model)?; ed_model.text.handle_key_down(modifiers, virtual_keycode)?;
} }
} }
@ -125,20 +108,20 @@ pub fn pass_keydown_to_focused(
pub fn handle_new_char(received_char: &char, app_model: &mut AppModel) -> EdResult<()> { pub fn handle_new_char(received_char: &char, app_model: &mut AppModel) -> EdResult<()> {
if let Some(ref mut ed_model) = app_model.ed_model_opt { if let Some(ref mut ed_model) = app_model.ed_model_opt {
if ed_model.has_focus { if ed_model.has_focus {
ed_update::handle_new_char(received_char, ed_model)?; ed_model.text.handle_new_char(received_char)?;
} }
} }
Ok(()) Ok(())
} }
/*
#[cfg(test)] #[cfg(test)]
pub mod test_app_update { pub mod test_app_update {
use crate::editor::mvc::app_model; use crate::editor::mvc::app_model;
use crate::editor::mvc::app_model::{AppModel, Clipboard}; use crate::editor::mvc::app_model::{AppModel, Clipboard};
use crate::editor::mvc::app_update::{handle_copy, handle_cut, handle_paste}; use crate::editor::mvc::app_update::{handle_copy, handle_cut, handle_paste};
use crate::editor::mvc::ed_model::{EdModel}; use crate::editor::mvc::ed_model::{EdModel};
use crate::editor::mvc::ed_update::test_ed_update::gen_big_text;
use crate::ui::text::{ use crate::ui::text::{
big_selectable_text::BigSelectableText, big_selectable_text::BigSelectableText,
selection::test_selection::{all_lines_vec, convert_selection_to_dsl}, selection::test_selection::{all_lines_vec, convert_selection_to_dsl},
@ -288,4 +271,4 @@ pub mod test_app_update {
Ok(()) Ok(())
} }
} }*/

View file

@ -1,7 +1,5 @@
use crate::graphics::primitives::rect::Rect; use crate::graphics::primitives::rect::Rect;
use crate::ui::text::{ use crate::ui::text::big_selectable_text::{from_path, BigSelectableText};
big_selectable_text::{BigSelectableText, from_path},
};
use crate::ui::ui_error::UIResult; use crate::ui::ui_error::UIResult;
use std::path::Path; use std::path::Path;

View file

@ -1,427 +0,0 @@
use super::ed_model::EdModel;
use crate::ui::text::{
text_pos::TextPos,
selection::{RawSelection, Selection, validate_selection},
big_selectable_text::BigSelectableText,
lines::{Lines, SelectableLines, MutSelectableLines},
caret_w_select::CaretWSelect,
};
use crate::ui::ui_error::UIResult;
use crate::editor::ed_error::EdResult;
use crate::editor::util::is_newline;
use std::cmp::{max, min};
use winit::event::VirtualKeyCode::*;
use winit::event::{ModifiersState, VirtualKeyCode};
pub type MoveCaretFun =
fn(bool, &BigSelectableText) -> UIResult<CaretWSelect>;
fn validate_sel_opt(start_pos: TextPos, end_pos: TextPos) -> UIResult<Option<Selection>> {
Ok(
Some(
validate_selection(start_pos, end_pos)?
)
)
}
fn handle_arrow(move_caret_fun: MoveCaretFun, modifiers: &ModifiersState, ed_model: &mut EdModel) -> UIResult<()> {
let new_caret_w_select = move_caret_fun(
modifiers.shift(),
&ed_model.text,
)?;
ed_model.text.caret_w_select = new_caret_w_select;
Ok(())
}
// TODO move this to impl EdModel
pub fn handle_select_all(ed_model: &mut EdModel) -> UIResult<()> {
if ed_model.text.nr_of_chars() > 0 {
let last_pos = ed_model.text.last_text_pos();
ed_model.text.set_raw_sel(
RawSelection {
start_pos: TextPos { line: 0, column: 0 },
end_pos: last_pos,
}
)?;
ed_model.text.set_caret(last_pos);
}
Ok(())
}
pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult<()> {
let old_caret_pos = ed_model.text.caret_w_select.caret_pos;
// TODO move this to ui folder
match received_char {
'\u{8}' | '\u{7f}' => {
// On Linux, '\u{8}' is backspace,
// on macOS '\u{7f}'.
if ed_model.text.is_selection_active() {
ed_model.text.del_selection()?;
} else {
ed_model.text.pop_char();
}
ed_model.text.set_sel_none();
}
ch if is_newline(ch) => {
if ed_model.text.is_selection_active() {
ed_model.text.del_selection()?;
ed_model.text.insert_char(&'\n')?;
} else {
ed_model.text.insert_char(&'\n')?;
ed_model.text.set_caret(TextPos {
line: old_caret_pos.line + 1,
column: 0,
});
}
ed_model.text.set_sel_none();
}
'\u{1}' // Ctrl + A
| '\u{3}' // Ctrl + C
| '\u{16}' // Ctrl + V
| '\u{18}' // Ctrl + X
| '\u{e000}'..='\u{f8ff}' // http://www.unicode.org/faq/private_use.html
| '\u{f0000}'..='\u{ffffd}' // ^
| '\u{100000}'..='\u{10fffd}' // ^
=> {
// chars that can be ignored
}
_ => {
if ed_model.text.is_selection_active() {
ed_model.text.del_selection()?;
ed_model
.text
.insert_char(received_char)?;
ed_model.text.set_caret(
move_caret_right(false, &ed_model.text)?.caret_pos
);
} else {
ed_model
.text
.insert_char(received_char)?;
ed_model.text.set_caret(
TextPos {
line: old_caret_pos.line,
column: old_caret_pos.column + 1,
}
);
}
ed_model.text.set_sel_none();
}
}
Ok(())
}
pub fn handle_key_down(
modifiers: &ModifiersState,
virtual_keycode: VirtualKeyCode,
ed_model: &mut EdModel,
) -> UIResult<()> {
match virtual_keycode {
Left => handle_arrow(move_caret_left, modifiers, ed_model),
Up => handle_arrow(move_caret_up, modifiers, ed_model),
Right => handle_arrow(move_caret_right, modifiers, ed_model),
Down => handle_arrow(move_caret_down, modifiers, ed_model),
A => {
if modifiers.ctrl() {
handle_select_all(ed_model)
} else {
Ok(())
}
}
Home => {
let curr_line_nr = ed_model.text.caret_w_select.caret_pos.line;
// TODO no unwrap
let curr_line_str = ed_model.text.get_line(curr_line_nr).unwrap();
let line_char_iter = curr_line_str.chars();
let mut first_no_space_char_col = 0;
let mut non_space_found = false;
for c in line_char_iter {
if !c.is_whitespace() {
non_space_found = true;
break;
} else {
first_no_space_char_col += 1;
}
}
if !non_space_found {
first_no_space_char_col = 0;
}
ed_model.text.caret_w_select.move_caret_w_mods(
TextPos {
line: ed_model.text.caret_w_select.caret_pos.line,
column: first_no_space_char_col
},
modifiers
)
}
End => {
let curr_line = ed_model.text.caret_w_select.caret_pos.line;
// TODO no unwrap
let new_col =
max(
0,
ed_model.text.line_len(curr_line).unwrap() - 1
);
let new_pos =
TextPos {
line: curr_line,
column: new_col
};
ed_model.text.caret_w_select.move_caret_w_mods(new_pos, modifiers)
}
_ => Ok(())
}
}
#[cfg(test)]
pub mod test_ed_update {
use crate::editor::mvc::app_update::test_app_update::mock_app_model;
use crate::editor::mvc::ed_update::{handle_new_char, handle_select_all};
use crate::ui::text::{
big_selectable_text::BigSelectableText,
};
use crate::ui::text::selection::test_selection::{
all_lines_vec, convert_dsl_to_selection, convert_selection_to_dsl, big_text_from_dsl_str,
};
use bumpalo::Bump;
pub fn gen_big_text(
lines: &[&str],
) -> Result<BigSelectableText, String> {
let lines_string_slice: Vec<String> = lines.iter().map(|l| l.to_string()).collect();
let mut big_text = big_text_from_dsl_str(&lines_string_slice);
let caret_w_select = convert_dsl_to_selection(&lines_string_slice).unwrap();
big_text.caret_w_select = caret_w_select;
Ok(big_text)
}
fn assert_insert(
pre_lines_str: &[&str],
expected_post_lines_str: &[&str],
new_char: char,
arena: &Bump,
) -> Result<(), String> {
let pre_big_text = gen_big_text(pre_lines_str)?;
let app_model = mock_app_model(pre_big_text, None);
let mut ed_model = app_model.ed_model_opt.unwrap();
if let Err(e) = handle_new_char(&new_char, &mut ed_model) {
return Err(e.to_string());
}
let mut actual_lines = all_lines_vec(&ed_model.text);
let dsl_slice = convert_selection_to_dsl(
ed_model.text.caret_w_select,
&mut actual_lines,
)
.unwrap();
assert_eq!(dsl_slice, expected_post_lines_str);
Ok(())
}
#[test]
fn insert_new_char_simple() -> Result<(), String> {
let arena = &Bump::new();
assert_insert(&["|"], &["a|"], 'a', arena)?;
assert_insert(&["|"], &[" |"], ' ', arena)?;
assert_insert(&["a|"], &["aa|"], 'a', arena)?;
assert_insert(&["a|"], &["a |"], ' ', arena)?;
assert_insert(&["a|\n", ""], &["ab|\n", ""], 'b', arena)?;
assert_insert(&["a|\n", ""], &["ab|\n", ""], 'b', arena)?;
assert_insert(&["a\n", "|"], &["a\n", "b|"], 'b', arena)?;
assert_insert(&["a\n", "b\n", "c|"], &["a\n", "b\n", "cd|"], 'd', arena)?;
Ok(())
}
#[test]
fn insert_new_char_mid() -> Result<(), String> {
let arena = &Bump::new();
assert_insert(&["ab|d"], &["abc|d"], 'c', arena)?;
assert_insert(&["a|cd"], &["ab|cd"], 'b', arena)?;
assert_insert(&["abc\n", "|e"], &["abc\n", "d|e"], 'd', arena)?;
assert_insert(&["abc\n", "def\n", "| "], &["abc\n", "def\n", "g| "], 'g', arena)?;
assert_insert(&["abc\n", "def\n", "| "], &["abc\n", "def\n", " | "], ' ', arena)?;
Ok(())
}
#[test]
fn simple_backspace() -> Result<(), String> {
let arena = &Bump::new();
assert_insert(&["|"], &["|"], '\u{8}', arena)?;
assert_insert(&[" |"], &["|"], '\u{8}', arena)?;
assert_insert(&["a|"], &["|"], '\u{8}', arena)?;
assert_insert(&["ab|"], &["a|"], '\u{8}', arena)?;
assert_insert(&["a|\n", ""], &["|\n", ""], '\u{8}', arena)?;
assert_insert(&["ab|\n", ""], &["a|\n", ""], '\u{8}', arena)?;
assert_insert(&["a\n", "|"], &["a|"], '\u{8}', arena)?;
assert_insert(&["a\n", "b\n", "c|"], &["a\n", "b\n", "|"], '\u{8}', arena)?;
assert_insert(&["a\n", "b\n", "|"], &["a\n", "b|"], '\u{8}', arena)?;
Ok(())
}
#[test]
fn selection_backspace() -> Result<(), String> {
let arena = &Bump::new();
assert_insert(&["[a]|"], &["|"], '\u{8}', arena)?;
assert_insert(&["a[a]|"], &["a|"], '\u{8}', arena)?;
assert_insert(&["[aa]|"], &["|"], '\u{8}', arena)?;
assert_insert(&["a[b c]|"], &["a|"], '\u{8}', arena)?;
assert_insert(&["[abc]|\n", ""], &["|\n", ""], '\u{8}', arena)?;
assert_insert(&["a\n", "[abc]|"], &["a\n", "|"], '\u{8}', arena)?;
assert_insert(&["[a\n", "abc]|"], &["|"], '\u{8}', arena)?;
assert_insert(&["a[b\n", "cdef ghij]|"], &["a|"], '\u{8}', arena)?;
assert_insert(&["[a\n", "b\n", "c]|"], &["|"], '\u{8}', arena)?;
assert_insert(&["a\n", "[b\n", "]|"], &["a\n", "|"], '\u{8}', arena)?;
assert_insert(
&["abc\n", "d[ef\n", "ghi]|\n", "jkl"],
&["abc\n", "d|\n", "jkl"],
'\u{8}',
arena,
)?;
assert_insert(
&["abc\n", "[def\n", "ghi]|\n", "jkl"],
&["abc\n", "|\n", "jkl"],
'\u{8}',
arena,
)?;
assert_insert(
&["abc\n", "\n", "[def\n", "ghi]|\n", "jkl"],
&["abc\n", "\n", "|\n", "jkl"],
'\u{8}',
arena,
)?;
assert_insert(
&["[abc\n", "\n", "def\n", "ghi\n", "jkl]|"],
&["|"],
'\u{8}',
arena,
)?;
Ok(())
}
#[test]
fn insert_with_selection() -> Result<(), String> {
let arena = &Bump::new();
assert_insert(&["[a]|"], &["z|"], 'z', arena)?;
assert_insert(&["a[a]|"], &["az|"], 'z', arena)?;
assert_insert(&["[aa]|"], &["z|"], 'z', arena)?;
assert_insert(&["a[b c]|"], &["az|"], 'z', arena)?;
assert_insert(&["[abc]|\n", ""], &["z|\n", ""], 'z', arena)?;
assert_insert(&["a\n", "[abc]|"], &["a\n", "z|"], 'z', arena)?;
assert_insert(&["[a\n", "abc]|"], &["z|"], 'z', arena)?;
assert_insert(&["a[b\n", "cdef ghij]|"], &["az|"], 'z', arena)?;
assert_insert(&["[a\n", "b\n", "c]|"], &["z|"], 'z', arena)?;
assert_insert(&["a\n", "[b\n", "]|"], &["a\n", "z|"], 'z', arena)?;
assert_insert(
&["abc\n", "d[ef\n", "ghi]|\n", "jkl"],
&["abc\n", "dz|\n", "jkl"],
'z',
arena,
)?;
assert_insert(
&["abc\n", "[def\n", "ghi]|\n", "jkl"],
&["abc\n", "z|\n", "jkl"],
'z',
arena,
)?;
assert_insert(
&["abc\n", "\n", "[def\n", "ghi]|\n", "jkl"],
&["abc\n", "\n", "z|\n", "jkl"],
'z',
arena,
)?;
assert_insert(&["[abc\n", "\n", "def\n", "ghi\n", "jkl]|"], &["z|"], 'z', arena)?;
Ok(())
}
fn assert_select_all(
pre_lines_str: &[&str],
expected_post_lines_str: &[&str],
arena: &Bump,
) -> Result<(), String> {
let pre_big_text = gen_big_text(pre_lines_str)?;
let app_model = mock_app_model(pre_big_text, None);
let mut ed_model = app_model.ed_model_opt.unwrap();
handle_select_all(&mut ed_model).unwrap();
let mut big_text_lines = all_lines_vec(&ed_model.text);
let post_lines_str = convert_selection_to_dsl(
ed_model.text.caret_w_select,
&mut big_text_lines,
)?;
assert_eq!(post_lines_str, expected_post_lines_str);
Ok(())
}
#[test]
fn select_all() -> Result<(), String> {
let arena = &Bump::new();
assert_select_all(&["|"], &["|"], arena)?;
assert_select_all(&["|a"], &["[a]|"], arena)?;
assert_select_all(&["a|"], &["[a]|"], arena)?;
assert_select_all(&["abc d|ef ghi"], &["[abc def ghi]|"], arena)?;
assert_select_all(&["[a]|"], &["[a]|"], arena)?;
assert_select_all(&["|[a]"], &["[a]|"], arena)?;
assert_select_all(&["|[abc def ghi]"], &["[abc def ghi]|"], arena)?;
assert_select_all(&["a\n", "[b\n", "]|"], &["[a\n", "b\n", "]|"], arena)?;
assert_select_all(&["a\n", "[b]|\n", ""], &["[a\n", "b\n", "]|"], arena)?;
assert_select_all(&["a\n", "|[b\n", "]"], &["[a\n", "b\n", "]|"], arena)?;
assert_select_all(
&["abc\n", "def\n", "gh|i\n", "jkl"],
&["[abc\n", "def\n", "ghi\n", "jkl]|"],
arena,
)?;
assert_select_all(
&["|[abc\n", "def\n", "ghi\n", "jkl]"],
&["[abc\n", "def\n", "ghi\n", "jkl]|"],
arena,
)?;
Ok(())
}
// TODO hometest
// TODO endtest
}

View file

@ -1,12 +1,9 @@
use super::ed_model::{EdModel}; use super::ed_model::EdModel;
use crate::ui::ui_error::{MissingGlyphDims};
use crate::ui::ui_error::UIResult;
use crate::ui::colors::CARET_COLOR;
use crate::graphics::primitives::rect::Rect; use crate::graphics::primitives::rect::Rect;
use crate::ui::text::{ use crate::ui::colors::CARET_COLOR;
selection::create_selection_rects, use crate::ui::text::{selection::create_selection_rects, text_pos::TextPos};
text_pos::TextPos, use crate::ui::ui_error::MissingGlyphDims;
}; use crate::ui::ui_error::UIResult;
use bumpalo::collections::Vec as BumpVec; use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump; use bumpalo::Bump;
use snafu::ensure; use snafu::ensure;

View file

@ -1,5 +1,4 @@
pub mod app_model; pub mod app_model;
pub mod app_update; pub mod app_update;
pub mod ed_model; pub mod ed_model;
pub mod ed_update;
pub mod ed_view; pub mod ed_view;

View file

@ -1,7 +1,4 @@
use cgmath::Vector2; use crate::editor::colors::CODE_COLOR;
use wgpu_glyph::GlyphBrush;
use winit::dpi::PhysicalSize;
use crate::ui::colors::CODE_COLOR;
use crate::{ use crate::{
graphics::{ graphics::{
primitives::text::{queue_code_text_draw, Text}, primitives::text::{queue_code_text_draw, Text},
@ -9,6 +6,9 @@ use crate::{
}, },
lang::{ast::Expr2, expr::Env}, lang::{ast::Expr2, expr::Env},
}; };
use cgmath::Vector2;
use wgpu_glyph::GlyphBrush;
use winit::dpi::PhysicalSize;
pub fn render_expr2<'a>( pub fn render_expr2<'a>(
env: &mut Env<'a>, env: &mut Env<'a>,

View file

@ -1,6 +1,7 @@
use crate::ui::colors; use crate::editor::colors as ed_colors;
use colors::ColorTup; use crate::graphics::colors as gr_colors;
use crate::graphics::primitives; use crate::graphics::primitives;
use gr_colors::ColorTup;
//TODO optimize memory allocation //TODO optimize memory allocation
//TODO this is a demo function, the AST should be used for highlighting, see #904. //TODO this is a demo function, the AST should be used for highlighting, see #904.
@ -10,16 +11,16 @@ pub fn highlight_code(
) { ) {
let split_code = split_inclusive(&code_text.text); let split_code = split_inclusive(&code_text.text);
let mut active_color = colors::WHITE; let mut active_color = gr_colors::WHITE;
let mut same_type_str = String::new(); let mut same_type_str = String::new();
for token_seq in split_code { for token_seq in split_code {
let new_word_color = if token_seq.contains(&'\"'.to_string()) { let new_word_color = if token_seq.contains(&'\"'.to_string()) {
colors::CODE_COLOR ed_colors::STRING_SYNTAX_COL
} else if token_seq.contains(&'='.to_string()) { } else if token_seq.contains(&'='.to_string()) {
colors::BLACK ed_colors::EQUALS_SYNTAX_COL
} else { } else {
colors::WHITE gr_colors::WHITE
}; };
if new_word_color != active_color { if new_word_color != active_color {

View file

@ -1,14 +1,7 @@
use super::ed_error::{EdResult, OutOfBounds}; use super::ed_error::{EdResult, OutOfBounds};
use snafu::OptionExt; use snafu::OptionExt;
use std::slice::SliceIndex; use std::slice::SliceIndex;
pub fn is_newline(char_ref: &char) -> bool {
let newline_codes = vec!['\u{d}', '\n'];
newline_codes.contains(char_ref)
}
// replace vec methods that return Option with ones that return Result and proper Error // replace vec methods that return Option with ones that return Result and proper Error
pub fn slice_get<T>(index: usize, slice: &[T]) -> EdResult<&<usize as SliceIndex<[T]>>::Output> { pub fn slice_get<T>(index: usize, slice: &[T]) -> EdResult<&<usize as SliceIndex<[T]>>::Output> {
let elt_ref = slice.get(index).context(OutOfBounds { let elt_ref = slice.get(index).context(OutOfBounds {

View file

@ -0,0 +1,15 @@
pub type ColorTup = (f32, f32, f32, f32);
pub const WHITE: ColorTup = (1.0, 1.0, 1.0, 1.0);
pub fn to_wgpu_color((r, g, b, a): ColorTup) -> wgpu::Color {
wgpu::Color {
r: r as f64,
g: g as f64,
b: b as f64,
a: a as f64,
}
}
pub fn to_slice((r, g, b, a): ColorTup) -> [f32; 4] {
[r, g, b, a]
}

View file

@ -1,7 +1,7 @@
// 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 super::vertex::Vertex; use super::vertex::Vertex;
use crate::ui::colors::to_slice; use crate::graphics::colors::to_slice;
use crate::graphics::primitives::rect::Rect; use crate::graphics::primitives::rect::Rect;
use bumpalo::collections::Vec as BumpVec; use bumpalo::collections::Vec as BumpVec;
use wgpu::util::{BufferInitDescriptor, DeviceExt}; use wgpu::util::{BufferInitDescriptor, DeviceExt};

View file

@ -1,4 +1,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,12 @@
// 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::ui::colors; use crate::editor::syntax_highlight;
use crate::graphics::colors;
use crate::graphics::colors::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 colors::{ColorTup, CODE_COLOR, WHITE};
use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section}; use wgpu_glyph::{ab_glyph, GlyphBrush, GlyphBrushBuilder, GlyphCruncher, Section};
#[derive(Debug)] #[derive(Debug)]
@ -40,7 +40,7 @@ pub fn example_code_glyph_rect(glyph_brush: &mut GlyphBrush<()>) -> Rect {
let code_text = Text { let code_text = Text {
position: CODE_TXT_XY.into(), position: CODE_TXT_XY.into(),
area_bounds: (std::f32::INFINITY, std::f32::INFINITY).into(), area_bounds: (std::f32::INFINITY, std::f32::INFINITY).into(),
color: CODE_COLOR.into(), color: (1.0, 1.0, 1.0, 1.0).into(),
text: "a", text: "a",
size: CODE_FONT_SIZE, size: CODE_FONT_SIZE,
..Default::default() ..Default::default()
@ -145,7 +145,7 @@ fn glyph_to_rect(glyph: &wgpu_glyph::SectionGlyph) -> Rect {
top_left_coords: [position.x, top_y].into(), top_left_coords: [position.x, top_y].into(),
width, width,
height, height,
color: WHITE, color: colors::WHITE,
} }
} }

View file

@ -98,9 +98,9 @@ impl<'a> File<'a> {
#[cfg(test)] #[cfg(test)]
mod test_file { mod test_file {
use crate::lang::roc_file;
use bumpalo::Bump; use bumpalo::Bump;
use std::path::Path; use std::path::Path;
use crate::lang::roc_file;
#[test] #[test]
fn read_and_fmt_simple_roc_module() { fn read_and_fmt_simple_roc_module() {

View file

@ -2,15 +2,15 @@
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check. // See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
#![allow(clippy::large_enum_variant)] #![allow(clippy::large_enum_variant)]
#[cfg_attr(test, macro_use)]
extern crate indoc;
extern crate pest; extern crate pest;
#[cfg_attr(test, macro_use)] #[cfg_attr(test, macro_use)]
extern crate pest_derive; extern crate pest_derive;
#[cfg_attr(test, macro_use)]
extern crate indoc;
mod graphics;
mod lang;
mod editor; mod editor;
mod graphics;
pub mod lang; //TODO remove pub for unused warnings
mod ui; mod ui;
use std::io; use std::io;
@ -18,4 +18,4 @@ use std::path::Path;
pub fn launch(filepaths: &[&Path]) -> io::Result<()> { pub fn launch(filepaths: &[&Path]) -> io::Result<()> {
editor::main::launch(filepaths) editor::main::launch(filepaths)
} }

View file

@ -1,21 +1,8 @@
pub type ColorTup = (f32, f32, f32, f32); use crate::graphics::colors as gr_colors;
pub const WHITE: ColorTup = (1.0, 1.0, 1.0, 1.0); use gr_colors::ColorTup;
pub const BLACK: ColorTup = (0.0, 0.0, 0.0, 1.0);
pub const LIGHT_BRAND_COL: ColorTup = (0.506, 0.337, 0.902, 1.0);
//pub const DARK_BRAND_COL: ColorTup = (0.380, 0.169, 0.871, 1.0);
pub const TXT_COLOR: ColorTup = (1.0, 1.0, 1.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 = gr_colors::WHITE;
pub const CARET_COLOR: ColorTup = WHITE;
pub const SELECT_COLOR: ColorTup = (0.45, 0.61, 1.0, 1.0); 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 {
r: r as f64,
g: g as f64,
b: b as f64,
a: a as f64,
}
}
pub fn to_slice((r, g, b, a): ColorTup) -> [f32; 4] {
[r, g, b, a]
}

View file

@ -1,4 +1,4 @@
pub mod ui_error;
pub mod colors; pub mod colors;
pub mod text; pub mod text;
mod util; pub mod ui_error;
mod util;

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,8 @@
use crate::ui::ui_error::UIResult;
use super::text_pos::TextPos;
use super::selection::{Selection};
use winit::event::{ModifiersState};
use super::selection::validate_selection; use super::selection::validate_selection;
use super::selection::Selection;
use super::text_pos::TextPos;
use crate::ui::ui_error::UIResult;
use winit::event::ModifiersState;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct CaretWSelect { pub struct CaretWSelect {
@ -12,29 +10,20 @@ pub struct CaretWSelect {
pub selection_opt: Option<Selection>, pub selection_opt: Option<Selection>,
} }
fn mk_some_sel(start_pos: TextPos, end_pos: TextPos) -> UIResult<Option<Selection>> { fn mk_some_sel(start_pos: TextPos, end_pos: TextPos) -> UIResult<Option<Selection>> {
Ok( Ok(Some(validate_selection(start_pos, end_pos)?))
Some(
validate_selection(start_pos, end_pos)?
)
)
} }
impl Default for CaretWSelect { impl Default for CaretWSelect {
fn default() -> Self { fn default() -> Self {
Self { Self {
caret_pos: TextPos { caret_pos: TextPos { line: 0, column: 0 },
line: 0, selection_opt: None,
column: 0
},
selection_opt: None
} }
} }
} }
impl CaretWSelect { impl CaretWSelect {
pub fn new(caret_pos: TextPos, selection_opt: Option<Selection>) -> Self { pub fn new(caret_pos: TextPos, selection_opt: Option<Selection>) -> Self {
Self { Self {
caret_pos, caret_pos,
@ -44,72 +33,46 @@ impl CaretWSelect {
pub fn move_caret_w_mods(&mut self, new_pos: TextPos, mods: &ModifiersState) -> UIResult<()> { pub fn move_caret_w_mods(&mut self, new_pos: TextPos, mods: &ModifiersState) -> UIResult<()> {
let caret_pos = self.caret_pos; let caret_pos = self.caret_pos;
// one does not simply move the caret // one does not simply move the caret
let valid_sel_opt = let valid_sel_opt = if new_pos != caret_pos {
if new_pos != caret_pos { if mods.shift() {
if mods.shift() { if let Some(old_sel) = self.selection_opt {
if let Some(old_sel) = self.selection_opt { if new_pos < old_sel.start_pos {
if new_pos < old_sel.start_pos { if caret_pos > old_sel.start_pos {
if caret_pos > old_sel.start_pos { mk_some_sel(new_pos, old_sel.start_pos)?
mk_some_sel(
new_pos,
old_sel.start_pos
)?
} else {
mk_some_sel(
new_pos,
old_sel.end_pos
)?
}
} else if new_pos > old_sel.end_pos {
if caret_pos < old_sel.end_pos {
mk_some_sel(
old_sel.end_pos,
new_pos
)?
} else {
mk_some_sel(
old_sel.start_pos,
new_pos
)?
}
} else if new_pos > caret_pos {
mk_some_sel(
new_pos,
old_sel.end_pos
)?
} else if new_pos < caret_pos {
mk_some_sel(
old_sel.start_pos,
new_pos
)?
} else { } else {
// TODO should this return none? mk_some_sel(new_pos, old_sel.end_pos)?
None
} }
} else if new_pos < self.caret_pos { } else if new_pos > old_sel.end_pos {
mk_some_sel( if caret_pos < old_sel.end_pos {
new_pos, mk_some_sel(old_sel.end_pos, new_pos)?
caret_pos } else {
)? mk_some_sel(old_sel.start_pos, new_pos)?
}
} else if new_pos > caret_pos {
mk_some_sel(new_pos, old_sel.end_pos)?
} else if new_pos < caret_pos {
mk_some_sel(old_sel.start_pos, new_pos)?
} else { } else {
mk_some_sel( // TODO should this return none?
caret_pos, None
new_pos
)?
} }
} else if new_pos < self.caret_pos {
mk_some_sel(new_pos, caret_pos)?
} else { } else {
None mk_some_sel(caret_pos, new_pos)?
} }
} else { } else {
self.selection_opt None
}; }
} else {
self.selection_opt
};
self.caret_pos = new_pos; self.caret_pos = new_pos;
self.selection_opt = valid_sel_opt; self.selection_opt = valid_sel_opt;
Ok(()) Ok(())
} }
} }

View file

@ -1,15 +1,13 @@
// Adapted from https://github.com/cessen/ropey by Nathan Vegdahl, licensed under the MIT license // Adapted from https://github.com/cessen/ropey by Nathan Vegdahl, licensed under the MIT license
use crate::ui::ui_error::{
UIResult,
};
use crate::ui::text::{ use crate::ui::text::{
text_pos::{TextPos}, selection::{RawSelection, Selection},
selection::{Selection, RawSelection}, text_pos::TextPos,
caret_w_select::CaretWSelect,
}; };
use crate::ui::ui_error::UIResult;
use bumpalo::collections::String as BumpString; use bumpalo::collections::String as BumpString;
use bumpalo::Bump; use bumpalo::Bump;
use winit::event::{ModifiersState, VirtualKeyCode};
pub trait Lines { pub trait Lines {
fn get_line(&self, line_nr: usize) -> UIResult<&str>; fn get_line(&self, line_nr: usize) -> UIResult<&str>;
@ -29,13 +27,13 @@ pub trait SelectableLines {
fn set_caret(&mut self, caret_pos: TextPos); fn set_caret(&mut self, caret_pos: TextPos);
fn move_caret_left(&mut self, shift_pressed: bool) -> UIResult<CaretWSelect>; fn move_caret_left(&mut self, shift_pressed: bool) -> UIResult<()>;
fn move_caret_right(&mut self, shift_pressed: bool) -> UIResult<CaretWSelect>; fn move_caret_right(&mut self, shift_pressed: bool) -> UIResult<()>;
fn move_caret_up(&mut self, shift_pressed: bool) -> UIResult<CaretWSelect>; fn move_caret_up(&mut self, shift_pressed: bool) -> UIResult<()>;
fn move_caret_down(&mut self, shift_pressed: bool) -> UIResult<CaretWSelect>; fn move_caret_down(&mut self, shift_pressed: bool) -> UIResult<()>;
fn get_selection(&self) -> Option<Selection>; fn get_selection(&self) -> Option<Selection>;
@ -47,15 +45,26 @@ pub trait SelectableLines {
fn set_sel_none(&mut self); fn set_sel_none(&mut self);
fn select_all(&mut self) -> UIResult<()>;
fn last_text_pos(&self) -> TextPos; fn last_text_pos(&self) -> TextPos;
} }
pub trait MutSelectableLines { pub trait MutSelectableLines {
fn insert_char(&mut self, new_char: &char) -> UIResult<()>; fn insert_char(&mut self, new_char: &char) -> UIResult<()>;
// could be for insertion, backspace, del...
fn handle_new_char(&mut self, received_char: &char) -> UIResult<()>;
fn insert_str(&mut self, new_str: &str) -> UIResult<()>; fn insert_str(&mut self, new_str: &str) -> UIResult<()>;
fn pop_char(&mut self); fn pop_char(&mut self) -> UIResult<()>;
fn del_selection(&mut self) -> UIResult<()>; fn del_selection(&mut self) -> UIResult<()>;
fn handle_key_down(
&mut self,
modifiers: &ModifiersState,
virtual_keycode: VirtualKeyCode,
) -> UIResult<()>;
} }

View file

@ -1,5 +1,5 @@
pub mod big_selectable_text;
pub mod caret_w_select; pub mod caret_w_select;
pub mod lines;
pub mod selection; pub mod selection;
pub mod text_pos; pub mod text_pos;
pub mod big_selectable_text;
pub mod lines;

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,3 @@
use std::cmp::Ordering; use std::cmp::Ordering;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -25,4 +24,4 @@ impl PartialEq for TextPos {
} }
} }
impl Eq for TextPos {} impl Eq for TextPos {}

View file

@ -47,4 +47,4 @@ impl From<UIError> for String {
fn from(ui_error: UIError) -> Self { fn from(ui_error: UIError) -> Self {
format!("{}", ui_error) format!("{}", ui_error)
} }
} }

View file

@ -1,15 +1,5 @@
pub fn is_newline(char_ref: &char) -> bool {
let newline_codes = vec!['\u{d}', '\n'];
use super::ui_error::{UIResult, OutOfBounds}; newline_codes.contains(char_ref)
use snafu::OptionExt; }
use std::slice::SliceIndex;
// replace vec methods that return Option with ones that return Result and proper Error
pub fn slice_get<T>(index: usize, slice: &[T]) -> UIResult<&<usize as SliceIndex<[T]>>::Output> {
let elt_ref = slice.get(index).context(OutOfBounds {
index,
collection_name: "Slice",
len: slice.len(),
})?;
Ok(elt_ref)
}