on master help sign in
Document more of helix-core (#904)
92c2d5dKirawi
helix-core/src/auto_pairs.rs+3
@@ -1,3 +1,6 @@
1+//! When typing the opening character of one of the possible pairs defined below,
2+//! this module provides the functionality to insert the paired closing character.
3+
1use crate::{Range, Rope, Selection, Tendril, Transaction};
4use crate::{Range, Rope, Selection, Tendril, Transaction};
2use smallvec::SmallVec;
5use smallvec::SmallVec;
3
6
helix-core/src/chars.rs+2
@@ -1,3 +1,5 @@
1+//! Utility functions to categorize a `char`.
2+
1use crate::LineEnding;
3use crate::LineEnding;
2
4
3#[derive(Debug, Eq, PartialEq)]
5#[derive(Debug, Eq, PartialEq)]
helix-core/src/comment.rs+3
@@ -1,3 +1,6 @@
1+//! This module contains the functionality toggle comments on lines over the selection
2+//! using the comment character defined in the user's `languages.toml`
3+
1use crate::{
4use crate::{
2 find_first_non_whitespace_char, Change, Rope, RopeSlice, Selection, Tendril, Transaction,
5 find_first_non_whitespace_char, Change, Rope, RopeSlice, Selection, Tendril, Transaction,
3};
6};
helix-core/src/diagnostic.rs+5
@@ -1,3 +1,6 @@
1+//! LSP diagnostic utility types.
2+
3+/// Describes the severity level of a [`Diagnostic`].
1#[derive(Debug, Eq, PartialEq)]
4#[derive(Debug, Eq, PartialEq)]
2pub enum Severity {
5pub enum Severity {
3 Error,
6 Error,
@@ -6,12 +9,14 @@ pub enum Severity {
6 Hint,
9 Hint,
7}
10}
8
11
12+/// A range of `char`s within the text.
9#[derive(Debug)]
13#[derive(Debug)]
10pub struct Range {
14pub struct Range {
11 pub start: usize,
15 pub start: usize,
12 pub end: usize,
16 pub end: usize,
13}
17}
14
18
19+/// Corresponds to [`lsp_types::Diagnostic`](https://docs.rs/lsp-types/0.91.0/lsp_types/struct.Diagnostic.html)
15#[derive(Debug)]
20#[derive(Debug)]
16pub struct Diagnostic {
21pub struct Diagnostic {
17 pub range: Range,
22 pub range: Range,
helix-core/src/graphemes.rs+3−1
@@ -1,4 +1,6 @@
1+//! Utility functions to traverse the unicode graphemes of a `Rope`'s text contents.
2+//!
1−// Based on https://github.com/cessen/led/blob/c4fa72405f510b7fd16052f90a598c429b3104a6/src/graphemes.rs
3+//! Based on https://github.com/cessen/led/blob/c4fa72405f510b7fd16052f90a598c429b3104a6/src/graphemes.rs
2use ropey::{iter::Chunks, str_utils::byte_to_char_idx, RopeSlice};
4use ropey::{iter::Chunks, str_utils::byte_to_char_idx, RopeSlice};
3use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
5use unicode_segmentation::{GraphemeCursor, GraphemeIncomplete};
4use unicode_width::UnicodeWidthStr;
6use unicode_width::UnicodeWidthStr;
helix-core/src/history.rs+65−40
@@ -4,48 +4,50 @@ use regex::Regex;
4use std::num::NonZeroUsize;
4use std::num::NonZeroUsize;
5use std::time::{Duration, Instant};
5use std::time::{Duration, Instant};
6
6
7−// Stores the history of changes to a buffer.
7+/// Stores the history of changes to a buffer.
8−//
8+///
9−// Currently the history is represented as a vector of revisions. The vector
9+/// Currently the history is represented as a vector of revisions. The vector
10−// always has at least one element: the empty root revision. Each revision
10+/// always has at least one element: the empty root revision. Each revision
11−// with the exception of the root has a parent revision, a [Transaction]
11+/// with the exception of the root has a parent revision, a [Transaction]
12−// that can be applied to its parent to transition from the parent to itself,
12+/// that can be applied to its parent to transition from the parent to itself,
13−// and an inversion of that transaction to transition from the parent to its
13+/// and an inversion of that transaction to transition from the parent to its
14−// latest child.
14+/// latest child.
15−//
15+///
16−// When using `u` to undo a change, an inverse of the stored transaction will
16+/// When using `u` to undo a change, an inverse of the stored transaction will
17−// be applied which will transition the buffer to the parent state.
17+/// be applied which will transition the buffer to the parent state.
18−//
18+///
19−// Each revision with the exception of the last in the vector also has a
19+/// Each revision with the exception of the last in the vector also has a
20−// last child revision. When using `U` to redo a change, the last child transaction
20+/// last child revision. When using `U` to redo a change, the last child transaction
21−// will be applied to the current state of the buffer.
21+/// will be applied to the current state of the buffer.
22−//
22+///
23−// The current revision is the one currently displayed in the buffer.
23+/// The current revision is the one currently displayed in the buffer.
24−//
24+///
25−// Commiting a new revision to the history will update the last child of the
25+/// Commiting a new revision to the history will update the last child of the
26−// current revision, and push a new revision to the end of the vector.
26+/// current revision, and push a new revision to the end of the vector.
27−//
27+///
28−// Revisions are commited with a timestamp. :earlier and :later can be used
28+/// Revisions are commited with a timestamp. :earlier and :later can be used
29−// to jump to the closest revision to a moment in time relative to the timestamp
29+/// to jump to the closest revision to a moment in time relative to the timestamp
30−// of the current revision plus (:later) or minus (:earlier) the duration
30+/// of the current revision plus (:later) or minus (:earlier) the duration
31−// given to the command. If a single integer is given, the editor will instead
31+/// given to the command. If a single integer is given, the editor will instead
32−// jump the given number of revisions in the vector.
32+/// jump the given number of revisions in the vector.
33−//
33+///
34−// Limitations:
34+/// Limitations:
35−// * Changes in selections currently don't commit history changes. The selection
35+/// * Changes in selections currently don't commit history changes. The selection
36−// will only be updated to the state after a commited buffer change.
36+/// will only be updated to the state after a commited buffer change.
37−// * The vector of history revisions is currently unbounded. This might
37+/// * The vector of history revisions is currently unbounded. This might
38−// cause the memory consumption to grow significantly large during long
38+/// cause the memory consumption to grow significantly large during long
39−// editing sessions.
39+/// editing sessions.
40−// * Because delete transactions currently don't store the text that they
40+/// * Because delete transactions currently don't store the text that they
41−// delete, we also store an inversion of the transaction.
41+/// delete, we also store an inversion of the transaction.
42+///
43+/// Using time to navigate the history: https://github.com/helix-editor/helix/pull/194
42#[derive(Debug)]
44#[derive(Debug)]
43pub struct History {
45pub struct History {
44 revisions: Vec<Revision>,
46 revisions: Vec<Revision>,
45 current: usize,
47 current: usize,
46}
48}
47
49
48−// A single point in history. See [History] for more information.
50+/// A single point in history. See [History] for more information.
49#[derive(Debug)]
51#[derive(Debug)]
50struct Revision {
52struct Revision {
51 parent: usize,
53 parent: usize,
@@ -111,6 +113,7 @@ impl History {
111 self.current == 0
113 self.current == 0
112 }
114 }
113
115
116+ /// Undo the last edit.
114 pub fn undo(&mut self) -> Option<&Transaction> {
117 pub fn undo(&mut self) -> Option<&Transaction> {
115 if self.at_root() {
118 if self.at_root() {
116 return None;
119 return None;
@@ -121,6 +124,7 @@ impl History {
121 Some(&current_revision.inversion)
124 Some(&current_revision.inversion)
122 }
125 }
123
126
127+ /// Redo the last edit.
124 pub fn redo(&mut self) -> Option<&Transaction> {
128 pub fn redo(&mut self) -> Option<&Transaction> {
125 let current_revision = &self.revisions[self.current];
129 let current_revision = &self.revisions[self.current];
126 let last_child = current_revision.last_child?;
130 let last_child = current_revision.last_child?;
@@ -147,8 +151,8 @@ impl History {
147 }
151 }
148 }
152 }
149
153
150− // List of nodes on the way from `n` to 'a`. Doesn`t include `a`.
154+ /// List of nodes on the way from `n` to 'a`. Doesn`t include `a`.
151− // Includes `n` unless `a == n`. `a` must be an ancestor of `n`.
155+ /// Includes `n` unless `a == n`. `a` must be an ancestor of `n`.
152 fn path_up(&self, mut n: usize, a: usize) -> Vec<usize> {
156 fn path_up(&self, mut n: usize, a: usize) -> Vec<usize> {
153 let mut path = Vec::new();
157 let mut path = Vec::new();
154 while n != a {
158 while n != a {
@@ -158,6 +162,7 @@ impl History {
158 path
162 path
159 }
163 }
160
164
165+ /// Create a [`Transaction`] that will jump to a specific revision in the history.
161 fn jump_to(&mut self, to: usize) -> Vec<Transaction> {
166 fn jump_to(&mut self, to: usize) -> Vec<Transaction> {
162 let lca = self.lowest_common_ancestor(self.current, to);
167 let lca = self.lowest_common_ancestor(self.current, to);
163 let up = self.path_up(self.current, lca);
168 let up = self.path_up(self.current, lca);
@@ -171,10 +176,12 @@ impl History {
171 up_txns.chain(down_txns).collect()
176 up_txns.chain(down_txns).collect()
172 }
177 }
173
178
179+ /// Creates a [`Transaction`] that will undo `delta` revisions.
174 fn jump_backward(&mut self, delta: usize) -> Vec<Transaction> {
180 fn jump_backward(&mut self, delta: usize) -> Vec<Transaction> {
175 self.jump_to(self.current.saturating_sub(delta))
181 self.jump_to(self.current.saturating_sub(delta))
176 }
182 }
177
183
184+ /// Creates a [`Transaction`] that will redo `delta` revisions.
178 fn jump_forward(&mut self, delta: usize) -> Vec<Transaction> {
185 fn jump_forward(&mut self, delta: usize) -> Vec<Transaction> {
179 self.jump_to(
186 self.jump_to(
180 self.current
187 self.current
@@ -183,7 +190,7 @@ impl History {
183 )
190 )
184 }
191 }
185
192
186− // Helper for a binary search case below.
193+ /// Helper for a binary search case below.
187 fn revision_closer_to_instant(&self, i: usize, instant: Instant) -> usize {
194 fn revision_closer_to_instant(&self, i: usize, instant: Instant) -> usize {
188 let dur_im1 = instant.duration_since(self.revisions[i - 1].timestamp);
195 let dur_im1 = instant.duration_since(self.revisions[i - 1].timestamp);
189 let dur_i = self.revisions[i].timestamp.duration_since(instant);
196 let dur_i = self.revisions[i].timestamp.duration_since(instant);
@@ -194,6 +201,8 @@ impl History {
194 }
201 }
195 }
202 }
196
203
204+ /// Creates a [`Transaction`] that will match a revision created at around
205+ /// `instant`.
197 fn jump_instant(&mut self, instant: Instant) -> Vec<Transaction> {
206 fn jump_instant(&mut self, instant: Instant) -> Vec<Transaction> {
198 let search_result = self
207 let search_result = self
199 .revisions
208 .revisions
@@ -209,6 +218,8 @@ impl History {
209 self.jump_to(revision)
218 self.jump_to(revision)
210 }
219 }
211
220
221+ /// Creates a [`Transaction`] that will match a revision created `duration` ago
222+ /// from the timestamp of current revision.
212 fn jump_duration_backward(&mut self, duration: Duration) -> Vec<Transaction> {
223 fn jump_duration_backward(&mut self, duration: Duration) -> Vec<Transaction> {
213 match self.revisions[self.current].timestamp.checked_sub(duration) {
224 match self.revisions[self.current].timestamp.checked_sub(duration) {
214 Some(instant) => self.jump_instant(instant),
225 Some(instant) => self.jump_instant(instant),
@@ -216,6 +227,8 @@ impl History {
216 }
227 }
217 }
228 }
218
229
230+ /// Creates a [`Transaction`] that will match a revision created `duration` in
231+ /// the future from the timestamp of the current revision.
219 fn jump_duration_forward(&mut self, duration: Duration) -> Vec<Transaction> {
232 fn jump_duration_forward(&mut self, duration: Duration) -> Vec<Transaction> {
220 match self.revisions[self.current].timestamp.checked_add(duration) {
233 match self.revisions[self.current].timestamp.checked_add(duration) {
221 Some(instant) => self.jump_instant(instant),
234 Some(instant) => self.jump_instant(instant),
@@ -223,6 +236,7 @@ impl History {
223 }
236 }
224 }
237 }
225
238
239+ /// Creates an undo [`Transaction`].
226 pub fn earlier(&mut self, uk: UndoKind) -> Vec<Transaction> {
240 pub fn earlier(&mut self, uk: UndoKind) -> Vec<Transaction> {
227 use UndoKind::*;
241 use UndoKind::*;
228 match uk {
242 match uk {
@@ -231,6 +245,7 @@ impl History {
231 }
245 }
232 }
246 }
233
247
248+ /// Creates a redo [`Transaction`].
234 pub fn later(&mut self, uk: UndoKind) -> Vec<Transaction> {
249 pub fn later(&mut self, uk: UndoKind) -> Vec<Transaction> {
235 use UndoKind::*;
250 use UndoKind::*;
236 match uk {
251 match uk {
@@ -240,13 +255,14 @@ impl History {
240 }
255 }
241}
256}
242
257
258+/// Whether to undo by a number of edits or a duration of time.
243#[derive(Debug, PartialEq)]
259#[derive(Debug, PartialEq)]
244pub enum UndoKind {
260pub enum UndoKind {
245 Steps(usize),
261 Steps(usize),
246 TimePeriod(std::time::Duration),
262 TimePeriod(std::time::Duration),
247}
263}
248
264
249−// A subset of sytemd.time time span syntax units.
265+/// A subset of sytemd.time time span syntax units.
250const TIME_UNITS: &[(&[&str], &str, u64)] = &[
266const TIME_UNITS: &[(&[&str], &str, u64)] = &[
251 (&["seconds", "second", "sec", "s"], "seconds", 1),
267 (&["seconds", "second", "sec", "s"], "seconds", 1),
252 (&["minutes", "minute", "min", "m"], "minutes", 60),
268 (&["minutes", "minute", "min", "m"], "minutes", 60),
@@ -254,11 +270,20 @@ const TIME_UNITS: &[(&[&str], &str, u64)] = &[
254 (&["days", "day", "d"], "days", 24 * 60 * 60),
270 (&["days", "day", "d"], "days", 24 * 60 * 60),
255];
271];
256
272
273+/// Checks if the duration input can be turned into a valid duration. It must be a
274+/// positive integer and denote the [unit of time.](`TIME_UNITS`)
275+/// Examples of valid durations:
276+/// * `5 sec`
277+/// * `5 min`
278+/// * `5 hr`
279+/// * `5 days`
257static DURATION_VALIDATION_REGEX: Lazy<Regex> =
280static DURATION_VALIDATION_REGEX: Lazy<Regex> =
258 Lazy::new(|| Regex::new(r"^(?:\d+\s*[a-z]+\s*)+$").unwrap());
281 Lazy::new(|| Regex::new(r"^(?:\d+\s*[a-z]+\s*)+$").unwrap());
259
282
283+/// Captures both the number and unit as separate capture groups.
260static NUMBER_UNIT_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"(\d+)\s*([a-z]+)").unwrap());
284static NUMBER_UNIT_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"(\d+)\s*([a-z]+)").unwrap());
261
285
286+/// Parse a string (e.g. "5 sec") and try to convert it into a [`Duration`].
262fn parse_human_duration(s: &str) -> Result<Duration, String> {
287fn parse_human_duration(s: &str) -> Result<Duration, String> {
263 if !DURATION_VALIDATION_REGEX.is_match(s) {
288 if !DURATION_VALIDATION_REGEX.is_match(s) {
264 return Err("duration should be composed \
289 return Err("duration should be composed \