aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2020-06-05 05:02:10 +0000
committerBlaž Hrastnik2020-06-05 05:04:30 +0000
commit10d53f3ef0f519dc6b55f8a882a32ec7b1c4e4e1 (patch)
treeed3215931ef256ad80ee123e03f59ba1a8c31fd9
parent387fb57c94a5269b5ff560891fdee53a2f3fc554 (diff)
Add primitives for converting between char offset indices and coords.
-rw-r--r--helix-core/src/lib.rs2
-rw-r--r--helix-core/src/state.rs45
2 files changed, 44 insertions, 3 deletions
diff --git a/helix-core/src/lib.rs b/helix-core/src/lib.rs
index 8675fc6f..7a0518d8 100644
--- a/helix-core/src/lib.rs
+++ b/helix-core/src/lib.rs
@@ -5,7 +5,7 @@ mod selection;
mod state;
mod transaction;
-pub use ropey::Rope;
+pub use ropey::{Rope, RopeSlice};
pub use tendril::StrTendril as Tendril;
pub use buffer::Buffer;
diff --git a/helix-core/src/state.rs b/helix-core/src/state.rs
index 1ffd708e..ccbfd28a 100644
--- a/helix-core/src/state.rs
+++ b/helix-core/src/state.rs
@@ -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 @@ impl State {
// 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
+ }
+}