@@ -52,6 +52,45 @@ pub fn get_pair(ch: char) -> (char, char) {
5252 .unwrap_or((ch, ch))
5353}
5454
55+pub fn find_nth_closest_pairs_pos(
56+ text: RopeSlice,
57+ range: Range,
58+ n: usize,
59+) -> Result<(usize, usize)> {
60+ let is_open_pair = |ch| PAIRS.iter().any(|(open, _)| *open == ch);
61+ let is_close_pair = |ch| PAIRS.iter().any(|(_, close)| *close == ch);
62+
63+ let mut stack = Vec::with_capacity(2);
64+ let pos = range.cursor(text);
65+
66+ for ch in text.chars_at(pos) {
67+ if is_open_pair(ch) {
68+ // Track open pairs encountered so that we can step over
69+ // the correspoding close pairs that will come up further
70+ // down the loop. We want to find a lone close pair whose
71+ // open pair is before the cursor position.
72+ stack.push(ch);
73+ continue;
74+ } else if is_close_pair(ch) {
75+ let (open, _) = get_pair(ch);
76+ if stack.last() == Some(&open) {
77+ stack.pop();
78+ continue;
79+ } else {
80+ // In the ideal case the stack would be empty here and the
81+ // current character would be the close pair that we are
82+ // looking for. It could also be the case that the pairs
83+ // are unbalanced and we encounter a close pair that doesn't
84+ // close the last seen open pair. In either case use this
85+ // char as the auto-detected closest pair.
86+ return find_nth_pairs_pos(text, ch, range, n);
87+ }
88+ }
89+ }
90+
91+ Err(Error::PairNotFound)
92+}
93+
5594/// Find the position of surround pairs of `ch` which can be either a closing
5695/// or opening pair. `n` will skip n - 1 pairs (eg. n=2 will discard (only)
5796/// the first pair found and keep looking)