mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 23:04:49 +00:00
finished tests, some restructuring, bugfixes
This commit is contained in:
parent
a5ac077ec9
commit
f3f57a13ef
9 changed files with 189 additions and 198 deletions
|
@ -15,12 +15,12 @@ pub enum EdError {
|
||||||
#[snafu(display("ClipboardWriteFailed: could not set clipboard contents: {}", err_msg))]
|
#[snafu(display("ClipboardWriteFailed: could not set clipboard contents: {}", err_msg))]
|
||||||
ClipboardWriteFailed { err_msg: String },
|
ClipboardWriteFailed { err_msg: String },
|
||||||
|
|
||||||
#[snafu(display("ClipboardInitFailed: could not initialize ClipboardContext: {}.", err_msg))]
|
#[snafu(display(
|
||||||
|
"ClipboardInitFailed: could not initialize ClipboardContext: {}.",
|
||||||
|
err_msg
|
||||||
|
))]
|
||||||
ClipboardInitFailed { err_msg: String },
|
ClipboardInitFailed { err_msg: String },
|
||||||
|
|
||||||
#[snafu(display("EdModelIsNone: editor model EdModel was never succesfully initiliazed."))]
|
|
||||||
EdModelIsNone { },
|
|
||||||
|
|
||||||
#[snafu(display(
|
#[snafu(display(
|
||||||
"FileOpenFailed: failed to open file with path {} with the following error: {}.",
|
"FileOpenFailed: failed to open file with path {} with the following error: {}.",
|
||||||
path_str,
|
path_str,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::error::EdResult;
|
use crate::error::EdResult;
|
||||||
use crate::mvc::app_model::AppModel;
|
use crate::mvc::app_model::AppModel;
|
||||||
use crate::mvc::app_update::{pass_keydown_to_focused, handle_copy, handle_paste};
|
use crate::mvc::app_update::{handle_copy, handle_paste, pass_keydown_to_focused};
|
||||||
use winit::event::{ElementState, ModifiersState, VirtualKeyCode};
|
|
||||||
use winit::event::VirtualKeyCode::*;
|
use winit::event::VirtualKeyCode::*;
|
||||||
|
use winit::event::{ElementState, ModifiersState, VirtualKeyCode};
|
||||||
|
|
||||||
pub fn handle_keydown(
|
pub fn handle_keydown(
|
||||||
elem_state: ElementState,
|
elem_state: ElementState,
|
||||||
|
@ -10,9 +10,8 @@ pub fn handle_keydown(
|
||||||
modifiers: ModifiersState,
|
modifiers: ModifiersState,
|
||||||
app_model: &mut AppModel,
|
app_model: &mut AppModel,
|
||||||
) -> EdResult<()> {
|
) -> EdResult<()> {
|
||||||
|
|
||||||
if let ElementState::Released = elem_state {
|
if let ElementState::Released = elem_state {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
match virtual_keycode {
|
match virtual_keycode {
|
||||||
|
@ -28,17 +27,23 @@ pub fn handle_keydown(
|
||||||
todo!("cut");
|
todo!("cut");
|
||||||
}
|
}
|
||||||
|
|
||||||
C => if modifiers.ctrl() {
|
C => {
|
||||||
handle_copy(app_model)?
|
if modifiers.ctrl() {
|
||||||
},
|
handle_copy(app_model)?
|
||||||
V => if modifiers.ctrl() {
|
}
|
||||||
handle_paste(app_model)?
|
}
|
||||||
},
|
V => {
|
||||||
X => if modifiers.ctrl() {
|
if modifiers.ctrl() {
|
||||||
//handle_cut(app_model)?
|
handle_paste(app_model)?
|
||||||
todo!("cut");
|
}
|
||||||
},
|
}
|
||||||
_ => ()
|
X => {
|
||||||
|
if modifiers.ctrl() {
|
||||||
|
//handle_cut(app_model)?
|
||||||
|
todo!("cut");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::graphics::style::CODE_FONT_SIZE;
|
||||||
use crate::graphics::style::CODE_TXT_XY;
|
use crate::graphics::style::CODE_TXT_XY;
|
||||||
use crate::mvc::app_model::AppModel;
|
use crate::mvc::app_model::AppModel;
|
||||||
use crate::mvc::ed_model::EdModel;
|
use crate::mvc::ed_model::EdModel;
|
||||||
use crate::mvc::{ed_model, ed_view, app_update};
|
use crate::mvc::{app_update, ed_model, ed_view};
|
||||||
use crate::resources::strings::NOTHING_OPENED;
|
use crate::resources::strings::NOTHING_OPENED;
|
||||||
use crate::vec_result::get_res;
|
use crate::vec_result::get_res;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use super::ed_model::EdModel;
|
use super::ed_model::EdModel;
|
||||||
use crate::error::{EdResult, print_err};
|
use crate::error::EdError::{ClipboardInitFailed, ClipboardReadFailed, ClipboardWriteFailed};
|
||||||
use crate::error::EdError::{ClipboardReadFailed, ClipboardWriteFailed, ClipboardInitFailed, EdModelIsNone};
|
use crate::error::{print_err, EdResult};
|
||||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AppModel {
|
pub struct AppModel {
|
||||||
pub ed_model_opt: Option<EdModel>,
|
pub ed_model_opt: Option<EdModel>,
|
||||||
|
@ -13,59 +12,38 @@ pub struct AppModel {
|
||||||
|
|
||||||
impl AppModel {
|
impl AppModel {
|
||||||
pub fn init(ed_model_opt: Option<EdModel>) -> AppModel {
|
pub fn init(ed_model_opt: Option<EdModel>) -> AppModel {
|
||||||
let clipboard_res = Clipboard::init();
|
|
||||||
|
|
||||||
let clipboard_opt =
|
|
||||||
match clipboard_res {
|
|
||||||
Ok(clipboard) => Some(clipboard),
|
|
||||||
Err(e) => {
|
|
||||||
print_err(&e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
AppModel {
|
AppModel {
|
||||||
ed_model_opt,
|
ed_model_opt,
|
||||||
clipboard_opt
|
clipboard_opt: AppModel::init_clipboard_opt(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ed_model(&self) -> EdResult<&EdModel> {
|
pub fn init_clipboard_opt() -> Option<Clipboard> {
|
||||||
if let Some(ref ed_model) = self.ed_model_opt {
|
let clipboard_res = Clipboard::init();
|
||||||
Ok(ed_model)
|
|
||||||
} else {
|
|
||||||
Err(EdModelIsNone {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_ed_model_mut(&mut self) -> EdResult<& mut EdModel> {
|
match clipboard_res {
|
||||||
if let Some(ref mut ed_model) = self.ed_model_opt {
|
Ok(clipboard) => Some(clipboard),
|
||||||
Ok(ed_model)
|
Err(e) => {
|
||||||
} else {
|
print_err(&e);
|
||||||
Err(EdModelIsNone {})
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Clipboard {
|
pub struct Clipboard {
|
||||||
context: ClipboardContext
|
context: ClipboardContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clipboard {
|
impl Clipboard {
|
||||||
|
|
||||||
pub fn init() -> EdResult<Clipboard> {
|
pub fn init() -> EdResult<Clipboard> {
|
||||||
let context_res = ClipboardProvider::new();
|
let context_res = ClipboardProvider::new();
|
||||||
|
|
||||||
match context_res {
|
match context_res {
|
||||||
Ok(context) => Ok(
|
Ok(context) => Ok(Clipboard { context }),
|
||||||
Clipboard {
|
|
||||||
context
|
|
||||||
}
|
|
||||||
),
|
|
||||||
Err(e) => Err(ClipboardInitFailed {
|
Err(e) => Err(ClipboardInitFailed {
|
||||||
err_msg: e.to_string()
|
err_msg: e.to_string(),
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,8 +54,8 @@ impl Clipboard {
|
||||||
match content_res {
|
match content_res {
|
||||||
Ok(content_str) => Ok(content_str),
|
Ok(content_str) => Ok(content_str),
|
||||||
Err(e) => Err(ClipboardReadFailed {
|
Err(e) => Err(ClipboardReadFailed {
|
||||||
err_msg: e.to_string()
|
err_msg: e.to_string(),
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,16 +65,37 @@ impl Clipboard {
|
||||||
match content_set_res {
|
match content_set_res {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(e) => Err(ClipboardWriteFailed {
|
Err(e) => Err(ClipboardWriteFailed {
|
||||||
err_msg: e.to_string()
|
err_msg: e.to_string(),
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_clipboard_txt(clipboard_opt: &mut Option<Clipboard>, txt: &str) -> EdResult<()> {
|
||||||
|
if let Some(ref mut clipboard) = clipboard_opt {
|
||||||
|
clipboard.set_content(txt.to_owned())?;
|
||||||
|
} else {
|
||||||
|
return Err(ClipboardWriteFailed {
|
||||||
|
err_msg: "Clipboard was never initialized succesfully.".to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_clipboard_txt(clipboard_opt: &mut Option<Clipboard>) -> EdResult<String> {
|
||||||
|
if let Some(ref mut clipboard) = clipboard_opt {
|
||||||
|
clipboard.get_content()
|
||||||
|
} else {
|
||||||
|
Err(ClipboardReadFailed {
|
||||||
|
err_msg: "Clipboard was never initialized succesfully.".to_owned(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Clipboard {
|
impl fmt::Debug for Clipboard {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// showing the clipboard would require a mut ref which is not possible
|
// showing the clipboard would require a mut ref which is not possible
|
||||||
f.debug_struct("Clipboard (can't show)")
|
f.debug_struct("Clipboard (can't show)").finish()
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,17 @@
|
||||||
|
use super::app_model;
|
||||||
use super::app_model::AppModel;
|
use super::app_model::AppModel;
|
||||||
|
use super::ed_model::Position;
|
||||||
use super::ed_update;
|
use super::ed_update;
|
||||||
use super::ed_model::{Position};
|
|
||||||
use crate::error::EdResult;
|
use crate::error::EdResult;
|
||||||
use crate::error::EdError::{ClipboardWriteFailed, ClipboardReadFailed};
|
|
||||||
use winit::event::{ModifiersState, VirtualKeyCode};
|
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 {
|
||||||
if ed_model.has_focus {
|
if ed_model.has_focus {
|
||||||
let selected_str_opt = super::ed_model::get_selected_str(ed_model)?;
|
let selected_str_opt = super::ed_model::get_selected_str(ed_model)?;
|
||||||
|
|
||||||
if let Some(selected_str) = selected_str_opt {
|
if let Some(selected_str) = selected_str_opt {
|
||||||
if let Some(ref mut clipboard) = app_model.clipboard_opt {
|
app_model::set_clipboard_txt(&mut app_model.clipboard_opt, selected_str)?;
|
||||||
clipboard.set_content(selected_str.to_owned())?;
|
|
||||||
} else {
|
|
||||||
return Err(ClipboardWriteFailed {
|
|
||||||
err_msg: "Clipboard was never initialized succesfully.".to_owned()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,52 +20,55 @@ pub fn handle_copy(app_model: &mut AppModel) -> EdResult<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_paste(app_model: &mut AppModel) -> EdResult<()> {
|
pub fn handle_paste(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 {
|
||||||
if let Some(ref mut clipboard) = app_model.clipboard_opt {
|
let clipboard_content = app_model::get_clipboard_txt(&mut app_model.clipboard_opt)?;
|
||||||
let clipboard_content = clipboard.get_content()?;
|
|
||||||
|
|
||||||
if !clipboard_content.is_empty() {
|
if !clipboard_content.is_empty() {
|
||||||
|
let mut rsplit_iter = clipboard_content.rsplit('\n');
|
||||||
|
// safe unwrap because we checked if empty
|
||||||
|
let last_line_nr_chars = rsplit_iter.next().unwrap().len();
|
||||||
|
let clipboard_nr_lines = rsplit_iter.count();
|
||||||
|
|
||||||
let mut rsplit_iter = clipboard_content.rsplit('\n');
|
let old_caret_pos = ed_model.caret_pos;
|
||||||
// safe unwrap because we checked if empty
|
|
||||||
let last_line_nr_chars = rsplit_iter.next().unwrap().len();
|
|
||||||
let clipboard_nr_lines = rsplit_iter.count();
|
|
||||||
|
|
||||||
let old_caret_pos = ed_model.caret_pos;
|
if let Some(selection) = ed_model.selection_opt {
|
||||||
|
let start_caret_pos = selection.start_pos;
|
||||||
|
ed_model.text_buf.del_selection(selection)?;
|
||||||
|
ed_model.selection_opt = None;
|
||||||
|
|
||||||
if let Some(selection) = ed_model.selection_opt {
|
ed_model
|
||||||
let start_caret_pos = selection.start_pos;
|
.text_buf
|
||||||
ed_model.text_buf.del_selection(selection)?;
|
.insert_str(start_caret_pos, &clipboard_content)?;
|
||||||
ed_model.selection_opt = None;
|
|
||||||
|
|
||||||
ed_model.text_buf.insert_str(
|
|
||||||
start_caret_pos,
|
|
||||||
&clipboard_content
|
|
||||||
)?;
|
|
||||||
|
|
||||||
|
if clipboard_nr_lines > 0 {
|
||||||
ed_model.caret_pos = Position {
|
ed_model.caret_pos = Position {
|
||||||
line: start_caret_pos.line + clipboard_nr_lines,
|
line: start_caret_pos.line + clipboard_nr_lines,
|
||||||
column: start_caret_pos.column + last_line_nr_chars
|
column: last_line_nr_chars,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ed_model.text_buf.insert_str(
|
ed_model.caret_pos = Position {
|
||||||
old_caret_pos,
|
line: start_caret_pos.line,
|
||||||
&clipboard_content
|
column: start_caret_pos.column + last_line_nr_chars,
|
||||||
)?;
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ed_model
|
||||||
|
.text_buf
|
||||||
|
.insert_str(old_caret_pos, &clipboard_content)?;
|
||||||
|
|
||||||
|
if clipboard_nr_lines > 0 {
|
||||||
ed_model.caret_pos = Position {
|
ed_model.caret_pos = Position {
|
||||||
line: old_caret_pos.line + clipboard_nr_lines,
|
line: old_caret_pos.line + clipboard_nr_lines,
|
||||||
column: old_caret_pos.column + last_line_nr_chars
|
column: last_line_nr_chars,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ed_model.caret_pos = Position {
|
||||||
|
line: old_caret_pos.line,
|
||||||
|
column: old_caret_pos.column + last_line_nr_chars,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
return Err(ClipboardReadFailed {
|
|
||||||
err_msg: "Clipboard was never initialized succesfully.".to_owned()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +88,7 @@ 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_update::handle_new_char(received_char, ed_model)?;
|
||||||
|
@ -104,108 +100,107 @@ pub fn handle_new_char(received_char: &char, app_model: &mut AppModel) -> EdResu
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test_app_update {
|
pub mod test_app_update {
|
||||||
|
use crate::mvc::app_model;
|
||||||
use crate::mvc::app_model::{AppModel, Clipboard};
|
use crate::mvc::app_model::{AppModel, Clipboard};
|
||||||
use crate::mvc::app_update::{handle_copy, handle_paste};
|
use crate::mvc::app_update::{handle_copy, handle_paste};
|
||||||
use crate::mvc::ed_update::test_ed_update::{gen_caret_text_buf};
|
|
||||||
use crate::mvc::ed_model::{EdModel, Position, RawSelection};
|
use crate::mvc::ed_model::{EdModel, Position, RawSelection};
|
||||||
use crate::selection::test_selection::{convert_selection_to_dsl, all_lines_vec};
|
use crate::mvc::ed_update::test_ed_update::gen_caret_text_buf;
|
||||||
|
use crate::selection::test_selection::{all_lines_vec, convert_selection_to_dsl};
|
||||||
use crate::text_buffer::TextBuffer;
|
use crate::text_buffer::TextBuffer;
|
||||||
use crate::error::EdResult;
|
|
||||||
use crate::error::EdError::ClipboardInitFailed;
|
|
||||||
|
|
||||||
pub fn mock_app_model(
|
pub fn mock_app_model(
|
||||||
text_buf: TextBuffer,
|
text_buf: TextBuffer,
|
||||||
caret_pos: Position,
|
caret_pos: Position,
|
||||||
selection_opt: Option<RawSelection>,
|
selection_opt: Option<RawSelection>,
|
||||||
|
clipboard_opt: Option<Clipboard>,
|
||||||
) -> AppModel {
|
) -> AppModel {
|
||||||
AppModel::init(
|
AppModel {
|
||||||
Some(
|
ed_model_opt: Some(EdModel {
|
||||||
EdModel {
|
text_buf,
|
||||||
text_buf,
|
caret_pos,
|
||||||
caret_pos,
|
selection_opt,
|
||||||
selection_opt,
|
glyph_dim_rect_opt: None,
|
||||||
glyph_dim_rect_opt: None,
|
has_focus: true,
|
||||||
has_focus: true,
|
}),
|
||||||
}
|
clipboard_opt,
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_clipboard(app_model: &mut AppModel) -> EdResult<&mut Clipboard> {
|
|
||||||
if let Some(ref mut clipboard) = app_model.clipboard_opt {
|
|
||||||
Ok(clipboard)
|
|
||||||
} else {
|
|
||||||
Err(ClipboardInitFailed {
|
|
||||||
err_msg: "Clipboard was never initialized succesfully.".to_owned()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_copy(
|
fn assert_copy(
|
||||||
pre_lines_str: &[&str],
|
pre_lines_str: &[&str],
|
||||||
expected_clipboard_content: &str,
|
expected_clipboard_content: &str,
|
||||||
) -> Result<(), String> {
|
clipboard_opt: Option<Clipboard>,
|
||||||
|
) -> Result<Option<Clipboard>, String> {
|
||||||
let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?;
|
let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?;
|
||||||
|
|
||||||
let mut app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt);
|
let mut app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt, clipboard_opt);
|
||||||
|
|
||||||
handle_copy(&mut app_model)?;
|
handle_copy(&mut app_model)?;
|
||||||
|
|
||||||
let clipboard = get_clipboard(&mut app_model)?;
|
let clipboard_content = app_model::get_clipboard_txt(&mut app_model.clipboard_opt)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(clipboard_content, expected_clipboard_content);
|
||||||
clipboard.get_content()?,
|
|
||||||
expected_clipboard_content
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(app_model.clipboard_opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_paste(
|
fn assert_paste(
|
||||||
pre_lines_str: &[&str],
|
pre_lines_str: &[&str],
|
||||||
clipboard_content: &str,
|
clipboard_content: &str,
|
||||||
expected_post_lines_str: &[&str],
|
expected_post_lines_str: &[&str],
|
||||||
) -> Result<(), String> {
|
clipboard_opt: Option<Clipboard>,
|
||||||
|
) -> Result<Option<Clipboard>, String> {
|
||||||
let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?;
|
let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?;
|
||||||
|
|
||||||
let mut app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt);
|
let mut app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt, clipboard_opt);
|
||||||
let clipboard = get_clipboard(&mut app_model)?;
|
|
||||||
clipboard.set_content(clipboard_content.to_owned())?;
|
app_model::set_clipboard_txt(&mut app_model.clipboard_opt, clipboard_content)?;
|
||||||
|
|
||||||
handle_paste(&mut app_model)?;
|
handle_paste(&mut app_model)?;
|
||||||
|
|
||||||
let ed_model = app_model.get_ed_model()?;
|
let ed_model = app_model.ed_model_opt.unwrap();
|
||||||
let mut text_buf_lines = all_lines_vec(&ed_model.text_buf);
|
let mut text_buf_lines = all_lines_vec(&ed_model.text_buf);
|
||||||
let post_lines_str = convert_selection_to_dsl(
|
let post_lines_str = convert_selection_to_dsl(
|
||||||
ed_model.selection_opt,
|
ed_model.selection_opt,
|
||||||
ed_model.caret_pos,
|
ed_model.caret_pos,
|
||||||
&mut text_buf_lines
|
&mut text_buf_lines,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(post_lines_str, expected_post_lines_str);
|
||||||
post_lines_str,
|
|
||||||
expected_post_lines_str
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(app_model.clipboard_opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn copy() -> Result<(), String> {
|
fn copy_paste() -> Result<(), String> {
|
||||||
assert_copy(&["[a]|"], "a")?;
|
// can only init clipboard once
|
||||||
assert_copy(&["|[b]"], "b")?;
|
let mut clipboard_opt = AppModel::init_clipboard_opt();
|
||||||
assert_copy(&["a[ ]|"], " ")?;
|
|
||||||
assert_copy(&["[ ]|b"], " ")?;
|
|
||||||
assert_copy(&["a\n", "[b\n", "]|"], "b\n")?;
|
|
||||||
assert_copy(&["[a\n", " b\n", "]|"], "a\n b\n")?;
|
|
||||||
assert_copy(&["abc\n", "d[ef\n", "ghi]|\n", "jkl"], "ef\nghi")?;
|
|
||||||
|
|
||||||
Ok(())
|
clipboard_opt = assert_copy(&["[a]|"], "a", clipboard_opt)?;
|
||||||
}
|
clipboard_opt = assert_copy(&["|[b]"], "b", clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_copy(&["a[ ]|"], " ", clipboard_opt)?;
|
||||||
#[test]
|
clipboard_opt = assert_copy(&["[ ]|b"], " ", clipboard_opt)?;
|
||||||
fn paste() -> Result<(), String> {
|
clipboard_opt = assert_copy(&["a\n", "[b\n", "]|"], "b\n", clipboard_opt)?;
|
||||||
assert_paste(&["|"], "", &["|"])?;
|
clipboard_opt = assert_copy(&["[a\n", " b\n", "]|"], "a\n b\n", clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_copy(
|
||||||
|
&["abc\n", "d[ef\n", "ghi]|\n", "jkl"],
|
||||||
|
"ef\nghi",
|
||||||
|
clipboard_opt,
|
||||||
|
)?;
|
||||||
|
clipboard_opt = assert_paste(&["|"], "", &["|"], clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_paste(&["|"], "a", &["a|"], clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_paste(&["a|"], "b", &["ab|"], clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_paste(&["|a"], "b", &["b|a"], clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_paste(&["[a]|"], "c", &["c|"], clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_paste(&["[ab]|"], "d", &["d|"], clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_paste(&["a[b]|c"], "e", &["ae|c"], clipboard_opt)?;
|
||||||
|
clipboard_opt = assert_paste(&["a\n", "[b\n", "]|"], "f", &["a\n", "f|"], clipboard_opt)?;
|
||||||
|
assert_paste(
|
||||||
|
&["abc\n", "d[ef\n", "ghi]|\n", "jkl"],
|
||||||
|
"ef\nghi",
|
||||||
|
&["abc\n", "def\n", "ghi|\n", "jkl"],
|
||||||
|
clipboard_opt,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ use std::cmp::Ordering;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EdModel {
|
pub struct EdModel {
|
||||||
pub text_buf: TextBuffer,
|
pub text_buf: TextBuffer,
|
||||||
|
@ -30,13 +29,9 @@ pub fn get_selected_str(ed_model: &EdModel) -> EdResult<Option<&str>> {
|
||||||
if let Some(curr_selection) = ed_model.selection_opt {
|
if let Some(curr_selection) = ed_model.selection_opt {
|
||||||
let selected_str = ed_model.text_buf.get_selection(curr_selection)?;
|
let selected_str = ed_model.text_buf.get_selection(curr_selection)?;
|
||||||
|
|
||||||
Ok(
|
Ok(Some(selected_str))
|
||||||
Some(selected_str)
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(
|
Ok(None)
|
||||||
None
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use super::app_model::AppModel;
|
|
||||||
use super::ed_model::EdModel;
|
use super::ed_model::EdModel;
|
||||||
use super::ed_model::{Position, RawSelection};
|
use super::ed_model::{Position, RawSelection};
|
||||||
use crate::error::EdResult;
|
use crate::error::EdResult;
|
||||||
use crate::text_buffer::TextBuffer;
|
use crate::text_buffer::TextBuffer;
|
||||||
use crate::util::is_newline;
|
use crate::util::is_newline;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use winit::event::{ModifiersState, VirtualKeyCode};
|
|
||||||
use winit::event::VirtualKeyCode::*;
|
use winit::event::VirtualKeyCode::*;
|
||||||
|
use winit::event::{ModifiersState, VirtualKeyCode};
|
||||||
|
|
||||||
pub type MoveCaretFun =
|
pub type MoveCaretFun =
|
||||||
fn(Position, Option<RawSelection>, bool, &TextBuffer) -> (Position, Option<RawSelection>);
|
fn(Position, Option<RawSelection>, bool, &TextBuffer) -> (Position, Option<RawSelection>);
|
||||||
|
@ -352,7 +351,12 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
|
||||||
|
|
||||||
ed_model.selection_opt = None;
|
ed_model.selection_opt = None;
|
||||||
}
|
}
|
||||||
'\u{3}' | '\u{16}' | '\u{30}' | '\u{e000}'..='\u{f8ff}' | '\u{f0000}'..='\u{ffffd}' | '\u{100000}'..='\u{10fffd}' => {
|
'\u{3}'
|
||||||
|
| '\u{16}'
|
||||||
|
| '\u{30}'
|
||||||
|
| '\u{e000}'..='\u{f8ff}'
|
||||||
|
| '\u{f0000}'..='\u{ffffd}'
|
||||||
|
| '\u{100000}'..='\u{10fffd}' => {
|
||||||
// chars that can be ignored
|
// chars that can be ignored
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -385,7 +389,7 @@ pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult
|
||||||
pub fn handle_key_down(
|
pub fn handle_key_down(
|
||||||
modifiers: &ModifiersState,
|
modifiers: &ModifiersState,
|
||||||
virtual_keycode: VirtualKeyCode,
|
virtual_keycode: VirtualKeyCode,
|
||||||
ed_model: &mut EdModel
|
ed_model: &mut EdModel,
|
||||||
) {
|
) {
|
||||||
match virtual_keycode {
|
match virtual_keycode {
|
||||||
Left => handle_arrow(move_caret_left, modifiers, ed_model),
|
Left => handle_arrow(move_caret_left, modifiers, ed_model),
|
||||||
|
@ -398,7 +402,7 @@ pub fn handle_key_down(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test_ed_update {
|
pub mod test_ed_update {
|
||||||
use crate::mvc::app_update::test_app_update::{mock_app_model};
|
use crate::mvc::app_update::test_app_update::mock_app_model;
|
||||||
use crate::mvc::ed_model::{Position, RawSelection};
|
use crate::mvc::ed_model::{Position, RawSelection};
|
||||||
use crate::mvc::ed_update::handle_new_char;
|
use crate::mvc::ed_update::handle_new_char;
|
||||||
use crate::selection::test_selection::{
|
use crate::selection::test_selection::{
|
||||||
|
@ -423,25 +427,21 @@ pub mod test_ed_update {
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?;
|
let (caret_pos, selection_opt, pre_text_buf) = gen_caret_text_buf(pre_lines_str)?;
|
||||||
|
|
||||||
let mut app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt);
|
let app_model = mock_app_model(pre_text_buf, caret_pos, selection_opt, None);
|
||||||
let mut ed_model = app_model.get_ed_model_mut()?;
|
let mut ed_model = app_model.ed_model_opt.unwrap();
|
||||||
|
|
||||||
if let Err(e) = handle_new_char(&new_char, ed_model) {
|
if let Err(e) = handle_new_char(&new_char, &mut ed_model) {
|
||||||
return Err(e.to_string());
|
return Err(e.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ed_model) = app_model.ed_model_opt {
|
let mut actual_lines = all_lines_vec(&ed_model.text_buf);
|
||||||
let mut actual_lines = all_lines_vec(&ed_model.text_buf);
|
let dsl_slice = convert_selection_to_dsl(
|
||||||
let dsl_slice = convert_selection_to_dsl(
|
ed_model.selection_opt,
|
||||||
ed_model.selection_opt,
|
ed_model.caret_pos,
|
||||||
ed_model.caret_pos,
|
&mut actual_lines,
|
||||||
&mut actual_lines,
|
)
|
||||||
)
|
.unwrap();
|
||||||
.unwrap();
|
assert_eq!(dsl_slice, expected_post_lines_str);
|
||||||
assert_eq!(dsl_slice, expected_post_lines_str);
|
|
||||||
} else {
|
|
||||||
panic!("Mock AppModel did not have an EdModel.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
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_view;
|
|
||||||
pub mod ed_update;
|
pub mod ed_update;
|
||||||
|
pub mod ed_view;
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl TextBuffer {
|
||||||
self.insert_str(caret_pos, &new_char.to_string())
|
self.insert_str(caret_pos, &new_char.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_str(&mut self, caret_pos: Position, new_str: &str) -> EdResult<()> {
|
pub fn insert_str(&mut self, caret_pos: Position, new_str: &str) -> EdResult<()> {
|
||||||
let char_indx = self.pos_to_char_indx(caret_pos);
|
let char_indx = self.pos_to_char_indx(caret_pos);
|
||||||
|
|
||||||
self.check_bounds(char_indx)?;
|
self.check_bounds(char_indx)?;
|
||||||
|
@ -101,10 +101,7 @@ impl TextBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_len(&self, line_nr: usize) -> Option<usize> {
|
pub fn line_len(&self, line_nr: usize) -> Option<usize> {
|
||||||
self.line(line_nr)
|
self.line(line_nr).map(|line| line.len())
|
||||||
.map(
|
|
||||||
|line| line.len()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_len_res(&self, line_nr: usize) -> EdResult<usize> {
|
pub fn line_len_res(&self, line_nr: usize) -> EdResult<usize> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue