From 836dd012b7c238e5cca4db3664f9ccfc672c479f Mon Sep 17 00:00:00 2001
From: "gcp-cherry-pick-bot[bot]"
<98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com>
Date: Mon, 3 Jun 2024 09:29:01 +0200
Subject: [PATCH] indent guides: Respect language specific settings in
multibuffers (cherry-pick #12528) (#12594)
Cherry-picked indent guides: Respect language specific settings in
multibuffers (#12528)
Indent guides can be configured per language, meaning that in a multi
buffer we can get excerpts where indent guides should be
disabled/enabled/styled differently than other excerpts.
Imagine the following scenario, i have indent guides disabled in my
settings, but want to enable them for JS and Python. I also want to use
a different line width for python files. Something like this is now
supported:
And the relevant settings for the example above:
```json
"indent_guides": {
"enabled": false
},
"languages": {
"JavaScript": {
"indent_guides": {
"enabled": true
}
},
"Python": {
"indent_guides": {
"enabled": true,
"line_width": 5
}
}
}
```
Release Notes:
- Respect language specific settings when showing indent guides in a
multibuffer
- Fixes an issue where indent guide specific settings were not
recognized when specified in local settings
Co-authored-by: Bennet Bo Fenner
---
crates/editor/src/editor.rs | 16 ++--
crates/editor/src/editor_tests.rs | 105 ++++++++++++------------
crates/editor/src/element.rs | 17 ++--
crates/editor/src/indent_guides.rs | 35 ++++++--
crates/language/src/buffer.rs | 28 +++----
crates/multi_buffer/src/multi_buffer.rs | 13 ++-
6 files changed, 113 insertions(+), 101 deletions(-)
diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs
index 67f0d0908ad65e5300b265939e191a7dd28da875..347ea8e88b3ef8d5fe729ee1897654c8c64a46e2 100644
--- a/crates/editor/src/editor.rs
+++ b/crates/editor/src/editor.rs
@@ -9770,19 +9770,19 @@ impl Editor {
}
pub fn toggle_indent_guides(&mut self, _: &ToggleIndentGuides, cx: &mut ViewContext) {
- let currently_enabled = self.should_show_indent_guides(cx);
- self.show_indent_guides = Some(!currently_enabled);
- cx.notify();
- }
-
- fn should_show_indent_guides(&self, cx: &mut ViewContext) -> bool {
- self.show_indent_guides.unwrap_or_else(|| {
+ let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
self.buffer
.read(cx)
.settings_at(0, cx)
.indent_guides
.enabled
- })
+ });
+ self.show_indent_guides = Some(!currently_enabled);
+ cx.notify();
+ }
+
+ fn should_show_indent_guides(&self) -> Option {
+ self.show_indent_guides
}
pub fn toggle_line_numbers(&mut self, _: &ToggleLineNumbers, cx: &mut ViewContext) {
diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs
index de1eb6bebb2913e01e92760306d1bc982c273954..1463af3514df374df4a6e5a503661a8120de4d3d 100644
--- a/crates/editor/src/editor_tests.rs
+++ b/crates/editor/src/editor_tests.rs
@@ -20,6 +20,7 @@ use language::{
FakeLspAdapter, IndentGuide, LanguageConfig, LanguageConfigOverride, LanguageMatcher, Override,
Point,
};
+use language_settings::IndentGuideSettings;
use multi_buffer::MultiBufferIndentGuide;
use parking_lot::Mutex;
use project::project_settings::{LspSettings, ProjectSettings};
@@ -11505,6 +11506,7 @@ fn assert_indent_guides(
let snapshot = editor.snapshot(cx).display_snapshot;
let mut indent_guides: Vec<_> = crate::indent_guides::indent_guides_in_range(
MultiBufferRow(range.start)..MultiBufferRow(range.end),
+ true,
&snapshot,
cx,
);
@@ -11543,6 +11545,21 @@ fn assert_indent_guides(
assert_eq!(indent_guides, expected, "Indent guides do not match");
}
+fn indent_guide(buffer_id: BufferId, start_row: u32, end_row: u32, depth: u32) -> IndentGuide {
+ IndentGuide {
+ buffer_id,
+ start_row,
+ end_row,
+ depth,
+ tab_size: 4,
+ settings: IndentGuideSettings {
+ enabled: true,
+ line_width: 1,
+ ..Default::default()
+ },
+ }
+}
+
#[gpui::test]
async fn test_indent_guide_single_line(cx: &mut gpui::TestAppContext) {
let (buffer_id, mut cx) = setup_indent_guides_editor(
@@ -11555,12 +11572,7 @@ async fn test_indent_guide_single_line(cx: &mut gpui::TestAppContext) {
)
.await;
- assert_indent_guides(
- 0..3,
- vec![IndentGuide::new(buffer_id, 1, 1, 0, 4)],
- None,
- &mut cx,
- );
+ assert_indent_guides(0..3, vec![indent_guide(buffer_id, 1, 1, 0)], None, &mut cx);
}
#[gpui::test]
@@ -11576,12 +11588,7 @@ async fn test_indent_guide_simple_block(cx: &mut gpui::TestAppContext) {
)
.await;
- assert_indent_guides(
- 0..4,
- vec![IndentGuide::new(buffer_id, 1, 2, 0, 4)],
- None,
- &mut cx,
- );
+ assert_indent_guides(0..4, vec![indent_guide(buffer_id, 1, 2, 0)], None, &mut cx);
}
#[gpui::test]
@@ -11604,9 +11611,9 @@ async fn test_indent_guide_nested(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
0..8,
vec![
- IndentGuide::new(buffer_id, 1, 6, 0, 4),
- IndentGuide::new(buffer_id, 3, 3, 1, 4),
- IndentGuide::new(buffer_id, 5, 5, 1, 4),
+ indent_guide(buffer_id, 1, 6, 0),
+ indent_guide(buffer_id, 3, 3, 1),
+ indent_guide(buffer_id, 5, 5, 1),
],
None,
&mut cx,
@@ -11630,8 +11637,8 @@ async fn test_indent_guide_tab(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
0..5,
vec![
- IndentGuide::new(buffer_id, 1, 3, 0, 4),
- IndentGuide::new(buffer_id, 2, 2, 1, 4),
+ indent_guide(buffer_id, 1, 3, 0),
+ indent_guide(buffer_id, 2, 2, 1),
],
None,
&mut cx,
@@ -11652,12 +11659,7 @@ async fn test_indent_guide_continues_on_empty_line(cx: &mut gpui::TestAppContext
)
.await;
- assert_indent_guides(
- 0..5,
- vec![IndentGuide::new(buffer_id, 1, 3, 0, 4)],
- None,
- &mut cx,
- );
+ assert_indent_guides(0..5, vec![indent_guide(buffer_id, 1, 3, 0)], None, &mut cx);
}
#[gpui::test]
@@ -11683,9 +11685,9 @@ async fn test_indent_guide_complex(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
0..11,
vec![
- IndentGuide::new(buffer_id, 1, 9, 0, 4),
- IndentGuide::new(buffer_id, 6, 6, 1, 4),
- IndentGuide::new(buffer_id, 8, 8, 1, 4),
+ indent_guide(buffer_id, 1, 9, 0),
+ indent_guide(buffer_id, 6, 6, 1),
+ indent_guide(buffer_id, 8, 8, 1),
],
None,
&mut cx,
@@ -11715,9 +11717,9 @@ async fn test_indent_guide_starts_off_screen(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
1..11,
vec![
- IndentGuide::new(buffer_id, 1, 9, 0, 4),
- IndentGuide::new(buffer_id, 6, 6, 1, 4),
- IndentGuide::new(buffer_id, 8, 8, 1, 4),
+ indent_guide(buffer_id, 1, 9, 0),
+ indent_guide(buffer_id, 6, 6, 1),
+ indent_guide(buffer_id, 8, 8, 1),
],
None,
&mut cx,
@@ -11747,9 +11749,9 @@ async fn test_indent_guide_ends_off_screen(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
1..10,
vec![
- IndentGuide::new(buffer_id, 1, 9, 0, 4),
- IndentGuide::new(buffer_id, 6, 6, 1, 4),
- IndentGuide::new(buffer_id, 8, 8, 1, 4),
+ indent_guide(buffer_id, 1, 9, 0),
+ indent_guide(buffer_id, 6, 6, 1),
+ indent_guide(buffer_id, 8, 8, 1),
],
None,
&mut cx,
@@ -11775,9 +11777,9 @@ async fn test_indent_guide_without_brackets(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
1..10,
vec![
- IndentGuide::new(buffer_id, 1, 4, 0, 4),
- IndentGuide::new(buffer_id, 2, 3, 1, 4),
- IndentGuide::new(buffer_id, 3, 3, 2, 4),
+ indent_guide(buffer_id, 1, 4, 0),
+ indent_guide(buffer_id, 2, 3, 1),
+ indent_guide(buffer_id, 3, 3, 2),
],
None,
&mut cx,
@@ -11802,8 +11804,8 @@ async fn test_indent_guide_ends_before_empty_line(cx: &mut gpui::TestAppContext)
assert_indent_guides(
0..6,
vec![
- IndentGuide::new(buffer_id, 1, 2, 0, 4),
- IndentGuide::new(buffer_id, 2, 2, 1, 4),
+ indent_guide(buffer_id, 1, 2, 0),
+ indent_guide(buffer_id, 2, 2, 1),
],
None,
&mut cx,
@@ -11825,12 +11827,7 @@ async fn test_indent_guide_continuing_off_screen(cx: &mut gpui::TestAppContext)
)
.await;
- assert_indent_guides(
- 0..1,
- vec![IndentGuide::new(buffer_id, 1, 1, 0, 4)],
- None,
- &mut cx,
- );
+ assert_indent_guides(0..1, vec![indent_guide(buffer_id, 1, 1, 0)], None, &mut cx);
}
#[gpui::test]
@@ -11852,8 +11849,8 @@ async fn test_indent_guide_tabs(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
0..6,
vec![
- IndentGuide::new(buffer_id, 1, 6, 0, 4),
- IndentGuide::new(buffer_id, 3, 4, 1, 4),
+ indent_guide(buffer_id, 1, 6, 0),
+ indent_guide(buffer_id, 3, 4, 1),
],
None,
&mut cx,
@@ -11880,7 +11877,7 @@ async fn test_active_indent_guide_single_line(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
0..3,
- vec![IndentGuide::new(buffer_id, 1, 1, 0, 4)],
+ vec![indent_guide(buffer_id, 1, 1, 0)],
Some(vec![0]),
&mut cx,
);
@@ -11909,8 +11906,8 @@ async fn test_active_indent_guide_respect_indented_range(cx: &mut gpui::TestAppC
assert_indent_guides(
0..4,
vec![
- IndentGuide::new(buffer_id, 1, 3, 0, 4),
- IndentGuide::new(buffer_id, 2, 2, 1, 4),
+ indent_guide(buffer_id, 1, 3, 0),
+ indent_guide(buffer_id, 2, 2, 1),
],
Some(vec![1]),
&mut cx,
@@ -11925,8 +11922,8 @@ async fn test_active_indent_guide_respect_indented_range(cx: &mut gpui::TestAppC
assert_indent_guides(
0..4,
vec![
- IndentGuide::new(buffer_id, 1, 3, 0, 4),
- IndentGuide::new(buffer_id, 2, 2, 1, 4),
+ indent_guide(buffer_id, 1, 3, 0),
+ indent_guide(buffer_id, 2, 2, 1),
],
Some(vec![1]),
&mut cx,
@@ -11941,8 +11938,8 @@ async fn test_active_indent_guide_respect_indented_range(cx: &mut gpui::TestAppC
assert_indent_guides(
0..4,
vec![
- IndentGuide::new(buffer_id, 1, 3, 0, 4),
- IndentGuide::new(buffer_id, 2, 2, 1, 4),
+ indent_guide(buffer_id, 1, 3, 0),
+ indent_guide(buffer_id, 2, 2, 1),
],
Some(vec![0]),
&mut cx,
@@ -11971,7 +11968,7 @@ async fn test_active_indent_guide_empty_line(cx: &mut gpui::TestAppContext) {
assert_indent_guides(
0..5,
- vec![IndentGuide::new(buffer_id, 1, 3, 0, 4)],
+ vec![indent_guide(buffer_id, 1, 3, 0)],
Some(vec![0]),
&mut cx,
);
@@ -11997,7 +11994,7 @@ async fn test_active_indent_guide_non_matching_indent(cx: &mut gpui::TestAppCont
assert_indent_guides(
0..3,
- vec![IndentGuide::new(buffer_id, 1, 2, 0, 4)],
+ vec![indent_guide(buffer_id, 1, 2, 0)],
Some(vec![0]),
&mut cx,
);
diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs
index eb4cb978c817da081c1976b335dc25fb1c5fc75f..280be0252304b2c0c38776362f5688162b56e17d 100644
--- a/crates/editor/src/element.rs
+++ b/crates/editor/src/element.rs
@@ -38,7 +38,7 @@ use gpui::{
};
use itertools::Itertools;
use language::language_settings::{
- IndentGuideBackgroundColoring, IndentGuideColoring, ShowWhitespaceSetting,
+ IndentGuideBackgroundColoring, IndentGuideColoring, IndentGuideSettings, ShowWhitespaceSetting,
};
use lsp::DiagnosticSeverity;
use multi_buffer::{Anchor, MultiBufferPoint, MultiBufferRow};
@@ -1438,6 +1438,7 @@ impl EditorElement {
single_indent_width,
depth: indent_guide.depth,
active: active_indent_guide_indices.contains(&i),
+ settings: indent_guide.settings,
})
} else {
None
@@ -2730,14 +2731,6 @@ impl EditorElement {
return;
};
- let settings = self
- .editor
- .read(cx)
- .buffer()
- .read(cx)
- .settings_at(0, cx)
- .indent_guides;
-
let faded_color = |color: Hsla, alpha: f32| {
let mut faded = color;
faded.a = alpha;
@@ -2746,6 +2739,7 @@ impl EditorElement {
for indent_guide in indent_guides {
let indent_accent_colors = cx.theme().accents().color_for_index(indent_guide.depth);
+ let settings = indent_guide.settings;
// TODO fixed for now, expose them through themes later
const INDENT_AWARE_ALPHA: f32 = 0.2;
@@ -2753,7 +2747,7 @@ impl EditorElement {
const INDENT_AWARE_BACKGROUND_ALPHA: f32 = 0.1;
const INDENT_AWARE_BACKGROUND_ACTIVE_ALPHA: f32 = 0.2;
- let line_color = match (&settings.coloring, indent_guide.active) {
+ let line_color = match (settings.coloring, indent_guide.active) {
(IndentGuideColoring::Disabled, _) => None,
(IndentGuideColoring::Fixed, false) => {
Some(cx.theme().colors().editor_indent_guide)
@@ -2769,7 +2763,7 @@ impl EditorElement {
}
};
- let background_color = match (&settings.background_coloring, indent_guide.active) {
+ let background_color = match (settings.background_coloring, indent_guide.active) {
(IndentGuideBackgroundColoring::Disabled, _) => None,
(IndentGuideBackgroundColoring::IndentAware, false) => Some(faded_color(
indent_accent_colors,
@@ -5286,6 +5280,7 @@ pub struct IndentGuideLayout {
single_indent_width: Pixels,
depth: u32,
active: bool,
+ settings: IndentGuideSettings,
}
pub struct CursorLayout {
diff --git a/crates/editor/src/indent_guides.rs b/crates/editor/src/indent_guides.rs
index 1b780e47085f1a8e0581528efa51730dd83537f1..b4034a88ace47eccf61671a64e24325f1e2ac5cd 100644
--- a/crates/editor/src/indent_guides.rs
+++ b/crates/editor/src/indent_guides.rs
@@ -2,7 +2,7 @@ use std::{ops::Range, time::Duration};
use collections::HashSet;
use gpui::{AppContext, Task};
-use language::BufferRow;
+use language::{language_settings::language_settings, BufferRow};
use multi_buffer::{MultiBufferIndentGuide, MultiBufferRow};
use text::{BufferId, LineIndent, Point};
use ui::ViewContext;
@@ -37,13 +37,26 @@ impl Editor {
snapshot: &DisplaySnapshot,
cx: &mut ViewContext,
) -> Option> {
- let enabled = self.should_show_indent_guides(cx);
+ let show_indent_guides = self.should_show_indent_guides().unwrap_or_else(|| {
+ if let Some(buffer) = self.buffer().read(cx).as_singleton() {
+ language_settings(buffer.read(cx).language(), buffer.read(cx).file(), cx)
+ .indent_guides
+ .enabled
+ } else {
+ true
+ }
+ });
- if enabled {
- Some(indent_guides_in_range(visible_buffer_range, snapshot, cx))
- } else {
- None
+ if !show_indent_guides {
+ return None;
}
+
+ Some(indent_guides_in_range(
+ visible_buffer_range,
+ self.should_show_indent_guides() == Some(true),
+ snapshot,
+ cx,
+ ))
}
pub fn find_active_indent_guide_indices(
@@ -77,9 +90,14 @@ impl Editor {
if state.should_refresh() {
state.cursor_row = cursor_row;
- let snapshot = snapshot.clone();
state.dirty = false;
+ if indent_guides.is_empty() {
+ return None;
+ }
+
+ let snapshot = snapshot.clone();
+
let task = cx
.background_executor()
.spawn(resolve_indented_range(snapshot, cursor_row));
@@ -131,6 +149,7 @@ impl Editor {
pub fn indent_guides_in_range(
visible_buffer_range: Range,
+ ignore_disabled_for_language: bool,
snapshot: &DisplaySnapshot,
cx: &AppContext,
) -> Vec {
@@ -143,7 +162,7 @@ pub fn indent_guides_in_range(
snapshot
.buffer_snapshot
- .indent_guides_in_range(start_anchor..end_anchor, cx)
+ .indent_guides_in_range(start_anchor..end_anchor, ignore_disabled_for_language, cx)
.into_iter()
.filter(|indent_guide| {
// Filter out indent guides that are inside a fold
diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs
index 9539829f69d596e68651c66781e27a967f59e69a..68dd36201c5640296d8a13a5323c31b63454d827 100644
--- a/crates/language/src/buffer.rs
+++ b/crates/language/src/buffer.rs
@@ -6,7 +6,7 @@ pub use crate::{
};
use crate::{
diagnostic_set::{DiagnosticEntry, DiagnosticGroup},
- language_settings::{language_settings, LanguageSettings},
+ language_settings::{language_settings, IndentGuideSettings, LanguageSettings},
markdown::parse_markdown,
outline::OutlineItem,
syntax_map::{
@@ -542,25 +542,10 @@ pub struct IndentGuide {
pub end_row: BufferRow,
pub depth: u32,
pub tab_size: u32,
+ pub settings: IndentGuideSettings,
}
impl IndentGuide {
- pub fn new(
- buffer_id: BufferId,
- start_row: BufferRow,
- end_row: BufferRow,
- depth: u32,
- tab_size: u32,
- ) -> Self {
- Self {
- buffer_id,
- start_row,
- end_row,
- depth,
- tab_size,
- }
- }
-
pub fn indent_level(&self) -> u32 {
self.depth * self.tab_size
}
@@ -3151,9 +3136,15 @@ impl BufferSnapshot {
pub fn indent_guides_in_range(
&self,
range: Range,
+ ignore_disabled_for_language: bool,
cx: &AppContext,
) -> Vec {
- let tab_size = language_settings(self.language(), None, cx).tab_size.get() as u32;
+ let language_settings = language_settings(self.language(), self.file.as_ref(), cx);
+ let settings = language_settings.indent_guides;
+ if !ignore_disabled_for_language && !settings.enabled {
+ return Vec::new();
+ }
+ let tab_size = language_settings.tab_size.get() as u32;
let start_row = range.start.to_point(self).row;
let end_row = range.end.to_point(self).row;
@@ -3234,6 +3225,7 @@ impl BufferSnapshot {
end_row: last_row,
depth: next_depth,
tab_size,
+ settings,
});
}
}
diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs
index cd0d6fd7ebe7cdf6ec29c7d702446909a5a0ad4c..4eb630e78e924bf3e0340818fe988fe32b3d53ac 100644
--- a/crates/multi_buffer/src/multi_buffer.rs
+++ b/crates/multi_buffer/src/multi_buffer.rs
@@ -3289,12 +3289,17 @@ impl MultiBufferSnapshot {
pub fn indent_guides_in_range(
&self,
range: Range,
+ ignore_disabled_for_language: bool,
cx: &AppContext,
) -> Vec {
// Fast path for singleton buffers, we can skip the conversion between offsets.
if let Some((_, _, snapshot)) = self.as_singleton() {
return snapshot
- .indent_guides_in_range(range.start.text_anchor..range.end.text_anchor, cx)
+ .indent_guides_in_range(
+ range.start.text_anchor..range.end.text_anchor,
+ ignore_disabled_for_language,
+ cx,
+ )
.into_iter()
.map(|guide| MultiBufferIndentGuide {
multibuffer_row_range: MultiBufferRow(guide.start_row)
@@ -3314,7 +3319,11 @@ impl MultiBufferSnapshot {
excerpt
.buffer
- .indent_guides_in_range(excerpt.range.context.clone(), cx)
+ .indent_guides_in_range(
+ excerpt.range.context.clone(),
+ ignore_disabled_for_language,
+ cx,
+ )
.into_iter()
.map(move |indent_guide| {
let start_row = excerpt_offset_row