@@ -1,4 +1,4 @@
1−use crate::{search, Selection};
1+use crate::{search, Range, Selection};
2use ropey::RopeSlice;
2use ropey::RopeSlice;
4pub const PAIRS: &[(char, char)] = &[
4pub const PAIRS: &[(char, char)] = &[
@@ -35,33 +35,27 @@ pub fn get_pair(ch: char) -> (char, char) {
35pub fn find_nth_pairs_pos(
35pub fn find_nth_pairs_pos(
36 text: RopeSlice,
36 text: RopeSlice,
38− pos: usize,
38+ range: Range,
40) -> Option<(usize, usize)> {
40) -> Option<(usize, usize)> {
41− let (open, close) = get_pair(ch);
43− if text.len_chars() < 2 || pos >= text.len_chars() {
41+ if text.len_chars() < 2 || range.to() >= text.len_chars() {
44 return None;
42 return None;
45+ let (open, close) = get_pair(ch);
46+ let pos = range.cursor(text);
47 if open == close {
48 if open == close {
48 if Some(open) == text.get_char(pos) {
49 if Some(open) == text.get_char(pos) {
49− // Special case: cursor is directly on a matching char.
50+ // Cursor is directly on match char. We return no match
51− 0 => Some((pos, search::find_nth_next(text, close, pos + 1, n)?)),
52− _ if (pos + 1) == text.len_chars() => {
53− Some((search::find_nth_prev(text, open, pos, n)?, pos))
55− // We return no match because there's no way to know which
51+ // because there's no way to know which side of the char
56− // side of the char we should be searching on.
52+ // we should be searching on.
57− _ => None,
53+ return None;
61− search::find_nth_prev(text, open, pos, n)?,
62− search::find_nth_next(text, close, pos, n)?,
56+ search::find_nth_prev(text, open, pos, n)?,
57+ search::find_nth_next(text, close, pos, n)?,
67 find_nth_open_pair(text, open, close, pos, n)?,
61 find_nth_open_pair(text, open, close, pos, n)?,
@@ -160,8 +154,8 @@ pub fn get_surround_pos(
160) -> Option<Vec<usize>> {
154) -> Option<Vec<usize>> {
161 let mut change_pos = Vec::new();
155 let mut change_pos = Vec::new();
163− for range in selection {
157+ for &range in selection {
164− let (open_pos, close_pos) = find_nth_pairs_pos(text, ch, range.head, skip)?;
158+ let (open_pos, close_pos) = find_nth_pairs_pos(text, ch, range, skip)?;
165 if change_pos.contains(&open_pos) || change_pos.contains(&close_pos) {
159 if change_pos.contains(&open_pos) || change_pos.contains(&close_pos) {
166 return None;
160 return None;
@@ -178,67 +172,91 @@ mod test {
178 use ropey::Rope;
172 use ropey::Rope;
179 use smallvec::SmallVec;
173 use smallvec::SmallVec;
181− #[test]
175+ fn check_find_nth_pair_pos(
182− fn test_find_nth_pairs_pos() {
176+ text: &str,
177+ cases: Vec<(usize, char, usize, Option<(usize, usize)>)>,
183− let doc = Rope::from("some (text) here");
179+ let doc = Rope::from(text);
184 let slice = doc.slice(..);
180 let slice = doc.slice(..);
186− // cursor on [t]ext
182+ for (cursor_pos, ch, n, expected_range) in cases {
187− assert_eq!(find_nth_pairs_pos(slice, '(', 6, 1), Some((5, 10)));
188− assert_eq!(find_nth_pairs_pos(slice, ')', 6, 1), Some((5, 10)));
190− assert_eq!(find_nth_pairs_pos(slice, '(', 2, 1), None);
183+ let range = find_nth_pairs_pos(slice, ch, (cursor_pos, cursor_pos + 1).into(), n);
191− // cursor on bracket itself
184+ assert_eq!(
192− assert_eq!(find_nth_pairs_pos(slice, '(', 5, 1), Some((5, 10)));
185+ range, expected_range,
193− assert_eq!(find_nth_pairs_pos(slice, '(', 10, 1), Some((5, 10)));
186+ "Expected {:?}, got {:?}",
187+ expected_range, range
197− fn test_find_nth_pairs_pos_skip() {
193+ fn test_find_nth_pairs_pos() {
198− let doc = Rope::from("(so (many (good) text) here)");
194+ check_find_nth_pair_pos(
199− let slice = doc.slice(..);
195+ "some (text) here",
198+ (6, '(', 1, Some((5, 10))),
199+ (6, ')', 1, Some((5, 10))),
202+ // cursor on bracket itself
203+ (5, '(', 1, Some((5, 10))),
204+ (10, '(', 1, Some((5, 10))),
210+ fn test_find_nth_pairs_pos_skip() {
211+ check_find_nth_pair_pos(
212+ "(so (many (good) text) here)",
201− // cursor on go[o]d
214+ // cursor on go[o]d
202− assert_eq!(find_nth_pairs_pos(slice, '(', 13, 1), Some((10, 15)));
215+ (13, '(', 1, Some((10, 15))),
203− assert_eq!(find_nth_pairs_pos(slice, '(', 13, 2), Some((4, 21)));
216+ (13, '(', 2, Some((4, 21))),
204− assert_eq!(find_nth_pairs_pos(slice, '(', 13, 3), Some((0, 27)));
217+ (13, '(', 3, Some((0, 27))),
208 fn test_find_nth_pairs_pos_same() {
223 fn test_find_nth_pairs_pos_same() {
224+ check_find_nth_pair_pos(
209− let doc = Rope::from("'so 'many 'good' text' here'");
225+ "'so 'many 'good' text' here'",
210− let slice = doc.slice(..);
226+ vec![
212− // cursor on go[o]d
227+ // cursor on go[o]d
213− assert_eq!(find_nth_pairs_pos(slice, '\'', 13, 1), Some((10, 15)));
228+ (13, '\'', 1, Some((10, 15))),
214− assert_eq!(find_nth_pairs_pos(slice, '\'', 13, 2), Some((4, 21)));
229+ (13, '\'', 2, Some((4, 21))),
215− assert_eq!(find_nth_pairs_pos(slice, '\'', 13, 3), Some((0, 27)));
230+ (13, '\'', 3, Some((0, 27))),
216− // cursor on the quotes
231+ // cursor on the quotes
217− assert_eq!(find_nth_pairs_pos(slice, '\'', 10, 1), None);
232+ (10, '\'', 1, None),
218− // this is the best we can do since opening and closing pairs are same
233+ ],
219− assert_eq!(find_nth_pairs_pos(slice, '\'', 0, 1), Some((0, 4)));
234+ )
220− assert_eq!(find_nth_pairs_pos(slice, '\'', 27, 1), Some((21, 27)));
224 fn test_find_nth_pairs_pos_step() {
238 fn test_find_nth_pairs_pos_step() {
239+ check_find_nth_pair_pos(
225− let doc = Rope::from("((so)((many) good (text))(here))");
240+ "((so)((many) good (text))(here))",
226− let slice = doc.slice(..);
241+ vec![
228− // cursor on go[o]d
242+ // cursor on go[o]d
229− assert_eq!(find_nth_pairs_pos(slice, '(', 15, 1), Some((5, 24)));
243+ (15, '(', 1, Some((5, 24))),
230− assert_eq!(find_nth_pairs_pos(slice, '(', 15, 2), Some((0, 31)));
244+ (15, '(', 2, Some((0, 31))),
234 fn test_find_nth_pairs_pos_mixed() {
250 fn test_find_nth_pairs_pos_mixed() {
251+ check_find_nth_pair_pos(
235− let doc = Rope::from("(so [many {good} text] here)");
252+ "(so [many {good} text] here)",
236− let slice = doc.slice(..);
253+ vec![
238− // cursor on go[o]d
254+ // cursor on go[o]d
239− assert_eq!(find_nth_pairs_pos(slice, '{', 13, 1), Some((10, 15)));
255+ (13, '{', 1, Some((10, 15))),
240− assert_eq!(find_nth_pairs_pos(slice, '[', 13, 1), Some((4, 21)));
256+ (13, '[', 1, Some((4, 21))),
241− assert_eq!(find_nth_pairs_pos(slice, '(', 13, 1), Some((0, 27)));
257+ (13, '(', 1, Some((0, 27))),