diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index da0b381f4c..f888534f6b 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 de1eb6bebb..1463af3514 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 eb4cb978c8..280be02523 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 1b780e4708..b4034a88ac 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 9539829f69..68dd36201c 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 cd0d6fd7eb..4eb630e78e 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