feat: add capture group selection

pull/13357/head
Tamerlan Salkenov 2025-04-15 21:30:16 +05:00
parent 7ebf650029
commit 8eabb117b0
1 changed files with 33 additions and 7 deletions

View File

@ -783,7 +783,7 @@ pub fn keep_or_remove_matches(
None None
} }
// TODO: support to split on capture #N instead of whole match // TODO: support to split on capture #N instead of last capture
pub fn select_on_matches( pub fn select_on_matches(
text: RopeSlice, text: RopeSlice,
selection: &Selection, selection: &Selection,
@ -792,11 +792,13 @@ pub fn select_on_matches(
let mut result = SmallVec::with_capacity(selection.len()); let mut result = SmallVec::with_capacity(selection.len());
for sel in selection { for sel in selection {
for mat in regex.find_iter(text.regex_input_at(sel.from()..sel.to())) { for cap in regex.captures_iter(text.regex_input_at(sel.from()..sel.to())) {
// TODO: retain range direction // TODO: retain range direction
// Get last capture group which is always Some
let cap = cap.get_group(cap.group_len() - 1).unwrap();
let start = text.byte_to_char(mat.start()); let start = text.byte_to_char(cap.start);
let end = text.byte_to_char(mat.end()); let end = text.byte_to_char(cap.end);
let range = Range::new(start, end); let range = Range::new(start, end);
// Make sure the match is not right outside of the selection. // Make sure the match is not right outside of the selection.
@ -863,11 +865,13 @@ pub fn split_on_matches(text: RopeSlice, selection: &Selection, regex: &rope::Re
let sel_end = sel.to(); let sel_end = sel.to();
let mut start = sel_start; let mut start = sel_start;
for mat in regex.find_iter(text.regex_input_at(sel_start..sel_end)) { for cap in regex.captures_iter(text.regex_input_at(sel_start..sel_end)) {
// TODO: retain range direction // TODO: retain range direction
let end = text.byte_to_char(mat.start()); // Get last capture group which is always Some
let cap = cap.get_group(cap.group_len() - 1).unwrap();
let end = text.byte_to_char(cap.start);
result.push(Range::new(start, end)); result.push(Range::new(start, end));
start = text.byte_to_char(mat.end()); start = text.byte_to_char(cap.end);
} }
if start < sel_end { if start < sel_end {
@ -1109,6 +1113,10 @@ mod test {
0 0
)) ))
); );
assert_eq!(
select_on_matches(s, &selection, &rope::Regex::new(r"Spanish (\w*)").unwrap()),
Some(Selection::single(27, 38))
);
let r = Rope::from_str("This\nString\n\ncontains multiple\nlines"); let r = Rope::from_str("This\nString\n\ncontains multiple\nlines");
let s = r.slice(..); let s = r.slice(..);
@ -1314,6 +1322,24 @@ mod test {
result.fragments(text.slice(..)).collect::<Vec<_>>(), result.fragments(text.slice(..)).collect::<Vec<_>>(),
&["", "abcd", "efg", "rs", "xyz"] &["", "abcd", "efg", "rs", "xyz"]
); );
let text = Rope::from("Range::new(0, 5), Range::new(6, 9), Range::new(11, 20)");
let result = split_on_matches(
text.slice(..),
&Selection::single(0, text.len_chars()),
&rope::Regex::new(r"(, )Range").unwrap(),
);
assert_eq!(
result.ranges(),
&[Range::new(0, 16), Range::new(18, 34), Range::new(36, 54)]
);
assert_eq!(
result.fragments(text.slice(..)).collect::<Vec<_>>(),
["Range::new(0, 5)", "Range::new(6, 9)", "Range::new(11, 20)"]
);
} }
#[test] #[test]