Add new argument vim text object (#7791)

This PR adds a new `argument` vim text object, inspired by
[targets.vim](https://github.com/wellle/targets.vim).

As it's the first vim text object to use the syntax tree, it needed to
operate on the `Buffer` level, not the `MultiBuffer` level, then map the
buffer coordinates to `DisplayPoint` as necessary.

This required two main changes:
1. `innermost_enclosing_bracket_ranges` and `enclosing_bracket_ranges`
were moved into `Buffer`. The `MultiBuffer` implementations were updated
to map to/from these.
2. `MultiBuffer::excerpt_containing` was made public, returning a new
`MultiBufferExcerpt` type that contains a reference to the excerpt and
methods for mapping to/from `Buffer` and `MultiBuffer` offsets and
ranges.

Release Notes:
- Added new `argument` vim text object, inspired by
[targets.vim](https://github.com/wellle/targets.vim).
This commit is contained in:
vultix 2024-02-23 20:37:13 -06:00 committed by GitHub
parent dc7e14f888
commit 2e616f8388
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 392 additions and 93 deletions

View file

@ -2492,7 +2492,7 @@ impl BufferSnapshot {
self.syntax.layers_for_range(0..self.len(), &self.text)
}
fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer> {
pub fn syntax_layer_at<D: ToOffset>(&self, position: D) -> Option<SyntaxLayer> {
let offset = position.to_offset(self);
self.syntax
.layers_for_range(offset..offset, &self.text)
@ -2886,6 +2886,52 @@ impl BufferSnapshot {
})
}
/// Returns enclosing bracket ranges containing the given range
pub fn enclosing_bracket_ranges<T: ToOffset>(
&self,
range: Range<T>,
) -> impl Iterator<Item = (Range<usize>, Range<usize>)> + '_ {
let range = range.start.to_offset(self)..range.end.to_offset(self);
self.bracket_ranges(range.clone())
.filter(move |(open, close)| open.start <= range.start && close.end >= range.end)
}
/// Returns the smallest enclosing bracket ranges containing the given range or None if no brackets contain range
///
/// Can optionally pass a range_filter to filter the ranges of brackets to consider
pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
&self,
range: Range<T>,
range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
) -> Option<(Range<usize>, Range<usize>)> {
let range = range.start.to_offset(self)..range.end.to_offset(self);
// Get the ranges of the innermost pair of brackets.
let mut result: Option<(Range<usize>, Range<usize>)> = None;
for (open, close) in self.enclosing_bracket_ranges(range.clone()) {
if let Some(range_filter) = range_filter {
if !range_filter(open.clone(), close.clone()) {
continue;
}
}
let len = close.end - open.start;
if let Some((existing_open, existing_close)) = &result {
let existing_len = existing_close.end - existing_open.start;
if len > existing_len {
continue;
}
}
result = Some((open, close));
}
result
}
/// Returns anchor ranges for any matches of the redaction query.
/// The buffer can be associated with multiple languages, and the redaction query associated with each
/// will be run on the relevant section of the buffer.