@@ -16768,9 +16768,9 @@ fn indent_guide(buffer_id: BufferId, start_row: u32, end_row: u32, depth: u32) -
async fn test_indent_guide_single_line(cx: &mut TestAppContext) {
let (buffer_id, mut cx) = setup_indent_guides_editor(
&"
- fn main() {
- let a = 1;
- }"
+ fn main() {
+ let a = 1;
+ }"
.unindent(),
cx,
)
@@ -16783,10 +16783,10 @@ async fn test_indent_guide_single_line(cx: &mut TestAppContext) {
async fn test_indent_guide_simple_block(cx: &mut TestAppContext) {
let (buffer_id, mut cx) = setup_indent_guides_editor(
&"
- fn main() {
- let a = 1;
- let b = 2;
- }"
+ fn main() {
+ let a = 1;
+ let b = 2;
+ }"
.unindent(),
cx,
)
@@ -16799,14 +16799,14 @@ async fn test_indent_guide_simple_block(cx: &mut TestAppContext) {
async fn test_indent_guide_nested(cx: &mut TestAppContext) {
let (buffer_id, mut cx) = setup_indent_guides_editor(
&"
- fn main() {
- let a = 1;
- if a == 3 {
- let b = 2;
- } else {
- let c = 3;
- }
- }"
+ fn main() {
+ let a = 1;
+ if a == 3 {
+ let b = 2;
+ } else {
+ let c = 3;
+ }
+ }"
.unindent(),
cx,
)
@@ -16828,11 +16828,11 @@ async fn test_indent_guide_nested(cx: &mut TestAppContext) {
async fn test_indent_guide_tab(cx: &mut TestAppContext) {
let (buffer_id, mut cx) = setup_indent_guides_editor(
&"
- fn main() {
- let a = 1;
- let b = 2;
- let c = 3;
- }"
+ fn main() {
+ let a = 1;
+ let b = 2;
+ let c = 3;
+ }"
.unindent(),
cx,
)
@@ -16962,6 +16962,72 @@ async fn test_indent_guide_ends_off_screen(cx: &mut TestAppContext) {
);
}
+#[gpui::test]
+async fn test_indent_guide_with_folds(cx: &mut TestAppContext) {
+ let (buffer_id, mut cx) = setup_indent_guides_editor(
+ &"
+ fn main() {
+ if a {
+ b(
+ c,
+ d,
+ )
+ } else {
+ e(
+ f
+ )
+ }
+ }"
+ .unindent(),
+ cx,
+ )
+ .await;
+
+ assert_indent_guides(
+ 0..11,
+ vec![
+ indent_guide(buffer_id, 1, 10, 0),
+ indent_guide(buffer_id, 2, 5, 1),
+ indent_guide(buffer_id, 7, 9, 1),
+ indent_guide(buffer_id, 3, 4, 2),
+ indent_guide(buffer_id, 8, 8, 2),
+ ],
+ None,
+ &mut cx,
+ );
+
+ cx.update_editor(|editor, window, cx| {
+ editor.fold_at(MultiBufferRow(2), window, cx);
+ assert_eq!(
+ editor.display_text(cx),
+ "
+ fn main() {
+ if a {
+ b(⋯
+ )
+ } else {
+ e(
+ f
+ )
+ }
+ }"
+ .unindent()
+ );
+ });
+
+ assert_indent_guides(
+ 0..11,
+ vec![
+ indent_guide(buffer_id, 1, 10, 0),
+ indent_guide(buffer_id, 2, 5, 1),
+ indent_guide(buffer_id, 7, 9, 1),
+ indent_guide(buffer_id, 8, 8, 2),
+ ],
+ None,
+ &mut cx,
+ );
+}
+
#[gpui::test]
async fn test_indent_guide_without_brackets(cx: &mut TestAppContext) {
let (buffer_id, mut cx) = setup_indent_guides_editor(
@@ -1,9 +1,9 @@
-use std::{ops::Range, time::Duration};
+use std::{cmp::Ordering, ops::Range, time::Duration};
use collections::HashSet;
use gpui::{App, AppContext as _, Context, Task, Window};
use language::language_settings::language_settings;
-use multi_buffer::{IndentGuide, MultiBufferRow};
+use multi_buffer::{IndentGuide, MultiBufferRow, ToPoint};
use text::{LineIndent, Point};
use util::ResultExt;
@@ -154,12 +154,28 @@ pub fn indent_guides_in_range(
snapshot: &DisplaySnapshot,
cx: &App,
) -> Vec<IndentGuide> {
- let start_anchor = snapshot
+ let start_offset = snapshot
.buffer_snapshot
- .anchor_before(Point::new(visible_buffer_range.start.0, 0));
- let end_anchor = snapshot
+ .point_to_offset(Point::new(visible_buffer_range.start.0, 0));
+ let end_offset = snapshot
.buffer_snapshot
- .anchor_after(Point::new(visible_buffer_range.end.0, 0));
+ .point_to_offset(Point::new(visible_buffer_range.end.0, 0));
+ let start_anchor = snapshot.buffer_snapshot.anchor_before(start_offset);
+ let end_anchor = snapshot.buffer_snapshot.anchor_after(end_offset);
+
+ let mut fold_ranges = Vec::<Range<Point>>::new();
+ let mut folds = snapshot.folds_in_range(start_offset..end_offset).peekable();
+ while let Some(fold) = folds.next() {
+ let start = fold.range.start.to_point(&snapshot.buffer_snapshot);
+ let end = fold.range.end.to_point(&snapshot.buffer_snapshot);
+ if let Some(last_range) = fold_ranges.last_mut() {
+ if last_range.end >= start {
+ last_range.end = last_range.end.max(end);
+ continue;
+ }
+ }
+ fold_ranges.push(start..end);
+ }
snapshot
.buffer_snapshot
@@ -169,15 +185,19 @@ pub fn indent_guides_in_range(
return false;
}
- let start = MultiBufferRow(indent_guide.start_row.0.saturating_sub(1));
- // Filter out indent guides that are inside a fold
- // All indent guides that are starting "offscreen" have a start value of the first visible row minus one
- // Therefore checking if a line is folded at first visible row minus one causes the other indent guides that are not related to the fold to disappear as well
- let is_folded = snapshot.is_line_folded(start);
- let line_indent = snapshot.line_indent_for_buffer_row(start);
- let contained_in_fold =
- line_indent.len(indent_guide.tab_size) <= indent_guide.indent_level();
- !(is_folded && contained_in_fold)
+ let has_containing_fold = fold_ranges
+ .binary_search_by(|fold_range| {
+ if fold_range.start >= Point::new(indent_guide.start_row.0, 0) {
+ Ordering::Greater
+ } else if fold_range.end < Point::new(indent_guide.end_row.0, 0) {
+ Ordering::Less
+ } else {
+ Ordering::Equal
+ }
+ })
+ .is_ok();
+
+ !has_containing_fold
})
.collect()
}
@@ -5753,15 +5753,28 @@ impl MultiBufferSnapshot {
let mut result = Vec::new();
let mut indent_stack = SmallVec::<[IndentGuide; 8]>::new();
+ let mut prev_settings = None;
while let Some((first_row, mut line_indent, buffer)) = row_indents.next() {
if first_row > end_row {
break;
}
let current_depth = indent_stack.len() as u32;
- let settings =
- language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx);
- let tab_size = settings.tab_size.get() as u32;
+ // Avoid retrieving the language settings repeatedly for every buffer row.
+ if let Some((prev_buffer_id, _)) = &prev_settings {
+ if prev_buffer_id != &buffer.remote_id() {
+ prev_settings.take();
+ }
+ }
+ let settings = &prev_settings
+ .get_or_insert_with(|| {
+ (
+ buffer.remote_id(),
+ language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx),
+ )
+ })
+ .1;
+ let tab_size = settings.tab_size.get();
// When encountering empty, continue until found useful line indent
// then add to the indent stack with the depth found