editor: Fix panic when editor::SelectLargerSyntaxNode
overflows excerpt in multi buffer (#25585)
Closes #25513 This PR handles case when `editor::SelectLargerSyntaxNode` expands across excerpt boundaries and eventually crashes in multi buffer. Release Notes: - Fixed panic caused when `editor::SelectLargerSyntaxNode` is called repetedly in multi buffer. Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
This commit is contained in:
parent
014d9dfce1
commit
0559e1f348
@ -132,7 +132,7 @@ pub use multi_buffer::{
|
|||||||
};
|
};
|
||||||
use multi_buffer::{
|
use multi_buffer::{
|
||||||
ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
|
ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
|
||||||
ToOffsetUtf16,
|
MultiOrSingleBufferOffsetRange, ToOffsetUtf16,
|
||||||
};
|
};
|
||||||
use project::{
|
use project::{
|
||||||
lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
|
lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
|
||||||
@ -10738,7 +10738,10 @@ impl Editor {
|
|||||||
while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
|
while let Some((node, containing_range)) = buffer.syntax_ancestor(new_range.clone())
|
||||||
{
|
{
|
||||||
new_node = Some(node);
|
new_node = Some(node);
|
||||||
new_range = containing_range;
|
new_range = match containing_range {
|
||||||
|
MultiOrSingleBufferOffsetRange::Single(_) => break,
|
||||||
|
MultiOrSingleBufferOffsetRange::Multi(range) => range,
|
||||||
|
};
|
||||||
if !display_map.intersects_fold(new_range.start)
|
if !display_map.intersects_fold(new_range.start)
|
||||||
&& !display_map.intersects_fold(new_range.end)
|
&& !display_map.intersects_fold(new_range.end)
|
||||||
{
|
{
|
||||||
|
@ -15,7 +15,7 @@ use itertools::Itertools;
|
|||||||
use language::{DiagnosticEntry, Language, LanguageRegistry};
|
use language::{DiagnosticEntry, Language, LanguageRegistry};
|
||||||
use lsp::DiagnosticSeverity;
|
use lsp::DiagnosticSeverity;
|
||||||
use markdown::{Markdown, MarkdownStyle};
|
use markdown::{Markdown, MarkdownStyle};
|
||||||
use multi_buffer::ToOffset;
|
use multi_buffer::{MultiOrSingleBufferOffsetRange, ToOffset};
|
||||||
use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart};
|
use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{borrow::Cow, cell::RefCell};
|
use std::{borrow::Cow, cell::RefCell};
|
||||||
@ -447,11 +447,13 @@ fn show_hover(
|
|||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
let snapshot = &snapshot.buffer_snapshot;
|
let snapshot = &snapshot.buffer_snapshot;
|
||||||
let offset_range = snapshot.syntax_ancestor(anchor..anchor)?.1;
|
match snapshot.syntax_ancestor(anchor..anchor)?.1 {
|
||||||
Some(
|
MultiOrSingleBufferOffsetRange::Multi(range) => Some(
|
||||||
snapshot.anchor_before(offset_range.start)
|
snapshot.anchor_before(range.start)
|
||||||
..snapshot.anchor_after(offset_range.end),
|
..snapshot.anchor_after(range.end),
|
||||||
)
|
),
|
||||||
|
MultiOrSingleBufferOffsetRange::Single(_) => None,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| anchor..anchor);
|
.unwrap_or_else(|| anchor..anchor);
|
||||||
|
|
||||||
|
@ -78,6 +78,12 @@ pub struct MultiBuffer {
|
|||||||
capability: Capability,
|
capability: Capability,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum MultiOrSingleBufferOffsetRange {
|
||||||
|
Single(Range<usize>),
|
||||||
|
Multi(Range<usize>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
ExcerptsAdded {
|
ExcerptsAdded {
|
||||||
@ -5682,13 +5688,19 @@ impl MultiBufferSnapshot {
|
|||||||
pub fn syntax_ancestor<T: ToOffset>(
|
pub fn syntax_ancestor<T: ToOffset>(
|
||||||
&self,
|
&self,
|
||||||
range: Range<T>,
|
range: Range<T>,
|
||||||
) -> Option<(tree_sitter::Node, Range<usize>)> {
|
) -> Option<(tree_sitter::Node, MultiOrSingleBufferOffsetRange)> {
|
||||||
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
let range = range.start.to_offset(self)..range.end.to_offset(self);
|
||||||
let mut excerpt = self.excerpt_containing(range.clone())?;
|
let mut excerpt = self.excerpt_containing(range.clone())?;
|
||||||
let node = excerpt
|
let node = excerpt
|
||||||
.buffer()
|
.buffer()
|
||||||
.syntax_ancestor(excerpt.map_range_to_buffer(range))?;
|
.syntax_ancestor(excerpt.map_range_to_buffer(range))?;
|
||||||
Some((node, excerpt.map_range_from_buffer(node.byte_range())))
|
let node_range = node.byte_range();
|
||||||
|
let range = if excerpt.contains_buffer_range(node_range.clone()) {
|
||||||
|
MultiOrSingleBufferOffsetRange::Multi(excerpt.map_range_from_buffer(node_range))
|
||||||
|
} else {
|
||||||
|
MultiOrSingleBufferOffsetRange::Single(node_range)
|
||||||
|
};
|
||||||
|
Some((node, range))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
|
pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option<Outline<Anchor>> {
|
||||||
@ -6660,9 +6672,17 @@ impl<'a> MultiBufferExcerpt<'a> {
|
|||||||
|
|
||||||
/// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
|
/// Map a range within the [`Buffer`] to a range within the [`MultiBuffer`]
|
||||||
pub fn map_range_from_buffer(&mut self, buffer_range: Range<usize>) -> Range<usize> {
|
pub fn map_range_from_buffer(&mut self, buffer_range: Range<usize>) -> Range<usize> {
|
||||||
|
if buffer_range.start < self.buffer_offset {
|
||||||
|
log::warn!("Attempting to map a range from a buffer offset that starts before the current buffer offset");
|
||||||
|
return buffer_range;
|
||||||
|
}
|
||||||
let overshoot = buffer_range.start - self.buffer_offset;
|
let overshoot = buffer_range.start - self.buffer_offset;
|
||||||
let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
|
let excerpt_offset = ExcerptDimension(self.excerpt_offset.0 + overshoot);
|
||||||
self.diff_transforms.seek(&excerpt_offset, Bias::Right, &());
|
self.diff_transforms.seek(&excerpt_offset, Bias::Right, &());
|
||||||
|
if excerpt_offset.0 < self.diff_transforms.start().1 .0 {
|
||||||
|
log::warn!("Attempting to map a range from a buffer offset that starts before the current buffer offset");
|
||||||
|
return buffer_range;
|
||||||
|
}
|
||||||
let overshoot = excerpt_offset.0 - self.diff_transforms.start().1 .0;
|
let overshoot = excerpt_offset.0 - self.diff_transforms.start().1 .0;
|
||||||
let start = self.diff_transforms.start().0 .0 + overshoot;
|
let start = self.diff_transforms.start().0 .0 + overshoot;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user