Verified Commit 71c4215d authored by Phil Booth's avatar Phil Booth

refactor(cursor): eliminate some common boilerplate and reorder some methods

parent b8d89a6b
Pipeline #32758787 passed with stage
in 2 minutes and 11 seconds
......@@ -20,6 +20,26 @@ mod test;
use tokens::{arena, Token, TokenId};
macro_rules! simple_move {
($self:ident, $delta:ident, $id:expr, $index:ident, $move_absolute:ident) => {
if let Some(id) = $id {
let ids = arena().read(id, &|token| {
if $delta >= 0 {
token.following_siblings()
} else {
token.preceding_siblings()
}
});
if $delta >= 0 {
$self.$index += $self.$move_absolute($delta as usize, ids);
} else {
$self.$index -= $self.$move_absolute((0 - $delta) as usize, ids.rev());
}
}
};
}
#[derive(Debug, Default)]
pub struct Cursor {
ideal_grapheme_index: usize,
......@@ -44,27 +64,22 @@ impl Cursor {
self.grapheme_index
}
pub fn line_index(&self) -> usize {
self.line_index
}
pub fn move_grapheme(&mut self, delta: isize) {
self.stick_to_line_end = false;
if self.grapheme_id.is_some() {
let grapheme_ids = arena().read(self.grapheme_id.unwrap(), &|grapheme| {
if delta >= 0 {
grapheme.following_siblings()
} else {
grapheme.preceding_siblings()
}
});
if delta >= 0 {
self.grapheme_index += self.move_grapheme_absolute(delta as usize, grapheme_ids);
} else {
self.grapheme_index -=
self.move_grapheme_absolute((0 - delta) as usize, grapheme_ids.rev());
}
simple_move!(
self,
delta,
self.grapheme_id,
grapheme_index,
move_grapheme_absolute
);
self.ideal_grapheme_index = self.grapheme_index;
}
self.ideal_grapheme_index = self.grapheme_index;
}
fn move_grapheme_absolute<I>(&mut self, absolute_delta: usize, grapheme_ids: I) -> usize
......@@ -89,94 +104,6 @@ impl Cursor {
count
}
pub fn line_index(&self) -> usize {
self.line_index
}
pub fn move_line(&mut self, delta: isize) {
if let Some(line_id) = self.line_id() {
let line_ids = arena().read(line_id, &|line| {
if delta >= 0 {
line.following_siblings()
} else {
line.preceding_siblings()
}
});
if delta >= 0 {
self.line_index += self.move_line_absolute(delta as usize, line_ids);
} else {
self.line_index -= self.move_line_absolute((0 - delta) as usize, line_ids.rev());
}
}
if self.stick_to_line_end {
self.move_to_line_end();
}
}
fn line_id(&self) -> Option<TokenId> {
if let Some(word_id) = self.word_id() {
arena().read(word_id, &|word| word.parent())
} else {
None
}
}
fn word_id(&self) -> Option<TokenId> {
if let Some(grapheme_id) = self.grapheme_id {
arena().read(grapheme_id, &|grapheme| grapheme.parent())
} else {
None
}
}
fn move_line_absolute<I>(&mut self, absolute_delta: usize, line_ids: I) -> usize
where
I: Iterator<Item = TokenId>,
{
let mut new_line_id = None;
let mut count = 0;
for line_id in line_ids {
if count == absolute_delta {
break;
}
new_line_id = Some(line_id);
count += 1;
}
if let Some(new_line_id) = new_line_id {
let word_id = arena().read(new_line_id, &|line| line.first_child());
if let Some(word_id) = word_id {
self.grapheme_id = arena().read(word_id, &|word| word.first_child());
if let Some(grapheme_id) = self.grapheme_id {
let grapheme_index = self.ideal_grapheme_index;
let grapheme_ids =
arena().read(grapheme_id, &|grapheme| grapheme.following_siblings());
self.grapheme_index = self.move_grapheme_absolute(grapheme_index, grapheme_ids);
}
}
}
count
}
pub fn move_to_line_end(&mut self) {
if let Some(line_id) = self.line_id() {
let line_length = arena().read(line_id, &|line| line.len());
if line_length > self.grapheme_index + 1 {
let delta = line_length - self.grapheme_index - 1;
self.move_grapheme(delta as isize);
}
}
self.stick_to_line_end = true;
}
pub fn move_word(&mut self, delta: isize) {
self.stick_to_line_end = false;
......@@ -207,6 +134,14 @@ impl Cursor {
}
}
fn word_id(&self) -> Option<TokenId> {
if let Some(grapheme_id) = self.grapheme_id {
arena().read(grapheme_id, &|grapheme| grapheme.parent())
} else {
None
}
}
fn move_word_absolute<I>(
&mut self,
absolute_delta: usize,
......@@ -305,6 +240,68 @@ impl Cursor {
}
}
pub fn move_line(&mut self, delta: isize) {
simple_move!(self, delta, self.line_id(), line_index, move_line_absolute);
if self.stick_to_line_end {
self.move_to_line_end();
}
}
fn line_id(&self) -> Option<TokenId> {
if let Some(word_id) = self.word_id() {
arena().read(word_id, &|word| word.parent())
} else {
None
}
}
fn move_line_absolute<I>(&mut self, absolute_delta: usize, line_ids: I) -> usize
where
I: Iterator<Item = TokenId>,
{
let mut new_line_id = None;
let mut count = 0;
for line_id in line_ids {
if count == absolute_delta {
break;
}
new_line_id = Some(line_id);
count += 1;
}
if let Some(new_line_id) = new_line_id {
let word_id = arena().read(new_line_id, &|line| line.first_child());
if let Some(word_id) = word_id {
self.grapheme_id = arena().read(word_id, &|word| word.first_child());
if let Some(grapheme_id) = self.grapheme_id {
let grapheme_index = self.ideal_grapheme_index;
let grapheme_ids =
arena().read(grapheme_id, &|grapheme| grapheme.following_siblings());
self.grapheme_index = self.move_grapheme_absolute(grapheme_index, grapheme_ids);
}
}
}
count
}
pub fn move_to_line_end(&mut self) {
if let Some(line_id) = self.line_id() {
let line_length = arena().read(line_id, &|line| line.len());
if line_length > self.grapheme_index + 1 {
let delta = line_length - self.grapheme_index - 1;
self.move_grapheme(delta as isize);
}
}
self.stick_to_line_end = true;
}
pub fn move_paragraph(&mut self, delta: isize) {
if delta == 0 {
return;
......
......@@ -169,86 +169,6 @@ fn move_grapheme_with_paragraph_ending() {
assert_eq!(cursor.line_index(), 2);
}
#[test]
fn move_line() {
let line_ids = parse::lines("000\n11\n2\n33333").unwrap();
let word_id = arena().read(line_ids[0], &|line| line.first_child().unwrap());
let grapheme_id = arena().read(word_id, &|word| word.first_child());
let mut cursor = Cursor::new(grapheme_id, 2, 0);
cursor.move_line(0);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 0);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 1);
assert_eq!(cursor.line_index(), 1);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 0);
assert_eq!(cursor.line_index(), 2);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 3);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 3);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 0);
assert_eq!(cursor.line_index(), 2);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 1);
assert_eq!(cursor.line_index(), 1);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 0);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 0);
cursor.move_line(2);
assert_eq!(cursor.grapheme_index(), 0);
assert_eq!(cursor.line_index(), 2);
cursor.move_line(2);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 3);
}
#[test]
fn move_to_line_end() {
let line_ids = parse::lines("00\n111\n2222").unwrap();
let word_id = arena().read(line_ids[0], &|line| line.first_child().unwrap());
let grapheme_id = arena().read(word_id, &|word| word.first_child());
let mut cursor = Cursor::new(grapheme_id, 0, 0);
cursor.move_to_line_end();
assert_eq!(cursor.grapheme_index(), 1);
assert_eq!(cursor.line_index(), 0);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 1);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 3);
assert_eq!(cursor.line_index(), 2);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 1);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 3);
assert_eq!(cursor.line_index(), 2);
}
#[test]
fn move_word() {
let line_ids = parse::lines("0 11, 222\n3333").unwrap();
......@@ -401,6 +321,86 @@ fn move_to_word_end() {
assert_eq!(cursor.line_index(), 0);
}
#[test]
fn move_line() {
let line_ids = parse::lines("000\n11\n2\n33333").unwrap();
let word_id = arena().read(line_ids[0], &|line| line.first_child().unwrap());
let grapheme_id = arena().read(word_id, &|word| word.first_child());
let mut cursor = Cursor::new(grapheme_id, 2, 0);
cursor.move_line(0);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 0);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 1);
assert_eq!(cursor.line_index(), 1);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 0);
assert_eq!(cursor.line_index(), 2);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 3);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 3);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 0);
assert_eq!(cursor.line_index(), 2);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 1);
assert_eq!(cursor.line_index(), 1);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 0);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 0);
cursor.move_line(2);
assert_eq!(cursor.grapheme_index(), 0);
assert_eq!(cursor.line_index(), 2);
cursor.move_line(2);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 3);
}
#[test]
fn move_to_line_end() {
let line_ids = parse::lines("00\n111\n2222").unwrap();
let word_id = arena().read(line_ids[0], &|line| line.first_child().unwrap());
let grapheme_id = arena().read(word_id, &|word| word.first_child());
let mut cursor = Cursor::new(grapheme_id, 0, 0);
cursor.move_to_line_end();
assert_eq!(cursor.grapheme_index(), 1);
assert_eq!(cursor.line_index(), 0);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 1);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 3);
assert_eq!(cursor.line_index(), 2);
cursor.move_line(-1);
assert_eq!(cursor.grapheme_index(), 2);
assert_eq!(cursor.line_index(), 1);
cursor.move_line(1);
assert_eq!(cursor.grapheme_index(), 3);
assert_eq!(cursor.line_index(), 2);
}
#[test]
fn move_paragraph() {
let paragraph_ids = parse::paragraphs("000\n111\n2222\n\n333\n444\n\n\n555").unwrap();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment