Selection: fail early if new() is called with no ranges.

This commit is contained in:
Blaž Hrastnik 2021-03-22 12:21:33 +09:00
parent 71999cce43
commit 798dbd27c5
2 changed files with 14 additions and 3 deletions

View File

@ -126,6 +126,7 @@ pub fn fragment<'a, 'b: 'a>(&'a self, text: RopeSlice<'b>) -> Cow<'b, str> {
} }
/// A selection consists of one or more selection ranges. /// A selection consists of one or more selection ranges.
/// invariant: A selection can never be empty (always contains at least primary range).
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Selection { pub struct Selection {
ranges: SmallVec<[Range; 1]>, ranges: SmallVec<[Range; 1]>,
@ -205,12 +206,14 @@ pub fn point(pos: usize) -> Self {
// TODO: consume an iterator or a vec to reduce allocations? // TODO: consume an iterator or a vec to reduce allocations?
#[must_use] #[must_use]
pub fn new(ranges: SmallVec<[Range; 1]>, primary_index: usize) -> Self { pub fn new(ranges: SmallVec<[Range; 1]>, primary_index: usize) -> Self {
assert!(!ranges.is_empty());
fn normalize(mut ranges: SmallVec<[Range; 1]>, mut primary_index: usize) -> Selection { fn normalize(mut ranges: SmallVec<[Range; 1]>, mut primary_index: usize) -> Selection {
let primary = ranges[primary_index]; let primary = ranges[primary_index];
ranges.sort_unstable_by_key(Range::from); ranges.sort_unstable_by_key(Range::from);
primary_index = ranges.iter().position(|&range| range == primary).unwrap(); primary_index = ranges.iter().position(|&range| range == primary).unwrap();
let mut result: SmallVec<[Range; 1]> = SmallVec::new(); let mut result = SmallVec::new();
// TODO: we could do with one vec by removing elements as we mutate // TODO: we could do with one vec by removing elements as we mutate
@ -294,7 +297,7 @@ fn into_iter(self) -> std::slice::Iter<'a, Range> {
} }
} }
// TODO: checkSelection -> check if valid for doc length // TODO: checkSelection -> check if valid for doc length && sorted
pub fn keep_matches( pub fn keep_matches(
text: RopeSlice, text: RopeSlice,
@ -387,6 +390,12 @@ pub fn split_on_matches(
mod test { mod test {
use super::*; use super::*;
#[test]
#[should_panic]
fn test_new_empty() {
let sel = Selection::new(smallvec![], 0);
}
#[test] #[test]
fn test_create_normalizes_and_merges() { fn test_create_normalizes_and_merges() {
let sel = Selection::new( let sel = Selection::new(

View File

@ -464,11 +464,13 @@ pub fn change<I>(doc: &Rope, changes: I) -> Self
I: IntoIterator<Item = Change> + ExactSizeIterator, I: IntoIterator<Item = Change> + ExactSizeIterator,
{ {
let len = doc.len_chars(); let len = doc.len_chars();
let acc = Vec::with_capacity(2 * changes.len() + 1); let acc = Vec::with_capacity(2 * changes.len() + 1); // rough estimate
let mut changeset = ChangeSet { changes: acc, len }; let mut changeset = ChangeSet { changes: acc, len };
// TODO: verify ranges are ordered and not overlapping or change will panic. // TODO: verify ranges are ordered and not overlapping or change will panic.
// TODO: test for (pos, pos, None) to factor out as nothing
let mut last = 0; let mut last = 0;
for (from, to, tendril) in changes { for (from, to, tendril) in changes {
// Retain from last "to" to current "from" // Retain from last "to" to current "from"