mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
show instructions if no file was opened, fmt
This commit is contained in:
parent
d6dc6dbf8b
commit
76e2edff97
15 changed files with 229 additions and 282 deletions
|
@ -3,7 +3,7 @@
|
|||
Run the following from the roc folder:
|
||||
|
||||
```
|
||||
cargo run edit
|
||||
cargo run edit examples/hello-world/Hello.roc
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
|
|
@ -27,19 +27,15 @@ pub enum EdError {
|
|||
backtrace: Backtrace,
|
||||
},
|
||||
#[snafu(display("MissingGlyphDims: glyph_dim_rect_opt was None for model. It needs to be set using the example_code_glyph_rect function."))]
|
||||
MissingGlyphDims {
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
#[snafu(display("FileOpenFailed: failed to open file with path {} with the following error: {}.", path_str, err_msg))]
|
||||
FileOpenFailed {
|
||||
path_str: String,
|
||||
err_msg: String,
|
||||
},
|
||||
MissingGlyphDims { backtrace: Backtrace },
|
||||
#[snafu(display(
|
||||
"FileOpenFailed: failed to open file with path {} with the following error: {}.",
|
||||
path_str,
|
||||
err_msg
|
||||
))]
|
||||
FileOpenFailed { path_str: String, err_msg: String },
|
||||
#[snafu(display("TextBufReadFailed: the file {} could be opened but we encountered the following error while trying to read it: {}.", path_str, err_msg))]
|
||||
TextBufReadFailed {
|
||||
path_str: String,
|
||||
err_msg: String
|
||||
}
|
||||
TextBufReadFailed { path_str: String, err_msg: String },
|
||||
}
|
||||
|
||||
pub type EdResult<T, E = EdError> = std::result::Result<T, E>;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Adapted from https://github.com/sotrh/learn-wgpu
|
||||
// by Benjamin Hansen, licensed under the MIT license
|
||||
use super::vertex::Vertex;
|
||||
use crate::graphics::primitives::rect::Rect;
|
||||
use crate::graphics::colors::to_slice;
|
||||
use crate::graphics::primitives::rect::Rect;
|
||||
use bumpalo::collections::Vec as BumpVec;
|
||||
use wgpu::util::{BufferInitDescriptor, DeviceExt};
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use crate::mvc::ed_model::EdModel;
|
||||
use crate::mvc::update::{move_caret_down, move_caret_left, move_caret_right, move_caret_up, MoveCaretFun};
|
||||
use crate::mvc::update::{
|
||||
move_caret_down, move_caret_left, move_caret_right, move_caret_up, MoveCaretFun,
|
||||
};
|
||||
use winit::event::{ElementState, ModifiersState, VirtualKeyCode};
|
||||
|
||||
pub fn handle_keydown(
|
||||
|
@ -15,18 +17,10 @@ pub fn handle_keydown(
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
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),
|
||||
Copy => {
|
||||
todo!("copy");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
pub mod ast;
|
||||
mod def;
|
||||
mod expr;
|
||||
pub mod roc_file;
|
||||
mod module;
|
||||
mod pattern;
|
||||
mod pool;
|
||||
pub mod roc_file;
|
||||
mod scope;
|
||||
mod types;
|
||||
|
|
|
@ -23,9 +23,10 @@ use crate::graphics::primitives::text::{
|
|||
};
|
||||
use crate::graphics::style::CODE_FONT_SIZE;
|
||||
use crate::graphics::style::CODE_TXT_XY;
|
||||
use crate::mvc::ed_model::EdModel;
|
||||
use crate::mvc::{ed_model, update, ed_view};
|
||||
use crate::mvc::app_model::AppModel;
|
||||
use crate::mvc::ed_model::EdModel;
|
||||
use crate::mvc::{ed_model, ed_view, update};
|
||||
use crate::resources::strings::NOTHING_OPENED;
|
||||
use crate::vec_result::get_res;
|
||||
use bumpalo::Bump;
|
||||
use cgmath::Vector2;
|
||||
|
@ -45,17 +46,18 @@ pub mod error;
|
|||
pub mod graphics;
|
||||
mod keyboard_input;
|
||||
pub mod lang;
|
||||
mod selection;
|
||||
mod mvc;
|
||||
mod resources;
|
||||
mod selection;
|
||||
mod text_buffer;
|
||||
mod util;
|
||||
mod vec_result;
|
||||
mod text_buffer;
|
||||
|
||||
/// 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.
|
||||
pub fn launch(filepaths: &[&Path]) -> io::Result<()> {
|
||||
//TODO support using multiple filepaths
|
||||
let first_path_opt = if !filepaths.is_empty(){
|
||||
let first_path_opt = if !filepaths.is_empty() {
|
||||
match get_res(0, filepaths) {
|
||||
Ok(path_ref_ref) => Some(*path_ref_ref),
|
||||
Err(e) => {
|
||||
|
@ -135,18 +137,15 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
|||
let mut glyph_brush = build_glyph_brush(&gpu_device, render_format)?;
|
||||
|
||||
let is_animating = true;
|
||||
let ed_model_opt =
|
||||
if let Some(file_path) = file_path_opt {
|
||||
let ed_model_res =
|
||||
ed_model::init_model(file_path);
|
||||
let ed_model_opt = if let Some(file_path) = file_path_opt {
|
||||
let ed_model_res = ed_model::init_model(file_path);
|
||||
|
||||
match ed_model_res {
|
||||
Ok(mut ed_model) => {
|
||||
ed_model.glyph_dim_rect_opt =
|
||||
Some(example_code_glyph_rect(&mut glyph_brush));
|
||||
ed_model.glyph_dim_rect_opt = Some(example_code_glyph_rect(&mut glyph_brush));
|
||||
|
||||
Some(ed_model)
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
print_err(&e);
|
||||
None
|
||||
|
@ -156,9 +155,7 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
|||
None
|
||||
};
|
||||
|
||||
let mut app_model = AppModel {
|
||||
ed_model_opt
|
||||
};
|
||||
let mut app_model = AppModel { ed_model_opt };
|
||||
|
||||
let mut keyboard_modifiers = ModifiersState::empty();
|
||||
|
||||
|
@ -258,14 +255,15 @@ fn run_event_loop(file_path_opt: Option<&Path>) -> Result<(), Box<dyn Error>> {
|
|||
|
||||
if let Some(ed_model) = &app_model.ed_model_opt {
|
||||
//TODO don't pass invisible lines
|
||||
//TODO show text if no file was opened
|
||||
queue_all_text(
|
||||
queue_editor_text(
|
||||
&size,
|
||||
&ed_model.text_buf.all_lines(),
|
||||
ed_model.caret_pos,
|
||||
CODE_TXT_XY.into(),
|
||||
&mut glyph_brush,
|
||||
);
|
||||
} else {
|
||||
queue_no_file_text(&size, NOTHING_OPENED, CODE_TXT_XY.into(), &mut glyph_brush);
|
||||
}
|
||||
|
||||
match draw_all_rects(
|
||||
|
@ -365,7 +363,7 @@ fn begin_render_pass<'a>(
|
|||
}
|
||||
|
||||
// returns bounding boxes for every glyph
|
||||
fn queue_all_text(
|
||||
fn queue_editor_text(
|
||||
size: &PhysicalSize<u32>,
|
||||
editor_lines: &str,
|
||||
caret_pos: Position,
|
||||
|
@ -396,3 +394,23 @@ fn queue_all_text(
|
|||
|
||||
queue_text_draw(&code_text, glyph_brush);
|
||||
}
|
||||
|
||||
fn queue_no_file_text(
|
||||
size: &PhysicalSize<u32>,
|
||||
text: &str,
|
||||
text_coords: Vector2<f32>,
|
||||
glyph_brush: &mut GlyphBrush<()>,
|
||||
) {
|
||||
let area_bounds = (size.width as f32, size.height as f32).into();
|
||||
|
||||
let code_text = Text {
|
||||
position: text_coords,
|
||||
area_bounds,
|
||||
color: CODE_COLOR.into(),
|
||||
text: text.to_owned(),
|
||||
size: CODE_FONT_SIZE,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
queue_text_draw(&code_text, glyph_brush);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
use super::ed_model::EdModel;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AppModel {
|
||||
pub ed_model_opt: Option<EdModel>
|
||||
pub ed_model_opt: Option<EdModel>,
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
use crate::error::EdResult;
|
||||
use crate::graphics::primitives::rect::Rect;
|
||||
use crate::text_buffer;
|
||||
use crate::text_buffer::TextBuffer;
|
||||
use crate::error::EdResult;
|
||||
use std::path::Path;
|
||||
use std::cmp::Ordering;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EdModel {
|
||||
|
@ -11,7 +11,7 @@ pub struct EdModel {
|
|||
pub caret_pos: Position,
|
||||
pub selection_opt: Option<RawSelection>,
|
||||
pub glyph_dim_rect_opt: Option<Rect>,
|
||||
pub has_focus: bool
|
||||
pub has_focus: bool,
|
||||
}
|
||||
|
||||
pub fn init_model(file_path: &Path) -> EdResult<EdModel> {
|
||||
|
@ -20,7 +20,7 @@ pub fn init_model(file_path: &Path) -> EdResult<EdModel> {
|
|||
caret_pos: Position { line: 0, column: 0 },
|
||||
selection_opt: None,
|
||||
glyph_dim_rect_opt: None,
|
||||
has_focus: true
|
||||
has_focus: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
|
||||
use super::ed_model::{EdModel, Position};
|
||||
use crate::graphics::primitives::rect::Rect;
|
||||
use crate::error::{EdResult, MissingGlyphDims};
|
||||
use crate::graphics::colors::CARET_COLOR;
|
||||
use crate::graphics::primitives::rect::Rect;
|
||||
use crate::selection::create_selection_rects;
|
||||
use crate::graphics::colors::{CARET_COLOR};
|
||||
use bumpalo::collections::Vec as BumpVec;
|
||||
use bumpalo::Bump;
|
||||
use snafu::{ensure};
|
||||
use snafu::ensure;
|
||||
|
||||
//TODO add editor text here as well
|
||||
|
||||
pub fn create_ed_rects<'a>(ed_model: &EdModel, arena: &'a Bump) -> EdResult<BumpVec<'a, Rect>> {
|
||||
ensure!(ed_model.glyph_dim_rect_opt.is_some(),
|
||||
MissingGlyphDims {}
|
||||
);
|
||||
ensure!(ed_model.glyph_dim_rect_opt.is_some(), MissingGlyphDims {});
|
||||
|
||||
let glyph_rect = ed_model.glyph_dim_rect_opt.unwrap();
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pub mod app_model;
|
||||
pub mod ed_model;
|
||||
pub mod ed_view;
|
||||
pub mod app_model;
|
||||
pub mod update;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use super::ed_model::{Position, RawSelection};
|
||||
use crate::text_buffer::TextBuffer;
|
||||
use crate::util::is_newline;
|
||||
use super::app_model::AppModel;
|
||||
use super::ed_model::EdModel;
|
||||
use super::ed_model::{Position, RawSelection};
|
||||
use crate::error::EdResult;
|
||||
use crate::text_buffer::TextBuffer;
|
||||
use crate::util::is_newline;
|
||||
use std::cmp::{max, min};
|
||||
|
||||
pub type MoveCaretFun =
|
||||
|
@ -343,12 +343,16 @@ pub fn handle_new_char(app_model: &mut AppModel, received_char: &char) -> EdResu
|
|||
_ => {
|
||||
if let Some(selection) = ed_model.selection_opt {
|
||||
del_selection(selection, ed_model)?;
|
||||
ed_model.text_buf.insert_char(ed_model.caret_pos, received_char)?;
|
||||
ed_model
|
||||
.text_buf
|
||||
.insert_char(ed_model.caret_pos, received_char)?;
|
||||
|
||||
ed_model.caret_pos =
|
||||
move_caret_right(ed_model.caret_pos, None, false, &ed_model.text_buf).0;
|
||||
} else {
|
||||
ed_model.text_buf.insert_char(old_caret_pos, received_char)?;
|
||||
ed_model
|
||||
.text_buf
|
||||
.insert_char(old_caret_pos, received_char)?;
|
||||
|
||||
ed_model.caret_pos = Position {
|
||||
line: old_caret_pos.line,
|
||||
|
@ -364,16 +368,19 @@ pub fn handle_new_char(app_model: &mut AppModel, received_char: &char) -> EdResu
|
|||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_update {
|
||||
use crate::selection::test_selection::{convert_dsl_to_selection, convert_selection_to_dsl, text_buffer_from_dsl_str, all_lines_vec};
|
||||
use crate::mvc::ed_model::{Position, EdModel, RawSelection};
|
||||
use crate::mvc::app_model::AppModel;
|
||||
use crate::mvc::update::{handle_new_char};
|
||||
use crate::mvc::ed_model::{EdModel, Position, RawSelection};
|
||||
use crate::mvc::update::handle_new_char;
|
||||
use crate::selection::test_selection::{
|
||||
all_lines_vec, convert_dsl_to_selection, convert_selection_to_dsl, text_buffer_from_dsl_str,
|
||||
};
|
||||
use crate::text_buffer::TextBuffer;
|
||||
|
||||
fn gen_caret_text_buf(lines: &[&str]) -> Result<(Position, Option<RawSelection>, TextBuffer), String> {
|
||||
fn gen_caret_text_buf(
|
||||
lines: &[&str],
|
||||
) -> Result<(Position, Option<RawSelection>, TextBuffer), String> {
|
||||
let lines_string_slice: Vec<String> = lines.iter().map(|l| l.to_string()).collect();
|
||||
let (selection_opt, caret_pos) = convert_dsl_to_selection(&lines_string_slice)?;
|
||||
let text_buf = text_buffer_from_dsl_str(&lines_string_slice);
|
||||
|
@ -381,17 +388,19 @@ mod test_update {
|
|||
Ok((caret_pos, selection_opt, text_buf))
|
||||
}
|
||||
|
||||
fn mock_app_model(text_buf: TextBuffer, caret_pos: Position, selection_opt: Option<RawSelection>) -> AppModel {
|
||||
fn mock_app_model(
|
||||
text_buf: TextBuffer,
|
||||
caret_pos: Position,
|
||||
selection_opt: Option<RawSelection>,
|
||||
) -> AppModel {
|
||||
AppModel {
|
||||
ed_model_opt: Some(
|
||||
EdModel{
|
||||
ed_model_opt: Some(EdModel {
|
||||
text_buf,
|
||||
caret_pos,
|
||||
selection_opt,
|
||||
glyph_dim_rect_opt: None,
|
||||
has_focus: true
|
||||
}
|
||||
)
|
||||
has_focus: true,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,7 +419,12 @@ mod test_update {
|
|||
|
||||
if let Some(ed_model) = app_model.ed_model_opt {
|
||||
let mut actual_lines = all_lines_vec(&ed_model.text_buf);
|
||||
let dsl_slice = convert_selection_to_dsl(ed_model.selection_opt, ed_model.caret_pos, &mut actual_lines).unwrap();
|
||||
let dsl_slice = convert_selection_to_dsl(
|
||||
ed_model.selection_opt,
|
||||
ed_model.caret_pos,
|
||||
&mut actual_lines,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(dsl_slice, expected_post_lines_str);
|
||||
} else {
|
||||
panic!("Mock AppModel did not have an EdModel.");
|
||||
|
@ -421,132 +435,75 @@ mod test_update {
|
|||
|
||||
#[test]
|
||||
fn insert_new_char_simple() -> Result<(), String> {
|
||||
assert_insert(
|
||||
&["|"], &["a|"], 'a'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["|"], &[" |"], ' '
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a|"], &["aa|"], 'a'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a|"], &["a |"], ' '
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a|\n", ""], &["ab|\n", ""], 'b'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a|\n", ""], &["ab|\n", ""], 'b'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "|"], &["a\n", "b|"], 'b'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "b\n", "c|"], &["a\n", "b\n", "cd|"], 'd'
|
||||
)?;
|
||||
assert_insert(&["|"], &["a|"], 'a')?;
|
||||
assert_insert(&["|"], &[" |"], ' ')?;
|
||||
assert_insert(&["a|"], &["aa|"], 'a')?;
|
||||
assert_insert(&["a|"], &["a |"], ' ')?;
|
||||
assert_insert(&["a|\n", ""], &["ab|\n", ""], 'b')?;
|
||||
assert_insert(&["a|\n", ""], &["ab|\n", ""], 'b')?;
|
||||
assert_insert(&["a\n", "|"], &["a\n", "b|"], 'b')?;
|
||||
assert_insert(&["a\n", "b\n", "c|"], &["a\n", "b\n", "cd|"], 'd')?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_new_char_mid() -> Result<(), String> {
|
||||
assert_insert(
|
||||
&["ab|d"], &["abc|d"], 'c'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a|cd"], &["ab|cd"], 'b'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "|e"], &["abc\n", "d|e"], 'd'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "def\n", "| "], &["abc\n", "def\n", "g| "], 'g'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "def\n", "| "], &["abc\n", "def\n", " | "], ' '
|
||||
)?;
|
||||
|
||||
assert_insert(&["ab|d"], &["abc|d"], 'c')?;
|
||||
assert_insert(&["a|cd"], &["ab|cd"], 'b')?;
|
||||
assert_insert(&["abc\n", "|e"], &["abc\n", "d|e"], 'd')?;
|
||||
assert_insert(&["abc\n", "def\n", "| "], &["abc\n", "def\n", "g| "], 'g')?;
|
||||
assert_insert(&["abc\n", "def\n", "| "], &["abc\n", "def\n", " | "], ' ')?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_backspace() -> Result<(), String> {
|
||||
assert_insert(
|
||||
&["|"], &["|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&[" |"], &["|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a|"], &["|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["ab|"], &["a|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a|\n", ""], &["|\n", ""], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["ab|\n", ""], &["a|\n", ""], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "|"], &["a|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "b\n", "c|"], &["a\n", "b\n", "|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "b\n", "|"], &["a\n", "b|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(&["|"], &["|"], '\u{8}')?;
|
||||
assert_insert(&[" |"], &["|"], '\u{8}')?;
|
||||
assert_insert(&["a|"], &["|"], '\u{8}')?;
|
||||
assert_insert(&["ab|"], &["a|"], '\u{8}')?;
|
||||
assert_insert(&["a|\n", ""], &["|\n", ""], '\u{8}')?;
|
||||
assert_insert(&["ab|\n", ""], &["a|\n", ""], '\u{8}')?;
|
||||
assert_insert(&["a\n", "|"], &["a|"], '\u{8}')?;
|
||||
assert_insert(&["a\n", "b\n", "c|"], &["a\n", "b\n", "|"], '\u{8}')?;
|
||||
assert_insert(&["a\n", "b\n", "|"], &["a\n", "b|"], '\u{8}')?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selection_backspace() -> Result<(), String> {
|
||||
assert_insert(&["[a]|"], &["|"], '\u{8}')?;
|
||||
assert_insert(&["a[a]|"], &["a|"], '\u{8}')?;
|
||||
assert_insert(&["[aa]|"], &["|"], '\u{8}')?;
|
||||
assert_insert(&["a[b c]|"], &["a|"], '\u{8}')?;
|
||||
assert_insert(&["[abc]|\n", ""], &["|\n", ""], '\u{8}')?;
|
||||
assert_insert(&["a\n", "[abc]|"], &["a\n", "|"], '\u{8}')?;
|
||||
assert_insert(&["[a\n", "abc]|"], &["|"], '\u{8}')?;
|
||||
assert_insert(&["a[b\n", "cdef ghij]|"], &["a|"], '\u{8}')?;
|
||||
assert_insert(&["[a\n", "b\n", "c]|"], &["|"], '\u{8}')?;
|
||||
assert_insert(&["a\n", "[b\n", "]|"], &["a\n", "|"], '\u{8}')?;
|
||||
assert_insert(
|
||||
&["[a]|"], &["|"], '\u{8}'
|
||||
&["abc\n", "d[ef\n", "ghi]|\n", "jkl"],
|
||||
&["abc\n", "d|\n", "jkl"],
|
||||
'\u{8}',
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a[a]|"], &["a|"], '\u{8}'
|
||||
&["abc\n", "[def\n", "ghi]|\n", "jkl"],
|
||||
&["abc\n", "|\n", "jkl"],
|
||||
'\u{8}',
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[aa]|"], &["|"], '\u{8}'
|
||||
&["abc\n", "\n", "[def\n", "ghi]|\n", "jkl"],
|
||||
&["abc\n", "\n", "|\n", "jkl"],
|
||||
'\u{8}',
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a[b c]|"], &["a|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[abc]|\n", ""], &["|\n", ""], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "[abc]|"], &["a\n","|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[a\n", "abc]|"], &["|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a[b\n", "cdef ghij]|"], &["a|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[a\n", "b\n", "c]|"], &["|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "[b\n", "]|"], &["a\n", "|"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "d[ef\n", "ghi]|\n", "jkl"], &["abc\n", "d|\n", "jkl"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "[def\n", "ghi]|\n", "jkl"], &["abc\n", "|\n", "jkl"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "\n", "[def\n", "ghi]|\n", "jkl"], &["abc\n", "\n", "|\n", "jkl"], '\u{8}'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[abc\n", "\n", "def\n", "ghi\n", "jkl]|"], &["|"], '\u{8}'
|
||||
&["[abc\n", "\n", "def\n", "ghi\n", "jkl]|"],
|
||||
&["|"],
|
||||
'\u{8}',
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -554,48 +511,32 @@ mod test_update {
|
|||
|
||||
#[test]
|
||||
fn insert_with_selection() -> Result<(), String> {
|
||||
assert_insert(&["[a]|"], &["z|"], 'z')?;
|
||||
assert_insert(&["a[a]|"], &["az|"], 'z')?;
|
||||
assert_insert(&["[aa]|"], &["z|"], 'z')?;
|
||||
assert_insert(&["a[b c]|"], &["az|"], 'z')?;
|
||||
assert_insert(&["[abc]|\n", ""], &["z|\n", ""], 'z')?;
|
||||
assert_insert(&["a\n", "[abc]|"], &["a\n", "z|"], 'z')?;
|
||||
assert_insert(&["[a\n", "abc]|"], &["z|"], 'z')?;
|
||||
assert_insert(&["a[b\n", "cdef ghij]|"], &["az|"], 'z')?;
|
||||
assert_insert(&["[a\n", "b\n", "c]|"], &["z|"], 'z')?;
|
||||
assert_insert(&["a\n", "[b\n", "]|"], &["a\n", "z|"], 'z')?;
|
||||
assert_insert(
|
||||
&["[a]|"], &["z|"], 'z'
|
||||
&["abc\n", "d[ef\n", "ghi]|\n", "jkl"],
|
||||
&["abc\n", "dz|\n", "jkl"],
|
||||
'z',
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a[a]|"], &["az|"], 'z'
|
||||
&["abc\n", "[def\n", "ghi]|\n", "jkl"],
|
||||
&["abc\n", "z|\n", "jkl"],
|
||||
'z',
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[aa]|"], &["z|"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a[b c]|"], &["az|"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[abc]|\n", ""], &["z|\n", ""], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "[abc]|"], &["a\n","z|"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[a\n", "abc]|"], &["z|"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a[b\n", "cdef ghij]|"], &["az|"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[a\n", "b\n", "c]|"], &["z|"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["a\n", "[b\n", "]|"], &["a\n", "z|"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "d[ef\n", "ghi]|\n", "jkl"], &["abc\n", "dz|\n", "jkl"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "[def\n", "ghi]|\n", "jkl"], &["abc\n", "z|\n", "jkl"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["abc\n", "\n", "[def\n", "ghi]|\n", "jkl"], &["abc\n", "\n", "z|\n", "jkl"], 'z'
|
||||
)?;
|
||||
assert_insert(
|
||||
&["[abc\n", "\n", "def\n", "ghi\n", "jkl]|"], &["z|"], 'z'
|
||||
&["abc\n", "\n", "[def\n", "ghi]|\n", "jkl"],
|
||||
&["abc\n", "\n", "z|\n", "jkl"],
|
||||
'z',
|
||||
)?;
|
||||
assert_insert(&["[abc\n", "\n", "def\n", "ghi\n", "jkl]|"], &["z|"], 'z')?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
1
editor/src/resources/mod.rs
Normal file
1
editor/src/resources/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub mod strings;
|
|
@ -1 +1 @@
|
|||
pub const NOTHING_OPENED: &str = "Execute `cargo run edit <filename>` to open a file";
|
||||
pub const NOTHING_OPENED: &str = "Execute `cargo run edit <filename>` to open a file.";
|
||||
|
|
|
@ -126,13 +126,15 @@ pub fn create_selection_rects<'a>(
|
|||
pub mod test_selection {
|
||||
use crate::error::{EdResult, OutOfBounds};
|
||||
use crate::mvc::ed_model::{Position, RawSelection};
|
||||
use crate::mvc::update::{move_caret_down, move_caret_left, move_caret_right, move_caret_up, MoveCaretFun};
|
||||
use crate::vec_result::get_res;
|
||||
use crate::mvc::update::{
|
||||
move_caret_down, move_caret_left, move_caret_right, move_caret_up, MoveCaretFun,
|
||||
};
|
||||
use crate::text_buffer::TextBuffer;
|
||||
use crate::vec_result::get_res;
|
||||
use core::cmp::Ordering;
|
||||
use pest::Parser;
|
||||
use snafu::OptionExt;
|
||||
use ropey::Rope;
|
||||
use snafu::OptionExt;
|
||||
use std::collections::HashMap;
|
||||
use std::slice::SliceIndex;
|
||||
|
||||
|
@ -204,7 +206,7 @@ pub mod test_selection {
|
|||
let elt_ref = vec.get_mut(index).context(OutOfBounds {
|
||||
index,
|
||||
collection_name: "Slice",
|
||||
len: vec_len
|
||||
len: vec_len,
|
||||
})?;
|
||||
|
||||
Ok(elt_ref)
|
||||
|
@ -223,7 +225,7 @@ pub mod test_selection {
|
|||
.iter()
|
||||
.map(|line| line.replace(&['[', ']', '|'][..], ""))
|
||||
.collect::<Vec<String>>()
|
||||
.join("")
|
||||
.join(""),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -358,8 +360,7 @@ pub mod test_selection {
|
|||
|
||||
let (sel_opt, caret_pos) = convert_dsl_to_selection(&pre_lines)?;
|
||||
|
||||
let clean_text_buf =
|
||||
text_buffer_from_dsl_str(&pre_lines);
|
||||
let clean_text_buf = text_buffer_from_dsl_str(&pre_lines);
|
||||
|
||||
let (new_caret_pos, new_sel_opt) =
|
||||
move_fun(caret_pos, sel_opt, shift_pressed, &clean_text_buf);
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
|
||||
// Adapted from https://github.com/cessen/ropey by Nathan Vegdahl, licensed under the MIT license
|
||||
|
||||
use crate::error::EdError::{FileOpenFailed, TextBufReadFailed};
|
||||
use crate::error::EdResult;
|
||||
use crate::error::OutOfBounds;
|
||||
use crate::error::EdError::{TextBufReadFailed, FileOpenFailed};
|
||||
use crate::mvc::ed_model::{Position, RawSelection};
|
||||
use crate::selection::{validate_selection};
|
||||
use crate::selection::validate_selection;
|
||||
use ropey::Rope;
|
||||
use snafu::{ensure, OptionExt};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use ropey::{Rope};
|
||||
use snafu::{ensure, OptionExt};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TextBuffer {
|
||||
|
@ -23,11 +21,14 @@ impl TextBuffer {
|
|||
pub fn insert_char(&mut self, caret_pos: Position, new_char: &char) -> EdResult<()> {
|
||||
let char_indx = self.pos_to_char_indx(caret_pos);
|
||||
|
||||
ensure!(char_indx <= self.text_rope.len_chars(), OutOfBounds{
|
||||
ensure!(
|
||||
char_indx <= self.text_rope.len_chars(),
|
||||
OutOfBounds {
|
||||
index: char_indx,
|
||||
collection_name: "Rope",
|
||||
len: self.text_rope.len_chars()
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
self.text_rope.insert(char_indx, &new_char.to_string());
|
||||
|
||||
|
@ -45,11 +46,14 @@ impl TextBuffer {
|
|||
pub fn del_selection(&mut self, raw_sel: RawSelection) -> EdResult<()> {
|
||||
let (start_char_indx, end_char_indx) = self.sel_to_tup(raw_sel)?;
|
||||
|
||||
ensure!(end_char_indx <= self.text_rope.len_chars(), OutOfBounds{
|
||||
ensure!(
|
||||
end_char_indx <= self.text_rope.len_chars(),
|
||||
OutOfBounds {
|
||||
index: end_char_indx,
|
||||
collection_name: "Rope",
|
||||
len: self.text_rope.len_chars()
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
self.text_rope.remove(start_char_indx..end_char_indx);
|
||||
|
||||
|
@ -76,7 +80,7 @@ impl TextBuffer {
|
|||
self.line_len(line_nr).context(OutOfBounds {
|
||||
index: line_nr,
|
||||
collection_name: "Rope",
|
||||
len: self.text_rope.len_lines()
|
||||
len: self.text_rope.len_lines(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -132,20 +136,16 @@ fn rope_from_path(path: &Path) -> EdResult<Rope> {
|
|||
Ok(file) => {
|
||||
let buf_reader = &mut io::BufReader::new(file);
|
||||
match Rope::from_reader(buf_reader) {
|
||||
Ok(rope) =>
|
||||
Ok(rope),
|
||||
Err(e) =>
|
||||
Err(TextBufReadFailed {
|
||||
Ok(rope) => Ok(rope),
|
||||
Err(e) => Err(TextBufReadFailed {
|
||||
path_str: path_to_string(path),
|
||||
err_msg: e.to_string()
|
||||
})
|
||||
err_msg: e.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
Err(FileOpenFailed {
|
||||
Err(e) => Err(FileOpenFailed {
|
||||
path_str: path_to_string(path),
|
||||
err_msg: e.to_string()
|
||||
})
|
||||
}
|
||||
err_msg: e.to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue