|
|
@ -1,5 +1,5 @@
|
|
|
|
use crate::graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary};
|
|
|
|
use crate::graphemes::{nth_next_grapheme_boundary, nth_prev_grapheme_boundary, RopeGraphemes};
|
|
|
|
use crate::{Buffer, Selection, SelectionRange};
|
|
|
|
use crate::{Buffer, Rope, RopeSlice, Selection, SelectionRange};
|
|
|
|
|
|
|
|
|
|
|
|
/// A state represents the current editor state of a single buffer.
|
|
|
|
/// A state represents the current editor state of a single buffer.
|
|
|
|
pub struct State {
|
|
|
|
pub struct State {
|
|
|
@ -117,3 +117,44 @@ impl State {
|
|
|
|
// TODO: update selection in state via transaction
|
|
|
|
// 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
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|