on master help sign in
Improve `Range` documentation and organization.
commitb2c76dc627d1cabe83b69a025fccb8ea8259d2a5 authorNathan Vegdahl <cessen@cessen.com> dateMon 26 Jul 2021, 18:04 (5 years ago) parentf62ec6e
1 file changed+57−42
helix-core/src/selection.rs+57−42
helix-core/src/selection.rs+57−42
@@ -1,5 +1,5 @@
1−//! Selections are the primary editing construct. Even a single cursor is
2−//! defined as a single empty or 1-wide selection range.
1+//! Selections are the primary editing construct. Even cursors are
2+//! defined as a selection range.
33//!
44//! All positioning is done via `char` offsets into the buffer.
55use crate::{
@@ -14,17 +14,20 @@ use std::borrow::Cow;
1414
1515/// A single selection range.
1616///
17−/// The range consists of an "anchor" and "head" position in
17+/// A range consists of an "anchor" and "head" position in
1818/// the text. The head is the part that the user moves when
19−/// directly extending the selection. The head and anchor
20−/// can be in any order: either can precede or follow the
21−/// other in the text, and they can share the same position
22−/// for a zero-width range.
19+/// directly extending a selection. The head and anchor
20+/// can be in any order, or even share the same position.
21+///
22+/// The anchor and head positions use gap indexing, meaning
23+/// that their indices represent the the gaps *between* `char`s
24+/// rather than the `char`s themselves. For example, 1
25+/// represents the position between the first and second `char`.
2326///
2427/// Below are some example `Range` configurations to better
2528/// illustrate. The anchor and head indices are show as
2629/// "(anchor, head)", followed by example text with "[" and "]"
27−/// inserted to visually represent the anchor and head positions:
30+/// inserted to represent the anchor and head positions:
2831///
2932/// - (0, 3): [Som]e text.
3033/// - (3, 0): ]Som[e text.
@@ -37,6 +40,12 @@ use std::borrow::Cow;
3740/// are directly adjecent, sharing an edge, do not overlap.
3841/// However, a zero-width range will overlap with the shared
3942/// left-edge of another range.
43+///
44+/// By convention, user-facing ranges are considered to have
45+/// a block cursor on the head-side of the range that spans a
46+/// single grapheme inward from the range's edge. There are a
47+/// variety of helper methods on `Range` for working in terms of
48+/// that block cursor, all of which have `cursor` in their name.
4049#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4150pub struct Range {
4251 /// The anchor of the range: the side that doesn't move when extending.
@@ -73,13 +82,6 @@ impl Range {
7382 std::cmp::max(self.anchor, self.head)
7483 }
7584
76− /// The line number that the block-cursor is on.
77− #[inline]
78− #[must_use]
79− pub fn cursor_line(&self, text: RopeSlice) -> usize {
80− text.char_to_line(self.cursor(text))
81− }
82−
8385 /// The (inclusive) range of lines that the range overlaps.
8486 #[inline]
8587 #[must_use]
@@ -184,32 +186,16 @@ impl Range {
184186 }
185187 }
186188
187− /// Compute a possibly new range from this range, attempting to ensure
188− /// a minimum range width of 1 char by shifting the head in the forward
189− /// direction as needed.
190− ///
191− /// This method will never shift the anchor, and will only shift the
192− /// head in the forward direction. Therefore, this method can fail
193− /// at ensuring the minimum width if and only if the passed range is
194− /// both zero-width and at the end of the `RopeSlice`.
195− ///
196− /// If the input range is grapheme-boundary aligned, the returned range
197− /// will also be. Specifically, if the head needs to shift to achieve
198− /// the minimum width, it will shift to the next grapheme boundary.
199− #[must_use]
189+ // groupAt
190+
200191 #[inline]
201− pub fn min_width_1(&self, slice: RopeSlice) -> Self {
202− if self.anchor == self.head {
203− Range {
204− anchor: self.anchor,
205− head: next_grapheme_boundary(slice, self.head),
206− horiz: self.horiz,
207− }
208− } else {
209− *self
210− }
192+ pub fn fragment<'a, 'b: 'a>(&'a self, text: RopeSlice<'b>) -> Cow<'b, str> {
193+ text.slice(self.from()..self.to()).into()
211194 }
212195
196+ //--------------------------------
197+ // Alignment methods.
198+
213199 /// Compute a possibly new range from this range, with its ends
214200 /// shifted as needed to align with grapheme boundaries.
215201 ///
@@ -243,6 +229,35 @@ impl Range {
243229 }
244230 }
245231
232+ /// Compute a possibly new range from this range, attempting to ensure
233+ /// a minimum range width of 1 char by shifting the head in the forward
234+ /// direction as needed.
235+ ///
236+ /// This method will never shift the anchor, and will only shift the
237+ /// head in the forward direction. Therefore, this method can fail
238+ /// at ensuring the minimum width if and only if the passed range is
239+ /// both zero-width and at the end of the `RopeSlice`.
240+ ///
241+ /// If the input range is grapheme-boundary aligned, the returned range
242+ /// will also be. Specifically, if the head needs to shift to achieve
243+ /// the minimum width, it will shift to the next grapheme boundary.
244+ #[must_use]
245+ #[inline]
246+ pub fn min_width_1(&self, slice: RopeSlice) -> Self {
247+ if self.anchor == self.head {
248+ Range {
249+ anchor: self.anchor,
250+ head: next_grapheme_boundary(slice, self.head),
251+ horiz: self.horiz,
252+ }
253+ } else {
254+ *self
255+ }
256+ }
257+
258+ //--------------------------------
259+ // Block-cursor methods.
260+
246261 /// Gets the left-side position of the block cursor.
247262 #[must_use]
248263 #[inline]
@@ -284,11 +299,11 @@ impl Range {
284299 }
285300 }
286301
287− // groupAt
288−
302+ /// The line number that the block-cursor is on.
289303 #[inline]
290− pub fn fragment<'a, 'b: 'a>(&'a self, text: RopeSlice<'b>) -> Cow<'b, str> {
291− text.slice(self.from()..self.to()).into()
304+ #[must_use]
305+ pub fn cursor_line(&self, text: RopeSlice) -> usize {
306+ text.char_to_line(self.cursor(text))
292307 }
293308}
294309