on master help sign in
Fix coord mapping, add vertical move.
commit195aad4675d62ab6d74b59990422b27d95ab85c7 authorBlaž Hrastnik <blaz@mxxn.io> dateMon 8 Jun 2020, 00:08 (6 years ago) parent10d53f3
1 file changed+42−3
helix-core/src/state.rs+42−3
helix-core/src/state.rs+42−3
@@ -69,6 +69,7 @@ impl State {
6969 (Direction::Forward, Granularity::Character) => {
7070 nth_next_grapheme_boundary(&text.slice(..), pos, n)
7171 }
72+ (_, Granularity::Line) => move_vertically(&text.slice(..), dir, pos, n),
7273 _ => pos,
7374 }
7475 }
@@ -125,7 +126,8 @@ type Coords = (usize, usize); // line, col
125126pub fn coords_at_pos(text: &RopeSlice, pos: usize) -> Coords {
126127 let line = text.char_to_line(pos);
127128 let line_start = text.line_to_char(line);
128− let col = RopeGraphemes::new(&text.slice(line_start..pos)).count();
129+ // convert to 0-indexed
130+ let col = text.slice(line_start..pos).len_chars().saturating_sub(1);
129131 (line, col)
130132}
131133
@@ -136,6 +138,31 @@ pub fn pos_at_coords(text: &RopeSlice, coords: Coords) -> usize {
136138 nth_next_grapheme_boundary(text, line_start, col)
137139}
138140
141+fn move_vertically(text: &RopeSlice, dir: Direction, pos: usize, n: usize) -> usize {
142+ let (line, col) = coords_at_pos(text, pos);
143+
144+ let new_line = match dir {
145+ Direction::Backward => line.saturating_sub(n),
146+ Direction::Forward => std::cmp::min(line.saturating_add(n), text.len_lines() - 1),
147+ };
148+
149+ // convert to 0-indexed
150+ let new_line_len = text.line(new_line).len_chars().saturating_sub(1);
151+
152+ let new_col = if new_line_len < col {
153+ // TODO: preserve horiz here
154+ new_line_len
155+ } else {
156+ col
157+ };
158+
159+ pos_at_coords(text, (new_line, new_col))
160+}
161+
162+/// A command is a function that takes the current state and a count, and does a side-effect on the
163+/// state (usually by creating and applying a transaction).
164+type Command = fn(state: &mut State, count: usize) -> bool;
165+
139166#[cfg(test)]
140167mod test {
141168 use super::*;
@@ -144,9 +171,9 @@ mod test {
144171 fn test_coords_at_pos() {
145172 let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
146173 assert_eq!(coords_at_pos(&text.slice(..), 0), (0, 0));
147− assert_eq!(coords_at_pos(&text.slice(..), 5), (0, 5)); // position on \n
174+ assert_eq!(coords_at_pos(&text.slice(..), 5), (0, 4)); // position on \n
148175 assert_eq!(coords_at_pos(&text.slice(..), 6), (1, 0)); // position on w
149− assert_eq!(coords_at_pos(&text.slice(..), 11), (1, 5)); // position on d
176+ assert_eq!(coords_at_pos(&text.slice(..), 11), (1, 4)); // position on d
150177 }
151178
152179 #[test]
@@ -157,4 +184,16 @@ mod test {
157184 assert_eq!(pos_at_coords(&text.slice(..), (1, 0)), 6); // position on w
158185 assert_eq!(pos_at_coords(&text.slice(..), (1, 5)), 11); // position on d
159186 }
187+
188+ #[test]
189+ fn test_vertical_move() {
190+ let text = Rope::from("abcd\nefg\nwrs");
191+ let pos = pos_at_coords(&text.slice(..), (0, 4));
192+ let slice = text.slice(..);
193+
194+ assert_eq!(
195+ coords_at_pos(&slice, move_vertically(&slice, Direction::Forward, pos, 1)),
196+ (1, 2)
197+ );
198+ }
160199}