|
|
@ -1,21 +1,16 @@
|
|
|
|
use ropey::RopeSlice;
|
|
|
|
use ropey::RopeSlice;
|
|
|
|
|
|
|
|
|
|
|
|
use crate::chars::{categorize_char, char_is_line_ending, char_is_whitespace, CharCategory};
|
|
|
|
use crate::chars::{categorize_char, CharCategory};
|
|
|
|
use crate::movement::{self, Direction};
|
|
|
|
use crate::graphemes::{next_grapheme_boundary, prev_grapheme_boundary};
|
|
|
|
|
|
|
|
use crate::movement::Direction;
|
|
|
|
use crate::surround;
|
|
|
|
use crate::surround;
|
|
|
|
use crate::Range;
|
|
|
|
use crate::Range;
|
|
|
|
|
|
|
|
|
|
|
|
fn this_word_end_pos(slice: RopeSlice, pos: usize) -> usize {
|
|
|
|
fn find_word_boundary(slice: RopeSlice, mut pos: usize, direction: Direction) -> usize {
|
|
|
|
this_word_bound_pos(slice, pos, Direction::Forward)
|
|
|
|
use CharCategory::{Eol, Whitespace};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn this_word_start_pos(slice: RopeSlice, pos: usize) -> usize {
|
|
|
|
|
|
|
|
this_word_bound_pos(slice, pos, Direction::Backward)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn this_word_bound_pos(slice: RopeSlice, mut pos: usize, direction: Direction) -> usize {
|
|
|
|
|
|
|
|
let iter = match direction {
|
|
|
|
let iter = match direction {
|
|
|
|
Direction::Forward => slice.chars_at(pos + 1),
|
|
|
|
Direction::Forward => slice.chars_at(pos),
|
|
|
|
Direction::Backward => {
|
|
|
|
Direction::Backward => {
|
|
|
|
let mut iter = slice.chars_at(pos);
|
|
|
|
let mut iter = slice.chars_at(pos);
|
|
|
|
iter.reverse();
|
|
|
|
iter.reverse();
|
|
|
@ -23,25 +18,32 @@ fn this_word_bound_pos(slice: RopeSlice, mut pos: usize, direction: Direction) -
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
match categorize_char(slice.char(pos)) {
|
|
|
|
let mut prev_category = match direction {
|
|
|
|
CharCategory::Eol | CharCategory::Whitespace => pos,
|
|
|
|
Direction::Forward if pos == 0 => Whitespace,
|
|
|
|
category => {
|
|
|
|
Direction::Forward => categorize_char(slice.char(pos - 1)),
|
|
|
|
for peek in iter {
|
|
|
|
Direction::Backward if pos == slice.len_chars() => Whitespace,
|
|
|
|
let curr_category = categorize_char(peek);
|
|
|
|
Direction::Backward => categorize_char(slice.char(pos)),
|
|
|
|
if curr_category != category
|
|
|
|
};
|
|
|
|
|| curr_category == CharCategory::Eol
|
|
|
|
|
|
|
|
|| curr_category == CharCategory::Whitespace
|
|
|
|
for ch in iter {
|
|
|
|
{
|
|
|
|
match categorize_char(ch) {
|
|
|
|
|
|
|
|
Eol | Whitespace => return pos,
|
|
|
|
|
|
|
|
category => {
|
|
|
|
|
|
|
|
if category != prev_category && pos != 0 && pos != slice.len_chars() {
|
|
|
|
return pos;
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pos = match direction {
|
|
|
|
if direction == Direction::Forward {
|
|
|
|
Direction::Forward => pos + 1,
|
|
|
|
pos += 1;
|
|
|
|
Direction::Backward => pos.saturating_sub(1),
|
|
|
|
} else {
|
|
|
|
|
|
|
|
pos = pos.saturating_sub(1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
prev_category = category;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pos
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pos
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
|
@ -55,46 +57,42 @@ pub fn textobject_word(
|
|
|
|
slice: RopeSlice,
|
|
|
|
slice: RopeSlice,
|
|
|
|
range: Range,
|
|
|
|
range: Range,
|
|
|
|
textobject: TextObject,
|
|
|
|
textobject: TextObject,
|
|
|
|
count: usize,
|
|
|
|
_count: usize,
|
|
|
|
) -> Range {
|
|
|
|
) -> Range {
|
|
|
|
let this_word_start = this_word_start_pos(slice, range.head);
|
|
|
|
// For 1-width cursor semantics.
|
|
|
|
let this_word_end = this_word_end_pos(slice, range.head);
|
|
|
|
let head = if range.head > range.anchor {
|
|
|
|
|
|
|
|
prev_grapheme_boundary(slice, range.head)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
range.head
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let word_start = find_word_boundary(slice, head, Direction::Backward);
|
|
|
|
|
|
|
|
let word_end = match slice.get_char(head).map(categorize_char) {
|
|
|
|
|
|
|
|
None | Some(CharCategory::Whitespace | CharCategory::Eol) => head,
|
|
|
|
|
|
|
|
_ => find_word_boundary(slice, head + 1, Direction::Forward),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Special case.
|
|
|
|
|
|
|
|
if word_start == word_end {
|
|
|
|
|
|
|
|
return Range::new(word_start, word_end);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let (anchor, head);
|
|
|
|
|
|
|
|
match textobject {
|
|
|
|
match textobject {
|
|
|
|
TextObject::Inside => {
|
|
|
|
TextObject::Inside => Range::new(word_start, word_end),
|
|
|
|
anchor = this_word_start;
|
|
|
|
TextObject::Around => Range::new(
|
|
|
|
head = this_word_end;
|
|
|
|
match slice
|
|
|
|
}
|
|
|
|
.get_char(word_start.saturating_sub(1))
|
|
|
|
TextObject::Around => {
|
|
|
|
.map(categorize_char)
|
|
|
|
if slice
|
|
|
|
|
|
|
|
.get_char(this_word_end + 1)
|
|
|
|
|
|
|
|
.map_or(true, char_is_line_ending)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
head = this_word_end;
|
|
|
|
None | Some(CharCategory::Eol) => word_start,
|
|
|
|
if slice
|
|
|
|
_ => prev_grapheme_boundary(slice, word_start),
|
|
|
|
.get_char(this_word_start.saturating_sub(1))
|
|
|
|
},
|
|
|
|
.map_or(true, char_is_line_ending)
|
|
|
|
match slice.get_char(word_end).map(categorize_char) {
|
|
|
|
{
|
|
|
|
None | Some(CharCategory::Eol) => word_end,
|
|
|
|
// single word on a line
|
|
|
|
_ => next_grapheme_boundary(slice, word_end),
|
|
|
|
anchor = this_word_start;
|
|
|
|
},
|
|
|
|
} else {
|
|
|
|
),
|
|
|
|
// last word on a line, select the whitespace before it too
|
|
|
|
}
|
|
|
|
anchor = movement::move_prev_word_end(slice, range, count).head;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if char_is_whitespace(slice.char(range.head)) {
|
|
|
|
|
|
|
|
// select whole whitespace and next word
|
|
|
|
|
|
|
|
head = movement::move_next_word_end(slice, range, count).head;
|
|
|
|
|
|
|
|
anchor = movement::backwards_skip_while(slice, range.head, |c| c.is_whitespace())
|
|
|
|
|
|
|
|
.map(|p| p + 1) // p is first *non* whitespace char, so +1 to get whitespace pos
|
|
|
|
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
head = movement::move_next_word_start(slice, range, count).head;
|
|
|
|
|
|
|
|
anchor = this_word_start;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
Range::new(anchor, head)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn textobject_surround(
|
|
|
|
pub fn textobject_surround(
|
|
|
@ -106,7 +104,10 @@ pub fn textobject_surround(
|
|
|
|
) -> Range {
|
|
|
|
) -> Range {
|
|
|
|
surround::find_nth_pairs_pos(slice, ch, range.head, count)
|
|
|
|
surround::find_nth_pairs_pos(slice, ch, range.head, count)
|
|
|
|
.map(|(anchor, head)| match textobject {
|
|
|
|
.map(|(anchor, head)| match textobject {
|
|
|
|
TextObject::Inside => Range::new(anchor + 1, head.saturating_sub(1)),
|
|
|
|
TextObject::Inside => Range::new(
|
|
|
|
|
|
|
|
next_grapheme_boundary(slice, anchor),
|
|
|
|
|
|
|
|
prev_grapheme_boundary(slice, head),
|
|
|
|
|
|
|
|
),
|
|
|
|
TextObject::Around => Range::new(anchor, head),
|
|
|
|
TextObject::Around => Range::new(anchor, head),
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.unwrap_or(range)
|
|
|
|
.unwrap_or(range)
|
|
|
@ -126,70 +127,70 @@ mod test {
|
|
|
|
let tests = &[
|
|
|
|
let tests = &[
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor at beginning of doc",
|
|
|
|
"cursor at beginning of doc",
|
|
|
|
vec![(0, Inside, (0, 5)), (0, Around, (0, 6))],
|
|
|
|
vec![(0, Inside, (0, 6)), (0, Around, (0, 7))],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor at middle of word",
|
|
|
|
"cursor at middle of word",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(13, Inside, (10, 15)),
|
|
|
|
(13, Inside, (10, 16)),
|
|
|
|
(10, Inside, (10, 15)),
|
|
|
|
(10, Inside, (10, 16)),
|
|
|
|
(15, Inside, (10, 15)),
|
|
|
|
(15, Inside, (10, 16)),
|
|
|
|
(13, Around, (10, 16)),
|
|
|
|
(13, Around, (9, 17)),
|
|
|
|
(10, Around, (10, 16)),
|
|
|
|
(10, Around, (9, 17)),
|
|
|
|
(15, Around, (10, 16)),
|
|
|
|
(15, Around, (9, 17)),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor between word whitespace",
|
|
|
|
"cursor between word whitespace",
|
|
|
|
vec![(6, Inside, (6, 6)), (6, Around, (6, 13))],
|
|
|
|
vec![(6, Inside, (6, 6)), (6, Around, (6, 6))],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor on word before newline\n",
|
|
|
|
"cursor on word before newline\n",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(22, Inside, (22, 28)),
|
|
|
|
(22, Inside, (22, 29)),
|
|
|
|
(28, Inside, (22, 28)),
|
|
|
|
(28, Inside, (22, 29)),
|
|
|
|
(25, Inside, (22, 28)),
|
|
|
|
(25, Inside, (22, 29)),
|
|
|
|
(22, Around, (21, 28)),
|
|
|
|
(22, Around, (21, 29)),
|
|
|
|
(28, Around, (21, 28)),
|
|
|
|
(28, Around, (21, 29)),
|
|
|
|
(25, Around, (21, 28)),
|
|
|
|
(25, Around, (21, 29)),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor on newline\nnext line",
|
|
|
|
"cursor on newline\nnext line",
|
|
|
|
vec![(17, Inside, (17, 17)), (17, Around, (17, 22))],
|
|
|
|
vec![(17, Inside, (17, 17)), (17, Around, (17, 17))],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor on word after newline\nnext line",
|
|
|
|
"cursor on word after newline\nnext line",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(29, Inside, (29, 32)),
|
|
|
|
(29, Inside, (29, 33)),
|
|
|
|
(30, Inside, (29, 32)),
|
|
|
|
(30, Inside, (29, 33)),
|
|
|
|
(32, Inside, (29, 32)),
|
|
|
|
(32, Inside, (29, 33)),
|
|
|
|
(29, Around, (29, 33)),
|
|
|
|
(29, Around, (29, 34)),
|
|
|
|
(30, Around, (29, 33)),
|
|
|
|
(30, Around, (29, 34)),
|
|
|
|
(32, Around, (29, 33)),
|
|
|
|
(32, Around, (29, 34)),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor on #$%:;* punctuation",
|
|
|
|
"cursor on #$%:;* punctuation",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(13, Inside, (10, 15)),
|
|
|
|
(13, Inside, (10, 16)),
|
|
|
|
(10, Inside, (10, 15)),
|
|
|
|
(10, Inside, (10, 16)),
|
|
|
|
(15, Inside, (10, 15)),
|
|
|
|
(15, Inside, (10, 16)),
|
|
|
|
(13, Around, (10, 16)),
|
|
|
|
(13, Around, (9, 17)),
|
|
|
|
(10, Around, (10, 16)),
|
|
|
|
(10, Around, (9, 17)),
|
|
|
|
(15, Around, (10, 16)),
|
|
|
|
(15, Around, (9, 17)),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor on punc%^#$:;.tuation",
|
|
|
|
"cursor on punc%^#$:;.tuation",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(14, Inside, (14, 20)),
|
|
|
|
(14, Inside, (14, 21)),
|
|
|
|
(20, Inside, (14, 20)),
|
|
|
|
(20, Inside, (14, 21)),
|
|
|
|
(17, Inside, (14, 20)),
|
|
|
|
(17, Inside, (14, 21)),
|
|
|
|
(14, Around, (14, 20)),
|
|
|
|
(14, Around, (13, 22)),
|
|
|
|
// FIXME: edge case
|
|
|
|
// FIXME: edge case
|
|
|
|
// (20, Around, (14, 20)),
|
|
|
|
// (20, Around, (14, 20)),
|
|
|
|
(17, Around, (14, 20)),
|
|
|
|
(17, Around, (13, 22)),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
@ -198,14 +199,14 @@ mod test {
|
|
|
|
(9, Inside, (9, 9)),
|
|
|
|
(9, Inside, (9, 9)),
|
|
|
|
(10, Inside, (10, 10)),
|
|
|
|
(10, Inside, (10, 10)),
|
|
|
|
(11, Inside, (11, 11)),
|
|
|
|
(11, Inside, (11, 11)),
|
|
|
|
(9, Around, (9, 16)),
|
|
|
|
(9, Around, (9, 9)),
|
|
|
|
(10, Around, (9, 16)),
|
|
|
|
(10, Around, (10, 10)),
|
|
|
|
(11, Around, (9, 16)),
|
|
|
|
(11, Around, (11, 11)),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"cursor at end of doc",
|
|
|
|
"cursor at end of doc",
|
|
|
|
vec![(19, Inside, (17, 19)), (19, Around, (16, 19))],
|
|
|
|
vec![(19, Inside, (17, 20)), (19, Around, (16, 20))],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
];
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
@ -234,67 +235,67 @@ mod test {
|
|
|
|
"simple (single) surround pairs",
|
|
|
|
"simple (single) surround pairs",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(3, Inside, (3, 3), '(', 1),
|
|
|
|
(3, Inside, (3, 3), '(', 1),
|
|
|
|
(7, Inside, (8, 13), ')', 1),
|
|
|
|
(7, Inside, (8, 14), ')', 1),
|
|
|
|
(10, Inside, (8, 13), '(', 1),
|
|
|
|
(10, Inside, (8, 14), '(', 1),
|
|
|
|
(14, Inside, (8, 13), ')', 1),
|
|
|
|
(14, Inside, (8, 14), ')', 1),
|
|
|
|
(3, Around, (3, 3), '(', 1),
|
|
|
|
(3, Around, (3, 3), '(', 1),
|
|
|
|
(7, Around, (7, 14), ')', 1),
|
|
|
|
(7, Around, (7, 15), ')', 1),
|
|
|
|
(10, Around, (7, 14), '(', 1),
|
|
|
|
(10, Around, (7, 15), '(', 1),
|
|
|
|
(14, Around, (7, 14), ')', 1),
|
|
|
|
(14, Around, (7, 15), ')', 1),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"samexx 'single' surround pairs",
|
|
|
|
"samexx 'single' surround pairs",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(3, Inside, (3, 3), '\'', 1),
|
|
|
|
(3, Inside, (3, 3), '\'', 1),
|
|
|
|
(7, Inside, (8, 13), '\'', 1),
|
|
|
|
(7, Inside, (7, 7), '\'', 1),
|
|
|
|
(10, Inside, (8, 13), '\'', 1),
|
|
|
|
(10, Inside, (8, 14), '\'', 1),
|
|
|
|
(14, Inside, (8, 13), '\'', 1),
|
|
|
|
(14, Inside, (14, 14), '\'', 1),
|
|
|
|
(3, Around, (3, 3), '\'', 1),
|
|
|
|
(3, Around, (3, 3), '\'', 1),
|
|
|
|
(7, Around, (7, 14), '\'', 1),
|
|
|
|
(7, Around, (7, 7), '\'', 1),
|
|
|
|
(10, Around, (7, 14), '\'', 1),
|
|
|
|
(10, Around, (7, 15), '\'', 1),
|
|
|
|
(14, Around, (7, 14), '\'', 1),
|
|
|
|
(14, Around, (14, 14), '\'', 1),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"(nested (surround (pairs)) 3 levels)",
|
|
|
|
"(nested (surround (pairs)) 3 levels)",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(0, Inside, (1, 34), '(', 1),
|
|
|
|
(0, Inside, (1, 35), '(', 1),
|
|
|
|
(6, Inside, (1, 34), ')', 1),
|
|
|
|
(6, Inside, (1, 35), ')', 1),
|
|
|
|
(8, Inside, (9, 24), '(', 1),
|
|
|
|
(8, Inside, (9, 25), '(', 1),
|
|
|
|
(8, Inside, (9, 34), ')', 2),
|
|
|
|
(8, Inside, (9, 35), ')', 2),
|
|
|
|
(20, Inside, (9, 24), '(', 2),
|
|
|
|
(20, Inside, (9, 25), '(', 2),
|
|
|
|
(20, Inside, (1, 34), ')', 3),
|
|
|
|
(20, Inside, (1, 35), ')', 3),
|
|
|
|
(0, Around, (0, 35), '(', 1),
|
|
|
|
(0, Around, (0, 36), '(', 1),
|
|
|
|
(6, Around, (0, 35), ')', 1),
|
|
|
|
(6, Around, (0, 36), ')', 1),
|
|
|
|
(8, Around, (8, 25), '(', 1),
|
|
|
|
(8, Around, (8, 26), '(', 1),
|
|
|
|
(8, Around, (8, 35), ')', 2),
|
|
|
|
(8, Around, (8, 36), ')', 2),
|
|
|
|
(20, Around, (8, 25), '(', 2),
|
|
|
|
(20, Around, (8, 26), '(', 2),
|
|
|
|
(20, Around, (0, 35), ')', 3),
|
|
|
|
(20, Around, (0, 36), ')', 3),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"(mixed {surround [pair] same} line)",
|
|
|
|
"(mixed {surround [pair] same} line)",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(2, Inside, (1, 33), '(', 1),
|
|
|
|
(2, Inside, (1, 34), '(', 1),
|
|
|
|
(9, Inside, (8, 27), '{', 1),
|
|
|
|
(9, Inside, (8, 28), '{', 1),
|
|
|
|
(18, Inside, (18, 21), '[', 1),
|
|
|
|
(18, Inside, (18, 22), '[', 1),
|
|
|
|
(2, Around, (0, 34), '(', 1),
|
|
|
|
(2, Around, (0, 35), '(', 1),
|
|
|
|
(9, Around, (7, 28), '{', 1),
|
|
|
|
(9, Around, (7, 29), '{', 1),
|
|
|
|
(18, Around, (17, 22), '[', 1),
|
|
|
|
(18, Around, (17, 23), '[', 1),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"(stepped (surround) pairs (should) skip)",
|
|
|
|
"(stepped (surround) pairs (should) skip)",
|
|
|
|
vec![(22, Inside, (1, 38), '(', 1), (22, Around, (0, 39), '(', 1)],
|
|
|
|
vec![(22, Inside, (1, 39), '(', 1), (22, Around, (0, 40), '(', 1)],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
(
|
|
|
|
"[surround pairs{\non different]\nlines}",
|
|
|
|
"[surround pairs{\non different]\nlines}",
|
|
|
|
vec![
|
|
|
|
vec![
|
|
|
|
(7, Inside, (1, 28), '[', 1),
|
|
|
|
(7, Inside, (1, 29), '[', 1),
|
|
|
|
(15, Inside, (16, 35), '{', 1),
|
|
|
|
(15, Inside, (16, 36), '{', 1),
|
|
|
|
(7, Around, (0, 29), '[', 1),
|
|
|
|
(7, Around, (0, 30), '[', 1),
|
|
|
|
(15, Around, (15, 36), '{', 1),
|
|
|
|
(15, Around, (15, 37), '{', 1),
|
|
|
|
],
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
];
|
|
|
|
];
|
|
|
|