From f29f01858d1b8c9e54b3293879796a4650823f60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= <blaz@mxxn.io>
Date: Fri, 19 Mar 2021 11:14:13 +0900
Subject: [PATCH] Implement iter() and len() directly on Selection.

---
 helix-core/src/comment.rs     |  2 +-
 helix-core/src/selection.rs   | 28 +++++++++++++++++++++++-----
 helix-core/src/transaction.rs |  2 +-
 helix-term/src/commands.rs    |  6 ++----
 helix-term/src/ui/editor.rs   |  1 -
 5 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs
index 35aabda9..5bcf3767 100644
--- a/helix-core/src/comment.rs
+++ b/helix-core/src/comment.rs
@@ -44,7 +44,7 @@ pub fn toggle_line_comments(doc: &Rope, selection: &Selection) -> Transaction {
     let token = "//";
     let comment = Tendril::from(format!("{} ", token));
 
-    for selection in selection.ranges() {
+    for selection in selection {
         let start = text.char_to_line(selection.from());
         let end = text.char_to_line(selection.to());
         let lines = start..end + 1;
diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs
index c34dff31..91edcf81 100644
--- a/helix-core/src/selection.rs
+++ b/helix-core/src/selection.rs
@@ -269,6 +269,25 @@ impl Selection {
     pub fn fragments<'a>(&'a self, text: RopeSlice<'a>) -> impl Iterator<Item = Cow<str>> + 'a {
         self.ranges.iter().map(move |range| range.fragment(text))
     }
+
+    #[inline(always)]
+    pub fn iter(&self) -> std::slice::Iter<'_, Range> {
+        self.ranges.iter()
+    }
+
+    #[inline(always)]
+    pub fn len(&self) -> usize {
+        self.ranges.len()
+    }
+}
+
+impl<'a> IntoIterator for &'a Selection {
+    type Item = &'a Range;
+    type IntoIter = std::slice::Iter<'a, Range>;
+
+    fn into_iter(self) -> std::slice::Iter<'a, Range> {
+        self.ranges().iter()
+    }
 }
 
 // TODO: checkSelection -> check if valid for doc length
@@ -279,7 +298,6 @@ pub fn keep_matches(
     regex: &crate::regex::Regex,
 ) -> Option<Selection> {
     let result: SmallVec<_> = selection
-        .ranges()
         .iter()
         .filter(|range| regex.is_match(&range.fragment(text)))
         .copied()
@@ -297,9 +315,9 @@ pub fn select_on_matches(
     selection: &Selection,
     regex: &crate::regex::Regex,
 ) -> Option<Selection> {
-    let mut result = SmallVec::with_capacity(selection.ranges().len());
+    let mut result = SmallVec::with_capacity(selection.len());
 
-    for sel in selection.ranges() {
+    for sel in selection {
         // TODO: can't avoid occasional allocations since Regex can't operate on chunks yet
         let fragment = sel.fragment(text);
 
@@ -331,9 +349,9 @@ pub fn split_on_matches(
     selection: &Selection,
     regex: &crate::regex::Regex,
 ) -> Selection {
-    let mut result = SmallVec::with_capacity(selection.ranges().len());
+    let mut result = SmallVec::with_capacity(selection.len());
 
-    for sel in selection.ranges() {
+    for sel in selection {
         // TODO: can't avoid occasional allocations since Regex can't operate on chunks yet
         let fragment = sel.fragment(text);
 
diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs
index 2bd100e8..1f9e63aa 100644
--- a/helix-core/src/transaction.rs
+++ b/helix-core/src/transaction.rs
@@ -494,7 +494,7 @@ impl Transaction {
     where
         F: FnMut(&Range) -> Change,
     {
-        Self::change(doc, selection.ranges().iter().map(f))
+        Self::change(doc, selection.iter().map(f))
     }
 
     /// Insert text at each selection head.
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 291f8577..f84bb16e 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -781,7 +781,6 @@ pub fn buffer_picker(cx: &mut Context) {
 // calculate line numbers for each selection range
 fn selection_lines(doc: &Rope, selection: &Selection) -> Vec<usize> {
     let mut lines = selection
-        .ranges()
         .iter()
         .map(|range| doc.char_to_line(range.head))
         .collect::<Vec<_>>();
@@ -1145,7 +1144,7 @@ fn get_lines(doc: &Document) -> Vec<usize> {
     let mut lines = Vec::new();
 
     // Get all line numbers
-    for range in doc.selection().ranges() {
+    for range in doc.selection() {
         let start = doc.text().char_to_line(range.from());
         let end = doc.text().char_to_line(range.to());
 
@@ -1220,7 +1219,6 @@ pub fn format_selections(cx: &mut Context) {
 
     let ranges: Vec<lsp::Range> = doc
         .selection()
-        .ranges()
         .iter()
         .map(|range| helix_lsp::util::range_to_lsp_range(doc.text(), *range))
         .collect();
@@ -1257,7 +1255,7 @@ pub fn join_selections(cx: &mut Context) {
     let mut changes = Vec::new();
     let fragment = Tendril::from(" ");
 
-    for selection in doc.selection().ranges() {
+    for selection in doc.selection() {
         let start = text.char_to_line(selection.from());
         let mut end = text.char_to_line(selection.to());
         if start == end {
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 5e8ef05e..670de6d6 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -211,7 +211,6 @@ impl EditorView {
             for selection in view
                 .doc
                 .selection()
-                .ranges()
                 .iter()
                 .filter(|range| range.overlaps(&screen))
             {