Start work on making row/columnwise movement work w/ byte columns
This commit is contained in:
parent
6621b9b552
commit
f3db0dcff6
4 changed files with 119 additions and 9 deletions
|
@ -335,6 +335,9 @@ impl Chunk {
|
|||
let mut point = Point::new(0, 0);
|
||||
for ch in self.0.chars() {
|
||||
if point >= target {
|
||||
if point > target {
|
||||
panic!("point {:?} is inside of character {:?}", target, ch);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -346,8 +349,6 @@ impl Chunk {
|
|||
}
|
||||
offset += ch.len_utf8();
|
||||
}
|
||||
|
||||
assert_eq!(point, target);
|
||||
offset
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2358,7 +2358,11 @@ impl workspace::ItemView for BufferView {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{editor::Point, settings, test::sample_text};
|
||||
use crate::{
|
||||
editor::Point,
|
||||
settings,
|
||||
test::{multibyte_sample_text, sample_text},
|
||||
};
|
||||
use unindent::Unindent;
|
||||
|
||||
#[gpui::test]
|
||||
|
@ -2715,6 +2719,70 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_move_cursor_multibyte(app: &mut gpui::MutableAppContext) {
|
||||
let buffer = app.add_model(|ctx| Buffer::new(0, "ⓐⓑⓒⓓⓔ\nabcde\nαβγδε\n", ctx));
|
||||
let settings = settings::channel(&app.font_cache()).unwrap().1;
|
||||
let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
|
||||
|
||||
assert_eq!('ⓐ'.len_utf8(), 3);
|
||||
assert_eq!('α'.len_utf8(), 2);
|
||||
|
||||
view.update(app, |view, ctx| {
|
||||
view.fold_ranges(
|
||||
vec![
|
||||
Point::new(0, 6)..Point::new(0, 12),
|
||||
Point::new(1, 2)..Point::new(1, 4),
|
||||
Point::new(2, 4)..Point::new(2, 8),
|
||||
],
|
||||
ctx,
|
||||
);
|
||||
assert_eq!(view.text(ctx.as_ref()), "ⓐⓑ…ⓔ\nab…e\nαβ…ε\n");
|
||||
|
||||
view.move_right(&(), ctx);
|
||||
assert_eq!(
|
||||
view.selection_ranges(ctx.as_ref()),
|
||||
&[DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3)]
|
||||
);
|
||||
|
||||
view.move_down(&(), ctx);
|
||||
assert_eq!(
|
||||
view.selection_ranges(ctx.as_ref()),
|
||||
&[DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
|
||||
);
|
||||
|
||||
view.move_right(&(), ctx);
|
||||
assert_eq!(
|
||||
view.selection_ranges(ctx.as_ref()),
|
||||
&[DisplayPoint::new(1, 2)..DisplayPoint::new(1, 2)]
|
||||
);
|
||||
|
||||
view.move_down(&(), ctx);
|
||||
assert_eq!(
|
||||
view.selection_ranges(ctx.as_ref()),
|
||||
&[DisplayPoint::new(2, 4)..DisplayPoint::new(2, 4)]
|
||||
);
|
||||
|
||||
view.move_left(&(), ctx);
|
||||
assert_eq!(
|
||||
view.selection_ranges(ctx.as_ref()),
|
||||
&[DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
|
||||
);
|
||||
|
||||
view.move_up(&(), ctx);
|
||||
assert_eq!(
|
||||
view.selection_ranges(ctx.as_ref()),
|
||||
&[DisplayPoint::new(1, 1)..DisplayPoint::new(1, 1)]
|
||||
);
|
||||
|
||||
view.move_up(&(), ctx);
|
||||
assert_eq!(
|
||||
view.selection_ranges(ctx.as_ref()),
|
||||
&[DisplayPoint::new(0, 3)..DisplayPoint::new(0, 3)]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_beginning_end_of_line(app: &mut gpui::MutableAppContext) {
|
||||
let buffer = app.add_model(|ctx| Buffer::new(0, "abc\n def", ctx));
|
||||
|
|
|
@ -92,8 +92,7 @@ impl DisplayMap {
|
|||
let mut is_blank = true;
|
||||
for c in self
|
||||
.snapshot(ctx)
|
||||
.chunks_at(DisplayPoint::new(display_row, 0), ctx)
|
||||
.flat_map(str::chars)
|
||||
.chars_at(DisplayPoint::new(display_row, 0), ctx)
|
||||
{
|
||||
if c == ' ' {
|
||||
indent += 1;
|
||||
|
@ -165,6 +164,32 @@ impl DisplayMapSnapshot {
|
|||
self.chunks_at(point, app).flat_map(str::chars)
|
||||
}
|
||||
|
||||
pub fn column_to_chars(&self, display_row: u32, target: u32, ctx: &AppContext) -> u32 {
|
||||
let mut count = 0;
|
||||
let mut column = 0;
|
||||
for c in self.chars_at(DisplayPoint::new(display_row, 0), ctx) {
|
||||
count += 1;
|
||||
column += c.len_utf8() as u32;
|
||||
if column >= target {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
pub fn column_from_chars(&self, display_row: u32, char_count: u32, ctx: &AppContext) -> u32 {
|
||||
let mut count = 0;
|
||||
let mut column = 0;
|
||||
for c in self.chars_at(DisplayPoint::new(display_row, 0), ctx) {
|
||||
count += 1;
|
||||
column += c.len_utf8() as u32;
|
||||
if count >= char_count {
|
||||
break;
|
||||
}
|
||||
}
|
||||
column
|
||||
}
|
||||
|
||||
fn expand_tabs(&self, mut point: DisplayPoint, ctx: &AppContext) -> DisplayPoint {
|
||||
let chars = self
|
||||
.folds_snapshot
|
||||
|
@ -187,7 +212,6 @@ impl DisplayMapSnapshot {
|
|||
let (collapsed, expanded_char_column, to_next_stop) =
|
||||
collapse_tabs(chars, expanded, bias, self.tab_size);
|
||||
*point.column_mut() = collapsed as u32;
|
||||
|
||||
(point, expanded_char_column, to_next_stop)
|
||||
}
|
||||
}
|
||||
|
@ -360,6 +384,10 @@ pub fn collapse_tabs(
|
|||
expanded_bytes += c.len_utf8();
|
||||
}
|
||||
collapsed_bytes += c.len_utf8();
|
||||
|
||||
if expanded_bytes > column {
|
||||
panic!("column {} is inside of character {:?}", column, c);
|
||||
}
|
||||
}
|
||||
(collapsed_bytes, expanded_chars, 0)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,12 @@ pub fn left(map: &DisplayMap, mut point: DisplayPoint, app: &AppContext) -> Resu
|
|||
pub fn right(map: &DisplayMap, mut point: DisplayPoint, app: &AppContext) -> Result<DisplayPoint> {
|
||||
let max_column = map.line_len(point.row(), app);
|
||||
if point.column() < max_column {
|
||||
*point.column_mut() += 1;
|
||||
*point.column_mut() += map
|
||||
.snapshot(app)
|
||||
.chars_at(point, app)
|
||||
.next()
|
||||
.unwrap()
|
||||
.len_utf8() as u32;
|
||||
} else if point.row() < map.max_point(app).row() {
|
||||
*point.row_mut() += 1;
|
||||
*point.column_mut() = 0;
|
||||
|
@ -35,9 +40,13 @@ pub fn up(
|
|||
} else {
|
||||
point.column()
|
||||
};
|
||||
|
||||
let map = map.snapshot(app);
|
||||
let char_column = map.column_to_chars(point.row(), goal_column, app);
|
||||
|
||||
if point.row() > 0 {
|
||||
*point.row_mut() -= 1;
|
||||
*point.column_mut() = cmp::min(goal_column, map.line_len(point.row(), app));
|
||||
*point.column_mut() = map.column_from_chars(point.row(), char_column, app);
|
||||
} else {
|
||||
point = DisplayPoint::new(0, 0);
|
||||
}
|
||||
|
@ -56,10 +65,14 @@ pub fn down(
|
|||
} else {
|
||||
point.column()
|
||||
};
|
||||
|
||||
let max_point = map.max_point(app);
|
||||
let map = map.snapshot(app);
|
||||
let char_column = map.column_to_chars(point.row(), goal_column, app);
|
||||
|
||||
if point.row() < max_point.row() {
|
||||
*point.row_mut() += 1;
|
||||
*point.column_mut() = cmp::min(goal_column, map.line_len(point.row(), app))
|
||||
*point.column_mut() = map.column_from_chars(point.row(), char_column, app);
|
||||
} else {
|
||||
point = max_point;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue