Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Use single position cursor #653

Merged
merged 7 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions crates/hooks/src/rope_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,11 @@ impl TextEditor for RopeEditor {

fn measure_new_cursor(&self, to: usize, editor_id: usize) -> TextCursor {
if self.mode == EditableMode::SingleLineMultipleEditors {
TextCursor::new(editor_id, to)
let row_char = self.line_to_char(editor_id);
let pos = row_char + to;
TextCursor::new(pos)
} else {
let row = self.char_to_line(to);
let row_idx = self.line_to_char(row);
let col = to - row_idx;
TextCursor::new(row, col)
TextCursor::new(to)
}
}

Expand Down
246 changes: 103 additions & 143 deletions crates/hooks/src/text_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,45 +5,27 @@ use freya_elements::events::keyboard::{Code, Key, Modifiers};

/// Holds the position of a cursor in a text
#[derive(Clone, Default, PartialEq, Debug)]
pub struct TextCursor {
col: usize,
row: usize,
}
pub struct TextCursor(usize);

impl TextCursor {
/// Construct a new [TextCursor] given a row and a column
pub fn new(row: usize, col: usize) -> Self {
Self { col, row }
}

/// Move the cursor to a new row and column
pub fn move_to(&mut self, row: usize, col: usize) {
self.col = col;
self.row = row;
}

/// Get the current column
pub fn col(&self) -> usize {
self.col
}

/// Get the current row
pub fn row(&self) -> usize {
self.row
/// Construct a new [TextCursor]
pub fn new(pos: usize) -> Self {
Self(pos)
}

/// Set a new column
pub fn set_col(&mut self, col: usize) {
self.col = col;
/// Get the position
pub fn pos(&self) -> usize {
self.0
}

/// Set a new row
pub fn set_row(&mut self, row: usize) {
self.row = row;
/// Set the position
pub fn set(&mut self, pos: usize) {
self.0 = pos;
}

pub fn as_tuple(&self) -> (usize, usize) {
(self.row, self.col)
/// Write the position
pub fn write(&mut self) -> &mut usize {
&mut self.0
}
}

Expand Down Expand Up @@ -131,12 +113,21 @@ pub trait TextEditor {

/// Get the cursor row
fn cursor_row(&self) -> usize {
self.cursor().row()
let pos = self.cursor_pos();
self.char_to_line(pos)
}

/// Get the cursor column
fn cursor_col(&self) -> usize {
self.cursor().col()
let pos = self.cursor_pos();
let line = self.char_to_line(pos);
let line_char = self.line_to_char(line);
pos - line_char
}

/// Get the cursor row and col
fn cursor_row_and_col(&self) -> (usize, usize) {
(self.cursor_row(), self.cursor_col())
}

/// Get the visible cursor position
Expand All @@ -145,47 +136,91 @@ pub trait TextEditor {
}

/// Move the cursor 1 line down
fn cursor_down(&mut self) {
let new_row = self.cursor_row() + 1;
self.cursor_mut().set_row(new_row);
fn cursor_down(&mut self) -> bool {
let old_row = self.cursor_row();
let old_col = self.cursor_col();

match old_row.cmp(&(self.len_lines() - 1)) {
Ordering::Less => {
// One line below
let new_row = old_row + 1;
let new_row_char = self.line_to_char(new_row);
self.cursor_mut().set(new_row_char + old_col);

true
}
Ordering::Equal => {
let end = self.len_chars();
// Reached max
self.cursor_mut().set(end);

true
}
Ordering::Greater => {
// Can't go further

false
}
}
}

/// Move the cursor 1 line up
fn cursor_up(&mut self) {
let new_row = self.cursor_row() - 1;
self.cursor_mut().set_row(new_row);
fn cursor_up(&mut self) -> bool {
let pos = self.cursor_pos();
let old_row = self.cursor_row();
let old_col = self.cursor_col();

if pos > 0 {
// Reached max
if old_row == 0 {
self.cursor_mut().set(0);
} else {
let new_row = old_row - 1;
let new_row_char = self.line_to_char(new_row);
self.cursor_mut().set(new_row_char + old_col);
}

true
} else {
false
}
}

/// Move the cursor 1 char to the right
fn cursor_right(&mut self) {
let new_col = self.cursor_col() + 1;
self.cursor_mut().set_col(new_col);
fn cursor_right(&mut self) -> bool {
if self.cursor_pos() < self.len_chars() {
*self.cursor_mut().write() += 1;

true
} else {
false
}
}

/// Move the cursor 1 char to the left
fn cursor_left(&mut self) {
let new_col = self.cursor_col() - 1;
self.cursor_mut().set_col(new_col);
fn cursor_left(&mut self) -> bool {
if self.cursor_pos() > 0 {
*self.cursor_mut().write() -= 1;

true
} else {
false
}
}

/// Get the cursor position
fn cursor_pos(&self) -> usize {
let line_begining = self.line_to_char(self.cursor_row());
line_begining + self.cursor_col()
self.cursor().pos()
}

/// Get the cursor position
fn visible_cursor_pos(&self) -> usize {
let line_begining = self.char_to_utf16_cu(self.line_to_char(self.cursor_row()));
line_begining + self.char_to_utf16_cu(self.cursor_col())
self.char_to_utf16_cu(self.cursor_pos())
}

/// Set the cursor position
fn set_cursor_pos(&mut self, pos: usize) {
let row = self.char_to_line(pos);
let row_idx = self.line_to_char(row);
let col = pos - row_idx;
self.cursor_mut().move_to(row, col)
self.cursor_mut().set(pos);
}

// Check if has any selection at all
Expand Down Expand Up @@ -241,33 +276,8 @@ pub trait TextEditor {
self.expand_selection_to_cursor();
}

let last_line = self.len_lines() - 1;

// Go one line down
match self.cursor_row().cmp(&last_line) {
Ordering::Equal => {
// Move the cursor to the end of the line
let current_line = self.line(self.cursor_row()).unwrap();
let last_char = current_line.len_chars();
self.cursor_mut().set_col(last_char);
event.insert(TextEvent::CURSOR_CHANGED);
}
Ordering::Less => {
let next_line = self.line(self.cursor_row() + 1).unwrap();

// Try to use the current cursor column, otherwise use the new line length
let cursor_col = if self.cursor_col() <= next_line.len_chars() {
self.cursor_col()
} else {
next_line.len_chars().max(1) - 1
};

self.cursor_mut().set_col(cursor_col);
self.cursor_down();

event.insert(TextEvent::CURSOR_CHANGED);
}
_ => {}
if self.cursor_down() {
event.insert(TextEvent::CURSOR_CHANGED);
}

if modifiers.contains(Modifiers::SHIFT) {
Expand All @@ -280,27 +290,8 @@ pub trait TextEditor {
self.expand_selection_to_cursor();
}

// Go one character to the left
if self.cursor_col() > 0 {
self.cursor_left();

if self.cursor_left() {
event.insert(TextEvent::CURSOR_CHANGED);
} else if self.cursor_row() > 0 {
// Go one line up if there is no more characters on the left
let prev_line = self.line(self.cursor_row() - 1);
if let Some(prev_line) = prev_line {
// Use the prev line length as new cursor column, otherwise just set it to 0
let cursor_col = if prev_line.len_chars() > 0 {
prev_line.len_chars() - 1
} else {
0
};

self.cursor_up();
self.cursor_mut().set_col(cursor_col);

event.insert(TextEvent::CURSOR_CHANGED);
}
}

if modifiers.contains(Modifiers::SHIFT) {
Expand All @@ -313,20 +304,7 @@ pub trait TextEditor {
self.expand_selection_to_cursor();
}

let current_line = self.line(self.cursor_row()).unwrap();

// Go one line down if there isn't more characters on the right
if self.cursor_row() < self.len_lines() - 1
&& self.cursor_col() == current_line.len_chars().max(1) - 1
{
self.cursor_down();
self.cursor_mut().set_col(0);

event.insert(TextEvent::CURSOR_CHANGED);
} else if self.cursor_col() < current_line.len_chars() {
// Go one character to the right if possible
self.cursor_right();

if self.cursor_right() {
event.insert(TextEvent::CURSOR_CHANGED);
}

Expand All @@ -340,24 +318,7 @@ pub trait TextEditor {
self.expand_selection_to_cursor();
}

// Go one line up if there is any
if self.cursor_row() > 0 {
let prev_line = self.line(self.cursor_row() - 1).unwrap();

// Try to use the current cursor column, otherwise use the prev line length
let cursor_col = if self.cursor_col() <= prev_line.len_chars() {
self.cursor_col()
} else {
prev_line.len_chars().max(1) - 1
};

self.cursor_up();
self.cursor_mut().set_col(cursor_col);

event.insert(TextEvent::CURSOR_CHANGED);
} else if self.cursor_col() > 0 {
// Move the cursor to the begining of the line
self.cursor_mut().set_col(0);
if self.cursor_up() {
event.insert(TextEvent::CURSOR_CHANGED);
}

Expand Down Expand Up @@ -396,10 +357,9 @@ pub trait TextEditor {
}
Key::Enter => {
// Breaks the line
let char_idx = self.line_to_char(self.cursor_row()) + self.cursor_col();
self.insert_char('\n', char_idx);
self.cursor_down();
self.cursor_mut().set_col(0);
let cursor_pos = self.cursor_pos();
self.insert_char('\n', cursor_pos);
self.cursor_right();

event.insert(TextEvent::TEXT_CHANGED);
}
Expand All @@ -414,8 +374,8 @@ pub trait TextEditor {
Code::Delete => {}
Code::Space => {
// Simply adds an space
let char_idx = self.line_to_char(self.cursor_row()) + self.cursor_col();
self.insert_char(' ', char_idx);
let cursor_pos = self.cursor_pos();
self.insert_char(' ', cursor_pos);
self.cursor_right();

event.insert(TextEvent::TEXT_CHANGED);
Expand Down Expand Up @@ -484,16 +444,16 @@ pub trait TextEditor {
_ => {
if let Ok(ch) = character.parse::<char>() {
// Inserts a character
let char_idx = self.line_to_char(self.cursor_row()) + self.cursor_col();
self.insert_char(ch, char_idx);
let cursor_pos = self.cursor_pos();
self.insert_char(ch, cursor_pos);
self.cursor_right();

event.insert(TextEvent::TEXT_CHANGED);
} else {
// Inserts a text
let char_idx = self.line_to_char(self.cursor_row()) + self.cursor_col();
self.insert(character, char_idx);
self.set_cursor_pos(char_idx + character.chars().count());
let cursor_pos = self.cursor_pos();
self.insert(character, cursor_pos);
self.set_cursor_pos(cursor_pos + character.chars().count());

event.insert(TextEvent::TEXT_CHANGED);
}
Expand Down
Loading