@@ -124,7 +124,6 @@ fn cover_or_next<I: Iterator<Item = (Range<usize>, Range<usize>)>>(
candidates: Option<I>,
caret: DisplayPoint,
map: &DisplaySnapshot,
- range_filter: Option<&dyn Fn(Range<usize>, Range<usize>) -> bool>,
) -> Option<CandidateWithRanges> {
let caret_offset = caret.to_offset(map, Bias::Left);
let mut covering = vec![];
@@ -135,11 +134,6 @@ fn cover_or_next<I: Iterator<Item = (Range<usize>, Range<usize>)>>(
for (open_range, close_range) in ranges {
let start_off = open_range.start;
let end_off = close_range.end;
- if let Some(range_filter) = range_filter
- && !range_filter(open_range.clone(), close_range.clone())
- {
- continue;
- }
let candidate = CandidateWithRanges {
candidate: CandidateRange {
start: start_off.to_display_point(map),
@@ -214,16 +208,35 @@ fn find_mini_delimiters(
let visible_line_range = get_visible_line_range(&line_range);
let snapshot = &map.buffer_snapshot();
- let excerpt = snapshot.excerpt_containing(offset..offset)?;
+ let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
let buffer = excerpt.buffer();
+ let buffer_offset = excerpt.map_offset_to_buffer(offset);
let bracket_filter = |open: Range<usize>, close: Range<usize>| {
is_valid_delimiter(buffer, open.start, close.start)
};
// Try to find delimiters in visible range first
- let ranges = map.buffer_snapshot().bracket_ranges(visible_line_range);
- if let Some(candidate) = cover_or_next(ranges, display_point, map, Some(&bracket_filter)) {
+ let ranges = map
+ .buffer_snapshot()
+ .bracket_ranges(visible_line_range)
+ .map(|ranges| {
+ ranges.filter_map(move |(open, close)| {
+ // Convert the ranges from multibuffer space to buffer space as
+ // that is what `is_valid_delimiter` expects, otherwise it might
+ // panic as the values might be out of bounds.
+ let buffer_open = excerpt.map_range_to_buffer(open.clone());
+ let buffer_close = excerpt.map_range_to_buffer(close.clone());
+
+ if is_valid_delimiter(buffer, buffer_open.start, buffer_close.start) {
+ Some((open, close))
+ } else {
+ None
+ }
+ })
+ });
+
+ if let Some(candidate) = cover_or_next(ranges, display_point, map) {
return Some(
DelimiterRange {
open: candidate.open_range,
@@ -234,8 +247,8 @@ fn find_mini_delimiters(
}
// Fall back to innermost enclosing brackets
- let (open_bracket, close_bracket) =
- buffer.innermost_enclosing_bracket_ranges(offset..offset, Some(&bracket_filter))?;
+ let (open_bracket, close_bracket) = buffer
+ .innermost_enclosing_bracket_ranges(buffer_offset..buffer_offset, Some(&bracket_filter))?;
Some(
DelimiterRange {
@@ -1736,8 +1749,10 @@ pub fn surrounding_markers(
#[cfg(test)]
mod test {
+ use editor::{Editor, EditorMode, MultiBuffer, test::editor_test_context::EditorTestContext};
use gpui::KeyBinding;
use indoc::indoc;
+ use text::Point;
use crate::{
object::{AnyBrackets, AnyQuotes, MiniBrackets},
@@ -3185,6 +3200,78 @@ mod test {
}
}
+ #[gpui::test]
+ async fn test_minibrackets_multibuffer(cx: &mut gpui::TestAppContext) {
+ // Initialize test context with the TypeScript language loaded, so we
+ // can actually get brackets definition.
+ let mut cx = VimTestContext::new(cx, true).await;
+
+ // Update `b` to `MiniBrackets` so we can later use it when simulating
+ // keystrokes.
+ cx.update(|_, cx| {
+ cx.bind_keys([KeyBinding::new("b", MiniBrackets, None)]);
+ });
+
+ let (editor, cx) = cx.add_window_view(|window, cx| {
+ let multi_buffer = MultiBuffer::build_multi(
+ [
+ ("111\n222\n333\n444\n", vec![Point::row_range(0..2)]),
+ ("111\na {bracket} example\n", vec![Point::row_range(0..2)]),
+ ],
+ cx,
+ );
+
+ // In order for the brackets to actually be found, we need to update
+ // the language used for the second buffer. This is something that
+ // is handled automatically when simply using `VimTestContext::new`
+ // but, since this is being set manually, the language isn't
+ // automatically set.
+ let editor = Editor::new(EditorMode::full(), multi_buffer.clone(), None, window, cx);
+ let buffer_ids = multi_buffer.read(cx).excerpt_buffer_ids();
+ if let Some(buffer) = multi_buffer.read(cx).buffer(buffer_ids[1]) {
+ buffer.update(cx, |buffer, cx| {
+ buffer.set_language(Some(language::rust_lang()), cx);
+ })
+ };
+
+ editor
+ });
+
+ let mut cx = EditorTestContext::for_editor_in(editor.clone(), cx).await;
+
+ cx.assert_excerpts_with_selections(indoc! {"
+ [EXCERPT]
+ ˇ111
+ 222
+ [EXCERPT]
+ 111
+ a {bracket} example
+ "
+ });
+
+ cx.simulate_keystrokes("j j j j f r");
+ cx.assert_excerpts_with_selections(indoc! {"
+ [EXCERPT]
+ 111
+ 222
+ [EXCERPT]
+ 111
+ a {bˇracket} example
+ "
+ });
+
+ cx.simulate_keystrokes("d i b");
+ cx.assert_excerpts_with_selections(indoc! {"
+ [EXCERPT]
+ 111
+ 222
+ [EXCERPT]
+ 111
+ a {ˇ} example
+ "
+ });
+ }
+
#[gpui::test]
async fn test_minibrackets_trailing_space(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await;