use more predictable rules for selecting which bracket to jump to and where
This commit is contained in:
parent
5041300b52
commit
0ba051a754
15 changed files with 457 additions and 217 deletions
|
@ -2621,56 +2621,71 @@ impl MultiBufferSnapshot {
|
|||
self.parse_count
|
||||
}
|
||||
|
||||
pub fn enclosing_bracket_ranges<T: ToOffset>(
|
||||
pub fn innermost_enclosing_bracket_ranges<T: ToOffset>(
|
||||
&self,
|
||||
range: Range<T>,
|
||||
) -> Option<(Range<usize>, Range<usize>)> {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
|
||||
let mut cursor = self.excerpts.cursor::<usize>();
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
let start_excerpt = cursor.item();
|
||||
// Get the ranges of the innermost pair of brackets.
|
||||
let mut result: Option<(Range<usize>, Range<usize>)> = None;
|
||||
|
||||
cursor.seek(&range.end, Bias::Right, &());
|
||||
let end_excerpt = cursor.item();
|
||||
let Some(enclosing_bracket_ranges) = self.enclosing_bracket_ranges(range.clone()) else { return None; };
|
||||
|
||||
start_excerpt
|
||||
.zip(end_excerpt)
|
||||
.and_then(|(start_excerpt, end_excerpt)| {
|
||||
if start_excerpt.id != end_excerpt.id {
|
||||
return None;
|
||||
for (open, close) in enclosing_bracket_ranges {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
let excerpt_buffer_start = start_excerpt
|
||||
.range
|
||||
.context
|
||||
.start
|
||||
.to_offset(&start_excerpt.buffer);
|
||||
let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.len;
|
||||
result = Some((open, close));
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns enclosingn bracket ranges containing the given range or returns None if the range is not contained in a single excerpt
|
||||
pub fn enclosing_bracket_ranges<'a, T: ToOffset>(
|
||||
&'a self,
|
||||
range: Range<T>,
|
||||
) -> Option<impl Iterator<Item = (Range<usize>, Range<usize>)> + 'a> {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
self.excerpt_containing(range.clone())
|
||||
.map(|(excerpt, excerpt_offset)| {
|
||||
let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
|
||||
let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
|
||||
|
||||
let start_in_buffer =
|
||||
excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
|
||||
let end_in_buffer =
|
||||
excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
|
||||
let (mut start_bracket_range, mut end_bracket_range) = start_excerpt
|
||||
.buffer
|
||||
.enclosing_bracket_ranges(start_in_buffer..end_in_buffer)?;
|
||||
excerpt_buffer_start + range.start.saturating_sub(excerpt_offset);
|
||||
let end_in_buffer = excerpt_buffer_start + range.end.saturating_sub(excerpt_offset);
|
||||
|
||||
if start_bracket_range.start >= excerpt_buffer_start
|
||||
&& end_bracket_range.end <= excerpt_buffer_end
|
||||
{
|
||||
start_bracket_range.start =
|
||||
cursor.start() + (start_bracket_range.start - excerpt_buffer_start);
|
||||
start_bracket_range.end =
|
||||
cursor.start() + (start_bracket_range.end - excerpt_buffer_start);
|
||||
end_bracket_range.start =
|
||||
cursor.start() + (end_bracket_range.start - excerpt_buffer_start);
|
||||
end_bracket_range.end =
|
||||
cursor.start() + (end_bracket_range.end - excerpt_buffer_start);
|
||||
Some((start_bracket_range, end_bracket_range))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
excerpt
|
||||
.buffer
|
||||
.enclosing_bracket_ranges(start_in_buffer..end_in_buffer)
|
||||
.filter_map(move |(start_bracket_range, end_bracket_range)| {
|
||||
if start_bracket_range.start < excerpt_buffer_start
|
||||
|| end_bracket_range.end > excerpt_buffer_end
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut start_bracket_range = start_bracket_range.clone();
|
||||
start_bracket_range.start =
|
||||
excerpt_offset + (start_bracket_range.start - excerpt_buffer_start);
|
||||
start_bracket_range.end =
|
||||
excerpt_offset + (start_bracket_range.end - excerpt_buffer_start);
|
||||
|
||||
let mut end_bracket_range = end_bracket_range.clone();
|
||||
end_bracket_range.start =
|
||||
excerpt_offset + (end_bracket_range.start - excerpt_buffer_start);
|
||||
end_bracket_range.end =
|
||||
excerpt_offset + (end_bracket_range.end - excerpt_buffer_start);
|
||||
Some((start_bracket_range, end_bracket_range))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2812,40 +2827,23 @@ impl MultiBufferSnapshot {
|
|||
pub fn range_for_syntax_ancestor<T: ToOffset>(&self, range: Range<T>) -> Option<Range<usize>> {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
|
||||
let mut cursor = self.excerpts.cursor::<usize>();
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
let start_excerpt = cursor.item();
|
||||
|
||||
cursor.seek(&range.end, Bias::Right, &());
|
||||
let end_excerpt = cursor.item();
|
||||
|
||||
start_excerpt
|
||||
.zip(end_excerpt)
|
||||
.and_then(|(start_excerpt, end_excerpt)| {
|
||||
if start_excerpt.id != end_excerpt.id {
|
||||
return None;
|
||||
}
|
||||
|
||||
let excerpt_buffer_start = start_excerpt
|
||||
.range
|
||||
.context
|
||||
.start
|
||||
.to_offset(&start_excerpt.buffer);
|
||||
let excerpt_buffer_end = excerpt_buffer_start + start_excerpt.text_summary.len;
|
||||
self.excerpt_containing(range.clone())
|
||||
.and_then(|(excerpt, excerpt_offset)| {
|
||||
let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer);
|
||||
let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len;
|
||||
|
||||
let start_in_buffer =
|
||||
excerpt_buffer_start + range.start.saturating_sub(*cursor.start());
|
||||
let end_in_buffer =
|
||||
excerpt_buffer_start + range.end.saturating_sub(*cursor.start());
|
||||
let mut ancestor_buffer_range = start_excerpt
|
||||
excerpt_buffer_start + range.start.saturating_sub(excerpt_offset);
|
||||
let end_in_buffer = excerpt_buffer_start + range.end.saturating_sub(excerpt_offset);
|
||||
let mut ancestor_buffer_range = excerpt
|
||||
.buffer
|
||||
.range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?;
|
||||
ancestor_buffer_range.start =
|
||||
cmp::max(ancestor_buffer_range.start, excerpt_buffer_start);
|
||||
ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end);
|
||||
|
||||
let start = cursor.start() + (ancestor_buffer_range.start - excerpt_buffer_start);
|
||||
let end = cursor.start() + (ancestor_buffer_range.end - excerpt_buffer_start);
|
||||
let start = excerpt_offset + (ancestor_buffer_range.start - excerpt_buffer_start);
|
||||
let end = excerpt_offset + (ancestor_buffer_range.end - excerpt_buffer_start);
|
||||
Some(start..end)
|
||||
})
|
||||
}
|
||||
|
@ -2929,6 +2927,31 @@ impl MultiBufferSnapshot {
|
|||
None
|
||||
}
|
||||
|
||||
/// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts
|
||||
fn excerpt_containing<'a, T: ToOffset>(
|
||||
&'a self,
|
||||
range: Range<T>,
|
||||
) -> Option<(&'a Excerpt, usize)> {
|
||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||
|
||||
let mut cursor = self.excerpts.cursor::<usize>();
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
let start_excerpt = cursor.item();
|
||||
|
||||
cursor.seek(&range.end, Bias::Right, &());
|
||||
let end_excerpt = cursor.item();
|
||||
|
||||
start_excerpt
|
||||
.zip(end_excerpt)
|
||||
.and_then(|(start_excerpt, end_excerpt)| {
|
||||
if start_excerpt.id != end_excerpt.id {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((start_excerpt, *cursor.start()))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn remote_selections_in_range<'a>(
|
||||
&'a self,
|
||||
range: &'a Range<Anchor>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue