Add containing range APIs to query cursor
Co-authored-by: Kirill Bulatov <mail4score@gmail.com> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com> Co-authored-by: dino <dinojoaocosta@gmail.com> Co-authored-by: John Tur <john-tur@outlook.com> Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: dino <dinojoaocosta@gmail.com> Co-authored-by: Will Lillis <will.lillis24@gmail.com>
This commit is contained in:
parent
7d3feeae9a
commit
c0b1710f8a
13 changed files with 420 additions and 34 deletions
|
|
@ -448,6 +448,14 @@ struct Query {
|
|||
/// The range of rows in which the query will be executed
|
||||
#[arg(long)]
|
||||
pub row_range: Option<String>,
|
||||
/// The range of byte offsets in which the query will be executed. Only the matches that are fully contained within the provided
|
||||
/// byte range will be returned.
|
||||
#[arg(long)]
|
||||
pub containing_byte_range: Option<String>,
|
||||
/// The range of rows in which the query will be executed. Only the matches that are fully contained within the provided row range
|
||||
/// will be returned.
|
||||
#[arg(long)]
|
||||
pub containing_row_range: Option<String>,
|
||||
/// Select a language by the scope instead of a file extension
|
||||
#[arg(long)]
|
||||
pub scope: Option<String>,
|
||||
|
|
@ -1486,6 +1494,18 @@ impl Query {
|
|||
let end = parts.next().unwrap().parse().ok()?;
|
||||
Some(Point::new(start, 0)..Point::new(end, 0))
|
||||
});
|
||||
let containing_byte_range = self.containing_byte_range.as_ref().and_then(|range| {
|
||||
let mut parts = range.split(':');
|
||||
let start = parts.next()?.parse().ok()?;
|
||||
let end = parts.next().unwrap().parse().ok()?;
|
||||
Some(start..end)
|
||||
});
|
||||
let containing_point_range = self.containing_row_range.as_ref().and_then(|range| {
|
||||
let mut parts = range.split(':');
|
||||
let start = parts.next()?.parse().ok()?;
|
||||
let end = parts.next().unwrap().parse().ok()?;
|
||||
Some(Point::new(start, 0)..Point::new(end, 0))
|
||||
});
|
||||
|
||||
let cancellation_flag = util::cancel_on_signal();
|
||||
|
||||
|
|
@ -1514,6 +1534,8 @@ impl Query {
|
|||
ordered_captures: self.captures,
|
||||
byte_range,
|
||||
point_range,
|
||||
containing_byte_range,
|
||||
containing_point_range,
|
||||
quiet: self.quiet,
|
||||
print_time: self.time,
|
||||
stdin: false,
|
||||
|
|
@ -1557,6 +1579,8 @@ impl Query {
|
|||
ordered_captures: self.captures,
|
||||
byte_range,
|
||||
point_range,
|
||||
containing_byte_range,
|
||||
containing_point_range,
|
||||
quiet: self.quiet,
|
||||
print_time: self.time,
|
||||
stdin: true,
|
||||
|
|
@ -1575,6 +1599,8 @@ impl Query {
|
|||
ordered_captures: self.captures,
|
||||
byte_range,
|
||||
point_range,
|
||||
containing_byte_range,
|
||||
containing_point_range,
|
||||
quiet: self.quiet,
|
||||
print_time: self.time,
|
||||
stdin: true,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ pub struct QueryFileOptions {
|
|||
pub ordered_captures: bool,
|
||||
pub byte_range: Option<Range<usize>>,
|
||||
pub point_range: Option<Range<Point>>,
|
||||
pub containing_byte_range: Option<Range<usize>>,
|
||||
pub containing_point_range: Option<Range<Point>>,
|
||||
pub quiet: bool,
|
||||
pub print_time: bool,
|
||||
pub stdin: bool,
|
||||
|
|
@ -48,6 +50,12 @@ pub fn query_file_at_path(
|
|||
if let Some(ref range) = opts.point_range {
|
||||
query_cursor.set_point_range(range.clone());
|
||||
}
|
||||
if let Some(ref range) = opts.containing_byte_range {
|
||||
query_cursor.set_containing_byte_range(range.clone());
|
||||
}
|
||||
if let Some(ref range) = opts.containing_point_range {
|
||||
query_cursor.set_containing_point_range(range.clone());
|
||||
}
|
||||
|
||||
let mut parser = Parser::new();
|
||||
parser.set_language(language)?;
|
||||
|
|
|
|||
|
|
@ -2669,6 +2669,64 @@ fn test_query_matches_within_range_of_long_repetition() {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_matches_contained_within_range() {
|
||||
allocations::record(|| {
|
||||
let language = get_language("json");
|
||||
let query = Query::new(
|
||||
&language,
|
||||
r#"
|
||||
("[" @l_bracket "]" @r_bracket)
|
||||
("{" @l_brace "}" @r_brace)
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let source = r#"
|
||||
[
|
||||
{"key1": "value1"},
|
||||
{"key2": "value2"},
|
||||
{"key3": "value3"},
|
||||
{"key4": "value4"},
|
||||
{"key5": "value5"},
|
||||
{"key6": "value6"},
|
||||
{"key7": "value7"},
|
||||
{"key8": "value8"},
|
||||
{"key9": "value9"},
|
||||
{"key10": "value10"},
|
||||
{"key11": "value11"},
|
||||
{"key12": "value12"},
|
||||
]
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
let mut parser = Parser::new();
|
||||
parser.set_language(&language).unwrap();
|
||||
let tree = parser.parse(&source, None).unwrap();
|
||||
|
||||
let expected_matches = [
|
||||
(1, vec![("l_brace", "{"), ("r_brace", "}")]),
|
||||
(1, vec![("l_brace", "{"), ("r_brace", "}")]),
|
||||
];
|
||||
{
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor
|
||||
.set_containing_point_range(Point::new(5, 0)..Point::new(7, 0))
|
||||
.matches(&query, tree.root_node(), source.as_bytes());
|
||||
assert_eq!(collect_matches(matches, &query, &source), &expected_matches);
|
||||
}
|
||||
{
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.set_containing_byte_range(78..120).matches(
|
||||
&query,
|
||||
tree.root_node(),
|
||||
source.as_bytes(),
|
||||
);
|
||||
assert_eq!(collect_matches(matches, &query, &source), &expected_matches);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_query_matches_different_queries_same_cursor() {
|
||||
allocations::record(|| {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue