mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Home + End keys, refactoring for seperate ui folder/lib
This commit is contained in:
parent
299018aa34
commit
9dda23cf8b
13 changed files with 2490 additions and 49 deletions
|
@ -15,10 +15,7 @@ pub fn handle_keydown(
|
||||||
}
|
}
|
||||||
|
|
||||||
match virtual_keycode {
|
match virtual_keycode {
|
||||||
Left => pass_keydown_to_focused(&modifiers, virtual_keycode, app_model),
|
Left | Up | Right | Down => pass_keydown_to_focused(&modifiers, virtual_keycode, app_model),
|
||||||
Up => pass_keydown_to_focused(&modifiers, virtual_keycode, app_model),
|
|
||||||
Right => pass_keydown_to_focused(&modifiers, virtual_keycode, app_model),
|
|
||||||
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)?,
|
||||||
|
@ -39,7 +36,7 @@ pub fn handle_keydown(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
A => pass_keydown_to_focused(&modifiers, virtual_keycode, app_model),
|
A | Home | End => pass_keydown_to_focused(&modifiers, virtual_keycode, app_model),
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ mod keyboard_input;
|
||||||
pub mod lang;
|
pub mod lang;
|
||||||
mod mvc;
|
mod mvc;
|
||||||
//pub mod mvc; // for benchmarking
|
//pub mod mvc; // for benchmarking
|
||||||
|
mod ui;
|
||||||
mod resources;
|
mod resources;
|
||||||
mod selection;
|
mod selection;
|
||||||
mod text_buffer;
|
mod text_buffer;
|
||||||
|
|
|
@ -2,8 +2,6 @@ use crate::error::EdResult;
|
||||||
use crate::graphics::primitives::rect::Rect;
|
use crate::graphics::primitives::rect::Rect;
|
||||||
use crate::text_buffer;
|
use crate::text_buffer;
|
||||||
use crate::text_buffer::TextBuffer;
|
use crate::text_buffer::TextBuffer;
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::fmt;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -47,45 +45,3 @@ impl EdModel {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct Position {
|
|
||||||
pub line: usize,
|
|
||||||
pub column: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ord for Position {
|
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
|
||||||
(self.line, self.column).cmp(&(other.line, other.column))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Position {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
||||||
Some(self.cmp(other))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Position {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
(self.line, self.column) == (other.line, other.column)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for Position {}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct RawSelection {
|
|
||||||
pub start_pos: Position,
|
|
||||||
pub end_pos: Position,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for RawSelection {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"RawSelection: start_pos: line:{} col:{}, end_pos: line:{} col:{}",
|
|
||||||
self.start_pos.line, self.start_pos.column, self.end_pos.line, self.end_pos.column
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -332,6 +332,83 @@ pub fn handle_select_all(ed_model: &mut EdModel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EdModel {
|
||||||
|
pub fn move_caret_w_mods(&mut self, new_pos: Position, mods: &ModifiersState) {
|
||||||
|
let caret_pos = self.caret_pos;
|
||||||
|
|
||||||
|
// one does not simply move the caret
|
||||||
|
if new_pos != caret_pos {
|
||||||
|
if mods.shift() {
|
||||||
|
if let Some(selection) = self.selection_opt {
|
||||||
|
if new_pos < selection.start_pos {
|
||||||
|
if caret_pos > selection.start_pos {
|
||||||
|
self.set_selection(
|
||||||
|
new_pos,
|
||||||
|
selection.start_pos
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.set_selection(
|
||||||
|
new_pos,
|
||||||
|
selection.end_pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if new_pos > selection.end_pos {
|
||||||
|
if caret_pos < selection.end_pos {
|
||||||
|
self.set_selection(
|
||||||
|
selection.end_pos,
|
||||||
|
new_pos
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.set_selection(
|
||||||
|
selection.start_pos,
|
||||||
|
new_pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if new_pos > caret_pos {
|
||||||
|
self.set_selection(
|
||||||
|
new_pos,
|
||||||
|
selection.end_pos
|
||||||
|
)
|
||||||
|
} else if new_pos < caret_pos {
|
||||||
|
self.set_selection(
|
||||||
|
selection.start_pos,
|
||||||
|
new_pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if new_pos < self.caret_pos {
|
||||||
|
self.set_selection(
|
||||||
|
new_pos,
|
||||||
|
caret_pos
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.set_selection(
|
||||||
|
caret_pos,
|
||||||
|
new_pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.selection_opt = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.caret_pos = new_pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_selection(&mut self, start_pos: Position, end_pos: Position) {
|
||||||
|
self.selection_opt =
|
||||||
|
if start_pos != end_pos {
|
||||||
|
Some(
|
||||||
|
RawSelection {
|
||||||
|
start_pos,
|
||||||
|
end_pos
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult<()> {
|
pub fn handle_new_char(received_char: &char, ed_model: &mut EdModel) -> EdResult<()> {
|
||||||
let old_caret_pos = ed_model.caret_pos;
|
let old_caret_pos = ed_model.caret_pos;
|
||||||
|
|
||||||
|
@ -418,6 +495,53 @@ pub fn handle_key_down(
|
||||||
handle_select_all(ed_model)
|
handle_select_all(ed_model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Home => {
|
||||||
|
let curr_line_nr = ed_model.caret_pos.line;
|
||||||
|
// TODO no unwrap
|
||||||
|
let curr_line_str = ed_model.text_buf.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.move_caret_w_mods(
|
||||||
|
Position {
|
||||||
|
line: ed_model.caret_pos.line,
|
||||||
|
column: first_no_space_char_col
|
||||||
|
},
|
||||||
|
modifiers
|
||||||
|
)
|
||||||
|
}
|
||||||
|
End => {
|
||||||
|
let curr_line = ed_model.caret_pos.line;
|
||||||
|
// TODO no unwrap
|
||||||
|
let new_col =
|
||||||
|
max(
|
||||||
|
0,
|
||||||
|
ed_model.text_buf.line_len(curr_line).unwrap() - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_pos =
|
||||||
|
Position {
|
||||||
|
line: curr_line,
|
||||||
|
column: new_col
|
||||||
|
};
|
||||||
|
|
||||||
|
ed_model.move_caret_w_mods(new_pos, modifiers);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -622,4 +746,8 @@ pub mod test_ed_update {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO hometest
|
||||||
|
|
||||||
|
// TODO endtest
|
||||||
}
|
}
|
||||||
|
|
20
editor/src/ui/error.rs
Normal file
20
editor/src/ui/error.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
use snafu::{Backtrace, ErrorCompat, Snafu};
|
||||||
|
|
||||||
|
#[derive(Debug, Snafu)]
|
||||||
|
#[snafu(visibility(pub))]
|
||||||
|
pub enum UIError {
|
||||||
|
#[snafu(display(
|
||||||
|
"OutOfBounds: index {} was out of bounds for {} with length {}.",
|
||||||
|
index,
|
||||||
|
collection_name,
|
||||||
|
len
|
||||||
|
))]
|
||||||
|
OutOfBounds {
|
||||||
|
index: usize,
|
||||||
|
collection_name: String,
|
||||||
|
len: usize,
|
||||||
|
backtrace: Backtrace,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type UIResult<T, E = UIError> = std::result::Result<T, E>;
|
3
editor/src/ui/mod.rs
Normal file
3
editor/src/ui/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod error;
|
||||||
|
pub mod model;
|
||||||
|
pub mod update;
|
1
editor/src/ui/model/mod.rs
Normal file
1
editor/src/ui/model/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod text;
|
3
editor/src/ui/model/text/mod.rs
Normal file
3
editor/src/ui/model/text/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod selectable_text_m;
|
||||||
|
pub mod selection;
|
||||||
|
pub mod txt_pos;
|
48
editor/src/ui/model/text/selectable_text_m.rs
Normal file
48
editor/src/ui/model/text/selectable_text_m.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
use crate::ui::error::UIResult;
|
||||||
|
use super::txt_pos::TxtPos;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
impl std::fmt::Display for RawSelection {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"RawSelection: start_pos: line:{} col:{}, end_pos: line:{} col:{}",
|
||||||
|
self.start_pos.line, self.start_pos.column, self.end_pos.line, self.end_pos.column
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SelectableLines {
|
||||||
|
fn get_line(&self, line_nr: usize) -> UIResult<&str>;
|
||||||
|
|
||||||
|
fn line_len(&self, line_nr: usize) -> UIResult<usize>;
|
||||||
|
|
||||||
|
fn nr_of_lines(&self) -> usize;
|
||||||
|
|
||||||
|
fn nr_of_chars(&self) -> usize;
|
||||||
|
|
||||||
|
// TODO use pool allocation here
|
||||||
|
fn all_lines<'a>(&self, arena: &'a Bump) -> BumpString<'a>;
|
||||||
|
|
||||||
|
fn last_TxtPos(&self) -> TxtPos;
|
||||||
|
|
||||||
|
fn get_selection(&self, raw_sel: RawSelection) -> UIResult<&str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait MutSelectableLines {
|
||||||
|
fn insert_char(&mut self, caret_pos: TxtPos, new_char: &char) -> UIResult<()>;
|
||||||
|
|
||||||
|
fn insert_str(&mut self, caret_pos: TxtPos, new_str: &str) -> UIResult<()>;
|
||||||
|
|
||||||
|
fn pop_char(&mut self, caret_pos: TxtPos);
|
||||||
|
|
||||||
|
fn del_selection(&mut self, raw_sel: RawSelection) -> UIResult<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SelectableText {
|
||||||
|
pub lines: SelectableLines,
|
||||||
|
pub caret_pos: TxtPos,
|
||||||
|
pub selection_opt: Option<RawSelection>,
|
||||||
|
}
|
2193
editor/src/ui/model/text/selection.rs
Normal file
2193
editor/src/ui/model/text/selection.rs
Normal file
File diff suppressed because it is too large
Load diff
28
editor/src/ui/model/text/txt_pos.rs
Normal file
28
editor/src/ui/model/text/txt_pos.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct TxtPos {
|
||||||
|
pub line: usize,
|
||||||
|
pub column: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for TxtPos {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
(self.line, self.column).cmp(&(other.line, other.column))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for TxtPos {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for TxtPos {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
(self.line, self.column) == (other.line, other.column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for TxtPos {}
|
1
editor/src/ui/update/mod.rs
Normal file
1
editor/src/ui/update/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod SelectableTextU;
|
62
editor/src/ui/update/selectable_text_u.rs
Normal file
62
editor/src/ui/update/selectable_text_u.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
impl SelectableText {
|
||||||
|
pub fn move_caret_w_mods(&mut self, new_pos: Position, mods: &ModifiersState) {
|
||||||
|
let caret_pos = self.caret_pos;
|
||||||
|
|
||||||
|
// one does not simply move the caret
|
||||||
|
if new_pos != caret_pos {
|
||||||
|
if mods.shift() {
|
||||||
|
if let Some(selection) = self.selection_opt {
|
||||||
|
if new_pos < selection.start_pos {
|
||||||
|
if caret_pos > selection.start_pos {
|
||||||
|
self.set_selection(
|
||||||
|
new_pos,
|
||||||
|
selection.start_pos
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.set_selection(
|
||||||
|
new_pos,
|
||||||
|
selection.end_pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if new_pos > selection.end_pos {
|
||||||
|
if caret_pos < selection.end_pos {
|
||||||
|
self.set_selection(
|
||||||
|
selection.end_pos,
|
||||||
|
new_pos
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.set_selection(
|
||||||
|
selection.start_pos,
|
||||||
|
new_pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if new_pos > caret_pos {
|
||||||
|
self.set_selection(
|
||||||
|
new_pos,
|
||||||
|
selection.end_pos
|
||||||
|
)
|
||||||
|
} else if new_pos < caret_pos {
|
||||||
|
self.set_selection(
|
||||||
|
selection.start_pos,
|
||||||
|
new_pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if new_pos < self.caret_pos {
|
||||||
|
self.set_selection(
|
||||||
|
new_pos,
|
||||||
|
caret_pos
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.set_selection(
|
||||||
|
caret_pos,
|
||||||
|
new_pos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.selection_opt = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.caret_pos = new_pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue