|
|
@ -154,6 +154,29 @@ fn find_nth_closest_pairs_plain(
|
|
|
|
Err(Error::PairNotFound)
|
|
|
|
Err(Error::PairNotFound)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Find the position of surrounding tags around cursor
|
|
|
|
|
|
|
|
/// `n` will skip n - 1 tags (e.g. n=2 will discard only the first tag found)
|
|
|
|
|
|
|
|
/// and keep looking
|
|
|
|
|
|
|
|
// pub fn find_nth_tag_pos(
|
|
|
|
|
|
|
|
// text: RopeSlice,
|
|
|
|
|
|
|
|
// range: Range,
|
|
|
|
|
|
|
|
// n: usize,
|
|
|
|
|
|
|
|
// ) -> Result<((usize, usize), (usize, usize))> {
|
|
|
|
|
|
|
|
// // 7 is the minimum possible length for a tag, e.g. <a></a>.
|
|
|
|
|
|
|
|
// if text.len_chars() < 7 {
|
|
|
|
|
|
|
|
// return Err(Error::PairNotFound);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if range.to() >= text.len_chars() {
|
|
|
|
|
|
|
|
// return Err(Error::RangeExceedsText);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// let cursor_position = range.cursor(text);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// let open = ();
|
|
|
|
|
|
|
|
// let close = ();
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
/// Find the position of surround pairs of `ch` which can be either a closing
|
|
|
|
/// Find the position of surround pairs of `ch` which can be either a closing
|
|
|
|
/// or opening pair. `n` will skip n - 1 pairs (eg. n=2 will discard (only)
|
|
|
|
/// or opening pair. `n` will skip n - 1 pairs (eg. n=2 will discard (only)
|
|
|
|
/// the first pair found and keep looking)
|
|
|
|
/// the first pair found and keep looking)
|
|
|
@ -314,54 +337,82 @@ pub fn get_surround_pos(
|
|
|
|
Ok(change_pos)
|
|
|
|
Ok(change_pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn find_nth_close_tag(
|
|
|
|
|
|
|
|
text: RopeSlice,
|
|
|
|
|
|
|
|
tag: &str,
|
|
|
|
|
|
|
|
mut pos: usize,
|
|
|
|
|
|
|
|
n: usize,
|
|
|
|
|
|
|
|
) -> Result<(Vec<usize>, Vec<usize>)> {
|
|
|
|
|
|
|
|
// if text.len_chars() < 2 {
|
|
|
|
|
|
|
|
// return Err(Error::PairNotFound);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if range.to() >= text.len_chars() {
|
|
|
|
|
|
|
|
// return Err(Error::RangeExceedsText);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
Ok((vec![4, 7], vec![10, 13]))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// like get_surround_pos, but for Tags
|
|
|
|
/// like get_surround_pos, but for Tags
|
|
|
|
pub fn get_surround_pos_tag(
|
|
|
|
pub fn get_surround_pos_tag(
|
|
|
|
text: RopeSlice,
|
|
|
|
text: RopeSlice,
|
|
|
|
selection: &Selection,
|
|
|
|
selection: &Selection,
|
|
|
|
tag: &str,
|
|
|
|
|
|
|
|
skip: usize,
|
|
|
|
skip: usize,
|
|
|
|
) -> Result<Vec<usize>> {
|
|
|
|
) -> Result<Vec<(usize, usize)>> {
|
|
|
|
let mut change_pos = Vec::new();
|
|
|
|
// // let change_pos: Vec<(usize, usize)> = vec![(4, 10), (13, 20), (24, 30), (33, 40)];
|
|
|
|
|
|
|
|
// let mut change_pos = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // for &range in selection {
|
|
|
|
|
|
|
|
// // let (start1, end1, start2, end2) = {
|
|
|
|
|
|
|
|
// // let cursor_pos = range.cursor(text);
|
|
|
|
|
|
|
|
// // // let range_raw = find_nth_close_tag(text, cursor_pos, skip).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // let first = range_raw.0;
|
|
|
|
|
|
|
|
// // let second = range_raw.1;
|
|
|
|
|
|
|
|
// // let first_1 = first.first().unwrap();
|
|
|
|
|
|
|
|
// // let first_2 = second.last().unwrap();
|
|
|
|
|
|
|
|
// // let second_1 = first.first().unwrap();
|
|
|
|
|
|
|
|
// // let second_2 = second.last().unwrap();
|
|
|
|
|
|
|
|
// // let range_first = Range::new(*first_1, *first_2);
|
|
|
|
|
|
|
|
// // let range_last = Range::new(*second_1, *second_2);
|
|
|
|
|
|
|
|
// // (
|
|
|
|
|
|
|
|
// // range_first.from(),
|
|
|
|
|
|
|
|
// // range_first.to(),
|
|
|
|
|
|
|
|
// // range_last.from(),
|
|
|
|
|
|
|
|
// // range_last.to(),
|
|
|
|
|
|
|
|
// // )
|
|
|
|
|
|
|
|
// // };
|
|
|
|
|
|
|
|
// // change_pos.push((start1, end1));
|
|
|
|
|
|
|
|
// // change_pos.push((start2, end2));
|
|
|
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
Ok(vec![(14, 24)])
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for &range in selection {
|
|
|
|
pub fn is_valid_tagname_char(ch: char) -> bool {
|
|
|
|
let (start1, end1, start2, end2) = {
|
|
|
|
ch.is_alphanumeric() || ch == '_' || ch == '-' || ch == '.'
|
|
|
|
let pos = range.cursor(text);
|
|
|
|
}
|
|
|
|
let range_raw = find_nth_close_tag(text, tag, pos, skip).unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
pub fn find_next_tag(text: RopeSlice, mut pos: usize, n: usize) -> Option<(usize, usize)> {
|
|
|
|
let first = range_raw.0;
|
|
|
|
if pos >= text.len_chars() || n == 0 {
|
|
|
|
let second = range_raw.1;
|
|
|
|
return None;
|
|
|
|
let first_1 = first.first().unwrap();
|
|
|
|
|
|
|
|
let first_2 = second.last().unwrap();
|
|
|
|
|
|
|
|
let second_1 = first.first().unwrap();
|
|
|
|
|
|
|
|
let second_2 = second.last().unwrap();
|
|
|
|
|
|
|
|
let range_first = Range::new(*first_1, *first_2);
|
|
|
|
|
|
|
|
let range_last = Range::new(*second_1, *second_2);
|
|
|
|
|
|
|
|
(
|
|
|
|
|
|
|
|
range_first.from(),
|
|
|
|
|
|
|
|
range_first.to(),
|
|
|
|
|
|
|
|
range_last.from(),
|
|
|
|
|
|
|
|
range_last.to(),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
change_pos.extend_from_slice(&[start1, end1, start2, end2]);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(change_pos)
|
|
|
|
|
|
|
|
|
|
|
|
let mut chars = text.chars_at(pos);
|
|
|
|
|
|
|
|
let mut possible_tag = String::new();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'outer: loop {
|
|
|
|
|
|
|
|
// look forward, try to find something that looks like a closing tag e.g. </html>
|
|
|
|
|
|
|
|
// extract the name so e.g. "html".
|
|
|
|
|
|
|
|
// set current_tag_name to this "html" string, then break.
|
|
|
|
|
|
|
|
let next_char = chars.next()?;
|
|
|
|
|
|
|
|
pos += 1;
|
|
|
|
|
|
|
|
if next_char == '<' {
|
|
|
|
|
|
|
|
let char_after_that = chars.next()?;
|
|
|
|
|
|
|
|
pos += 1;
|
|
|
|
|
|
|
|
if char_after_that == '/' {
|
|
|
|
|
|
|
|
let mut possible_tag_name = String::new();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
|
|
|
let current_char = chars.next()?;
|
|
|
|
|
|
|
|
pos += 1;
|
|
|
|
|
|
|
|
if is_valid_tagname_char(current_char) {
|
|
|
|
|
|
|
|
possible_tag_name.push(current_char);
|
|
|
|
|
|
|
|
} else if current_char == '>' && possible_tag_name.len() != 0 {
|
|
|
|
|
|
|
|
// victory!
|
|
|
|
|
|
|
|
possible_tag.push_str(&possible_tag_name[..]);
|
|
|
|
|
|
|
|
break 'outer;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Some((pos - possible_tag.len() - 1, pos - 2));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
#[cfg(test)]
|
|
|
@ -388,18 +439,10 @@ mod test {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[test]
|
|
|
|
fn test_get_surround_pos_tag_simple() {
|
|
|
|
fn test_find_next_tag() {
|
|
|
|
#[rustfmt::skip]
|
|
|
|
let doc = Rope::from("<tag>hello</tag>");
|
|
|
|
let (doc, selection, expectations) =
|
|
|
|
|
|
|
|
rope_with_selections_and_expectations_tags(
|
|
|
|
|
|
|
|
"<tag>hello</tag> <MegaDiv>lol</MegaDiv>",
|
|
|
|
|
|
|
|
" ___ ^ ___ _______ ^ _______ "
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
assert_eq!(find_next_tag(doc.slice(..), 7, 1).unwrap(), (14, 24));
|
|
|
|
get_tag_surround_pos(None, doc.slice(..), &selection, 1).unwrap(),
|
|
|
|
|
|
|
|
expectations
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[test]
|
|
|
|