Add primitives for converting between char offset indices and coords.

This commit is contained in:
Blaž Hrastnik 2020-06-05 14:02:10 +09:00
parent 387fb57c94
commit 10d53f3ef0
2 changed files with 44 additions and 3 deletions

View File

@ -5,7 +5,7 @@
mod state;
mod transaction;
pub use ropey::Rope;
pub use ropey::{Rope, RopeSlice};
pub use tendril::StrTendril as Tendril;
pub use buffer::Buffer;

View File

@ -1,5 +1,5 @@
use crate::graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary};
use crate::{Buffer, Selection, SelectionRange};
use crate::graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary, RopeGraphemes};
use crate::{Buffer, Rope, RopeSlice, Selection, SelectionRange};
/// A state represents the current editor state of a single buffer.
pub struct State {
@ -117,3 +117,44 @@ pub fn extend_selection(
// TODO: update selection in state via transaction
}
}
/// Coordinates are a 0-indexed line and column pair.
type Coords = (usize, usize); // line, col
/// Convert a character index to (line, column) coordinates.
pub fn coords_at_pos(text: &RopeSlice, pos: usize) -> Coords {
let line = text.char_to_line(pos);
let line_start = text.line_to_char(line);
let col = RopeGraphemes::new(&text.slice(line_start..pos)).count();
(line, col)
}
/// Convert (line, column) coordinates to a character index.
pub fn pos_at_coords(text: &RopeSlice, coords: Coords) -> usize {
let (line, col) = coords;
let line_start = text.line_to_char(line);
nth_next_grapheme_boundary(text, line_start, col)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_coords_at_pos() {
let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
assert_eq!(coords_at_pos(&text.slice(..), 0), (0, 0));
assert_eq!(coords_at_pos(&text.slice(..), 5), (0, 5)); // position on \n
assert_eq!(coords_at_pos(&text.slice(..), 6), (1, 0)); // position on w
assert_eq!(coords_at_pos(&text.slice(..), 11), (1, 5)); // position on d
}
#[test]
fn test_pos_at_coords() {
let text = Rope::from("ḧëḷḷö\nẅöṛḷḋ");
assert_eq!(pos_at_coords(&text.slice(..), (0, 0)), 0);
assert_eq!(pos_at_coords(&text.slice(..), (0, 5)), 5); // position on \n
assert_eq!(pos_at_coords(&text.slice(..), (1, 0)), 6); // position on w
assert_eq!(pos_at_coords(&text.slice(..), (1, 5)), 11); // position on d
}
}