WIP getting graphemes working again.

This commit is contained in:
Nathan Vegdahl 2017-12-31 01:56:45 -08:00
parent ca948588e6
commit 2e9c2b2704
4 changed files with 49 additions and 60 deletions

View File

@ -69,9 +69,20 @@ impl Buffer {
self.text.len_chars()
}
pub fn grapheme_count(&self) -> usize {
// TODO: be correct
self.text.len_chars()
pub fn nth_next_grapheme(&self, char_idx: usize, n: usize) -> usize {
let mut char_idx = char_idx;
for _ in 0..n {
char_idx = self.text.next_grapheme_boundary(char_idx);
}
char_idx
}
pub fn nth_prev_grapheme(&self, char_idx: usize, n: usize) -> usize {
let mut char_idx = char_idx;
for _ in 0..n {
char_idx = self.text.prev_grapheme_boundary(char_idx);
}
char_idx
}
pub fn line_count(&self) -> usize {

View File

@ -5,7 +5,7 @@ use formatter::LineFormatter;
use formatter::RoundingBehavior::*;
use std::path::{Path, PathBuf};
use std::cmp::{max, min};
use string_utils::{grapheme_count, str_to_line_ending, LineEnding};
use string_utils::{char_count, str_to_line_ending, LineEnding};
use utils::digit_count;
use self::cursor::CursorSet;
@ -26,7 +26,7 @@ pub struct Editor<T: LineFormatter> {
// The dimensions and position of just the text view portion of the editor
pub view_dim: (usize, usize), // (height, width)
pub view_pos: (usize, usize), // (grapheme index, visual horizontal offset)
pub view_pos: (usize, usize), // (char index, visual horizontal offset)
// The editing cursor position
pub cursors: CursorSet,
@ -324,24 +324,24 @@ impl<T: LineFormatter> Editor<T> {
// there are no cursors currently in view, and should jump to
// the closest cursor.
// Find the first and last grapheme index visible within the editor.
let g_first =
// Find the first and last char index visible within the editor.
let c_first =
self.formatter
.index_set_horizontal_v2d(&self.buffer, self.view_pos.0, 0, Floor);
let mut g_last = self.formatter.index_offset_vertical_v2d(
let mut c_last = self.formatter.index_offset_vertical_v2d(
&self.buffer,
g_first,
c_first,
self.view_dim.0 as isize,
(Floor, Floor),
);
g_last =
c_last =
self.formatter
.index_set_horizontal_v2d(&self.buffer, g_last, self.view_dim.1, Floor);
.index_set_horizontal_v2d(&self.buffer, c_last, self.view_dim.1, Floor);
// Adjust the view depending on where the cursor is
if self.cursors[0].range.0 < g_first {
if self.cursors[0].range.0 < c_first {
self.view_pos.0 = self.cursors[0].range.0;
} else if self.cursors[0].range.0 > g_last {
} else if self.cursors[0].range.0 >= c_last {
self.view_pos.0 = self.formatter.index_offset_vertical_v2d(
&self.buffer,
self.cursors[0].range.0,
@ -354,7 +354,7 @@ impl<T: LineFormatter> Editor<T> {
pub fn insert_text_at_cursor(&mut self, text: &str) {
self.cursors.make_consistent();
let str_len = grapheme_count(text);
let str_len = char_count(text);
let mut offset = 0;
for c in self.cursors.iter_mut() {
@ -421,13 +421,6 @@ impl<T: LineFormatter> Editor<T> {
self.remove_text_behind_cursor(1);
}
pub fn insert_text_at_grapheme(&mut self, text: &str, pos: usize) {
self.dirty = true;
let buf_len = self.buffer.grapheme_count();
self.buffer
.insert_text(text, if pos < buf_len { pos } else { buf_len });
}
pub fn remove_text_behind_cursor(&mut self, grapheme_count: usize) {
self.cursors.make_consistent();
@ -443,7 +436,7 @@ impl<T: LineFormatter> Editor<T> {
continue;
}
let len = min(c.range.0, grapheme_count);
let len = c.range.0 - self.buffer.nth_prev_grapheme(c.range.0, grapheme_count);
// Remove text
self.buffer.remove_text_before(c.range.0, len);
@ -475,16 +468,11 @@ impl<T: LineFormatter> Editor<T> {
c.range.1 -= min(c.range.1, offset);
// Do nothing if there's nothing to delete.
if c.range.1 == self.buffer.grapheme_count() {
if c.range.1 == self.buffer.char_count() {
return;
}
let max_len = if self.buffer.grapheme_count() > c.range.1 {
self.buffer.grapheme_count() - c.range.1
} else {
0
};
let len = min(max_len, grapheme_count);
let len = self.buffer.nth_next_grapheme(c.range.1, grapheme_count) - c.range.1;
// Remove text
self.buffer.remove_text_after(c.range.1, len);
@ -548,7 +536,7 @@ impl<T: LineFormatter> Editor<T> {
}
pub fn cursor_to_end_of_buffer(&mut self) {
let end = self.buffer.grapheme_count();
let end = self.buffer.char_count();
self.cursors = CursorSet::new();
self.cursors[0].range = (end, end);
@ -560,12 +548,7 @@ impl<T: LineFormatter> Editor<T> {
pub fn cursor_left(&mut self, n: usize) {
for c in self.cursors.iter_mut() {
if c.range.0 >= n {
c.range.0 -= n;
} else {
c.range.0 = 0;
}
c.range.0 = self.buffer.nth_prev_grapheme(c.range.0, n);
c.range.1 = c.range.0;
c.update_vis_start(&(self.buffer), &(self.formatter));
}
@ -576,12 +559,7 @@ impl<T: LineFormatter> Editor<T> {
pub fn cursor_right(&mut self, n: usize) {
for c in self.cursors.iter_mut() {
c.range.1 += n;
if c.range.1 > self.buffer.grapheme_count() {
c.range.1 = self.buffer.grapheme_count();
}
c.range.1 = self.buffer.nth_next_grapheme(c.range.1, n);
c.range.0 = c.range.1;
c.update_vis_start(&(self.buffer), &(self.formatter));
}
@ -629,7 +607,7 @@ impl<T: LineFormatter> Editor<T> {
(Round, Round),
);
if temp_index == self.buffer.grapheme_count() {
if temp_index == self.buffer.char_count() {
c.update_vis_start(&(self.buffer), &(self.formatter));
} else {
temp_index = self.formatter.index_set_horizontal_v2d(

View File

@ -26,13 +26,13 @@ pub trait LineFormatter {
where
T: Iterator<Item = &'a str>;
/// Converts a grapheme index within a text into a visual 2d position.
/// Converts a char index within a text into a visual 2d position.
/// The text to be formatted is passed as a grapheme iterator.
fn index_to_v2d<'a, T>(&'a self, g_iter: T, index: usize) -> (usize, usize)
fn index_to_v2d<'a, T>(&'a self, g_iter: T, char_idx: usize) -> (usize, usize)
where
T: Iterator<Item = &'a str>;
/// Converts a visual 2d position into a grapheme index within a text.
/// Converts a visual 2d position into a char index within a text.
/// The text to be formatted is passed as a grapheme iterator.
fn v2d_to_index<'a, T>(
&'a self,
@ -43,8 +43,8 @@ pub trait LineFormatter {
where
T: Iterator<Item = &'a str>;
fn index_to_horizontal_v2d(&self, buf: &Buffer, index: usize) -> usize {
let (line_i, col_i) = buf.index_to_line_col(index);
fn index_to_horizontal_v2d(&self, buf: &Buffer, char_idx: usize) -> usize {
let (line_i, col_i) = buf.index_to_line_col(char_idx);
let line = buf.get_line(line_i);
// Find the right block in the line, and the index within that block
@ -57,12 +57,12 @@ pub trait LineFormatter {
return self.index_to_v2d(g_iter, col_i_adjusted).1;
}
/// Takes a grapheme index and a visual vertical offset, and returns the grapheme
/// Takes a char index and a visual vertical offset, and returns the char
/// index after that visual offset is applied.
fn index_offset_vertical_v2d(
&self,
buf: &Buffer,
index: usize,
char_idx: usize,
offset: isize,
rounding: (RoundingBehavior, RoundingBehavior),
) -> usize {
@ -70,7 +70,7 @@ pub trait LineFormatter {
// TODO: do this with bidirectional line iterator
// Get the line and block index of the given index
let (mut line_i, mut col_i) = buf.index_to_line_col(index);
let (mut line_i, mut col_i) = buf.index_to_line_col(char_idx);
// Find the right block in the line, and the index within that block
let (line_block, col_i_adjusted) = block_index_and_offset(col_i);
@ -104,7 +104,7 @@ pub trait LineFormatter {
// Check for off-the-end
if is_last_block && (line_i + 1) >= buf.line_count() {
return buf.grapheme_count();
return buf.char_count();
}
if is_last_block {
@ -153,17 +153,17 @@ pub trait LineFormatter {
return buf.line_col_to_index((line_i, col_i));
}
/// Takes a grapheme index and a desired visual horizontal position, and
/// returns a grapheme index on the same visual line as the given index,
/// Takes a char index and a desired visual horizontal position, and
/// returns a char index on the same visual line as the given index,
/// but offset to have the desired horizontal position.
fn index_set_horizontal_v2d(
&self,
buf: &Buffer,
index: usize,
char_idx: usize,
horizontal: usize,
rounding: RoundingBehavior,
) -> usize {
let (line_i, col_i) = buf.index_to_line_col(index);
let (line_i, col_i) = buf.index_to_line_col(char_idx);
let line = buf.get_line(line_i);
// Find the right block in the line, and the index within that block
@ -189,7 +189,7 @@ pub trait LineFormatter {
new_col_i = line.len_chars() - 1;
}
return (index + new_col_i) - col_i;
return (char_idx + new_col_i) - col_i;
}
}

View File

@ -345,8 +345,8 @@ impl TermUI {
// Percentage position in document
// TODO: use view instead of cursor for calculation if there is more
// than one cursor.
let percentage: usize = if editor.buffer.grapheme_count() > 0 {
(((editor.cursors[0].range.0 as f32) / (editor.buffer.grapheme_count() as f32)) * 100.0)
let percentage: usize = if editor.buffer.char_count() > 0 {
(((editor.cursors[0].range.0 as f32) / (editor.buffer.char_count() as f32)) * 100.0)
as usize
} else {
100
@ -584,7 +584,7 @@ impl TermUI {
// Calculate the cell coordinates at which to draw the cursor
let pos_x = editor
.formatter
.index_to_horizontal_v2d(&self.editor.buffer, self.editor.buffer.grapheme_count());
.index_to_horizontal_v2d(&self.editor.buffer, self.editor.buffer.char_count());
let px = pos_x as isize + screen_col - editor.view_pos.1 as isize;
let py = screen_line - 1;