diff --git a/assets/settings/default.json b/assets/settings/default.json index 1c394c065d..27a5958fb7 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -218,6 +218,23 @@ // 1. Do nothing: `none` // 2. Find references for the same symbol: `find_all_references` (default) "go_to_definition_fallback": "find_all_references", + // Which level to use to filter out diagnostics displayed in the editor. + // + // Affects the editor rendering only, and does not interrupt + // the functionality of diagnostics fetching and project diagnostics editor. + // Which files containing diagnostic errors/warnings to mark in the tabs. + // Diagnostics are only shown when file icons are also active. + // This setting only works when can take the following three values: + // + // Which diagnostic indicators to show in the scrollbar, their level should be more or equal to the specified severity level. + // Possible values: + // - "off" — no diagnostics are allowed + // - "error" + // - "warning" (default) + // - "info" + // - "hint" + // - null — allow all diagnostics + "diagnostics_max_severity": "warning", // Whether to show wrap guides (vertical rulers) in the editor. // Setting this to true will show a guide at the 'preferred_line_length' value // if 'soft_wrap' is set to 'preferred_line_length', and will show any @@ -1002,7 +1019,7 @@ // longer than this value will still push diagnostics further to the right. "min_column": 0, // The minimum severity of the diagnostics to show inline. - // Shows all diagnostics when not specified. + // Inherits editor's diagnostics' max severity settings when `null`. "max_severity": null }, "cargo": { diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index cf9e023546..955b28d40d 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -23,11 +23,10 @@ use gpui::{ use language::{ Bias, Buffer, BufferRow, BufferSnapshot, DiagnosticEntry, Point, ToTreeSitterPoint, }; -use lsp::DiagnosticSeverity; use project::{ DiagnosticSummary, Project, ProjectPath, lsp_store::rust_analyzer_ext::{cancel_flycheck, run_flycheck}, - project_settings::ProjectSettings, + project_settings::{DiagnosticSeverity, ProjectSettings}, }; use settings::Settings; use std::{ @@ -203,6 +202,14 @@ impl ProjectDiagnosticsEditor { Editor::for_multibuffer(excerpts.clone(), Some(project_handle.clone()), window, cx); editor.set_vertical_scroll_margin(5, cx); editor.disable_inline_diagnostics(); + editor.set_max_diagnostics_severity( + if include_warnings { + DiagnosticSeverity::Warning + } else { + DiagnosticSeverity::Error + }, + cx, + ); editor.set_all_diagnostics_active(cx); editor }); @@ -224,7 +231,18 @@ impl ProjectDiagnosticsEditor { ) .detach(); cx.observe_global_in::(window, |this, window, cx| { - this.include_warnings = cx.global::().0; + let include_warnings = cx.global::().0; + this.include_warnings = include_warnings; + this.editor.update(cx, |editor, cx| { + editor.set_max_diagnostics_severity( + if include_warnings { + DiagnosticSeverity::Warning + } else { + DiagnosticSeverity::Error + }, + cx, + ) + }); this.diagnostics.clear(); this.update_all_diagnostics(false, window, cx); }) @@ -488,9 +506,9 @@ impl ProjectDiagnosticsEditor { let buffer_snapshot = buffer.read(cx).snapshot(); let buffer_id = buffer_snapshot.remote_id(); let max_severity = if self.include_warnings { - DiagnosticSeverity::WARNING + lsp::DiagnosticSeverity::WARNING } else { - DiagnosticSeverity::ERROR + lsp::DiagnosticSeverity::ERROR }; cx.spawn_in(window, async move |this, mut cx| { diff --git a/crates/editor/src/actions.rs b/crates/editor/src/actions.rs index 38ee4148f2..8952f3ce10 100644 --- a/crates/editor/src/actions.rs +++ b/crates/editor/src/actions.rs @@ -425,6 +425,7 @@ actions!( ToggleAutoSignatureHelp, ToggleGitBlameInline, OpenGitBlameCommit, + ToggleDiagnostics, ToggleIndentGuides, ToggleInlayHints, ToggleInlineValues, diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index 643872e828..b3742620da 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -47,12 +47,13 @@ pub use invisibles::{is_invisible, replacement}; use language::{ OffsetUtf16, Point, Subscription as BufferSubscription, language_settings::language_settings, }; -use lsp::DiagnosticSeverity; use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, MultiBuffer, MultiBufferPoint, MultiBufferRow, MultiBufferSnapshot, RowInfo, ToOffset, ToPoint, }; +use project::project_settings::DiagnosticSeverity; use serde::Deserialize; + use std::{ any::TypeId, borrow::Cow, @@ -109,6 +110,7 @@ pub struct DisplayMap { pub(crate) fold_placeholder: FoldPlaceholder, pub clip_at_line_ends: bool, pub(crate) masked: bool, + pub(crate) diagnostics_max_severity: DiagnosticSeverity, } impl DisplayMap { @@ -120,6 +122,7 @@ impl DisplayMap { buffer_header_height: u32, excerpt_header_height: u32, fold_placeholder: FoldPlaceholder, + diagnostics_max_severity: DiagnosticSeverity, cx: &mut Context, ) -> Self { let buffer_subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); @@ -145,6 +148,7 @@ impl DisplayMap { block_map, crease_map, fold_placeholder, + diagnostics_max_severity, text_highlights: Default::default(), inlay_highlights: Default::default(), clip_at_line_ends: false, @@ -171,6 +175,7 @@ impl DisplayMap { tab_snapshot, wrap_snapshot, block_snapshot, + diagnostics_max_severity: self.diagnostics_max_severity, crease_snapshot: self.crease_map.snapshot(), text_highlights: self.text_highlights.clone(), inlay_highlights: self.inlay_highlights.clone(), @@ -745,6 +750,7 @@ pub struct DisplaySnapshot { inlay_highlights: InlayHighlights, clip_at_line_ends: bool, masked: bool, + diagnostics_max_severity: DiagnosticSeverity, pub(crate) fold_placeholder: FoldPlaceholder, } @@ -947,21 +953,22 @@ impl DisplaySnapshot { let mut diagnostic_highlight = HighlightStyle::default(); - if chunk.is_unnecessary { - diagnostic_highlight.fade_out = Some(editor_style.unnecessary_code_fade); - } - - // Omit underlines for HINT/INFO diagnostics on 'unnecessary' code. if let Some(severity) = chunk.diagnostic_severity.filter(|severity| { - editor_style.show_underlines - && (!chunk.is_unnecessary || *severity <= DiagnosticSeverity::WARNING) + self.diagnostics_max_severity + .into_lsp() + .map_or(false, |max_severity| severity <= &max_severity) }) { - let diagnostic_color = super::diagnostic_style(severity, &editor_style.status); - diagnostic_highlight.underline = Some(UnderlineStyle { - color: Some(diagnostic_color), - thickness: 1.0.into(), - wavy: true, - }); + if chunk.is_unnecessary { + diagnostic_highlight.fade_out = Some(editor_style.unnecessary_code_fade); + } + if editor_style.show_underlines { + let diagnostic_color = super::diagnostic_style(severity, &editor_style.status); + diagnostic_highlight.underline = Some(UnderlineStyle { + color: Some(diagnostic_color), + thickness: 1.0.into(), + wavy: true, + }); + } } if let Some(highlight_style) = highlight_style.as_mut() { @@ -1546,6 +1553,7 @@ pub mod tests { buffer_start_excerpt_header_height, excerpt_header_height, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -1794,6 +1802,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -1903,6 +1912,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -1964,6 +1974,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -2057,6 +2068,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -2157,6 +2169,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -2238,7 +2251,7 @@ pub mod tests { [DiagnosticEntry { range: PointUtf16::new(0, 0)..PointUtf16::new(2, 1), diagnostic: Diagnostic { - severity: DiagnosticSeverity::ERROR, + severity: lsp::DiagnosticSeverity::ERROR, group_id: 1, message: "hi".into(), ..Default::default() @@ -2262,6 +2275,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -2297,7 +2311,7 @@ pub mod tests { }); let snapshot = map.update(cx, |map, cx| map.snapshot(cx)); - let mut chunks = Vec::<(String, Option, Rgba)>::new(); + let mut chunks = Vec::<(String, Option, Rgba)>::new(); for chunk in snapshot.chunks(DisplayRow(0)..DisplayRow(5), true, Default::default()) { let color = chunk .highlight_style @@ -2318,11 +2332,11 @@ pub mod tests { [ ( "struct A {\n b: usize;\n".into(), - Some(DiagnosticSeverity::ERROR), + Some(lsp::DiagnosticSeverity::ERROR), black ), ("\n".into(), None, black), - ("}".into(), Some(DiagnosticSeverity::ERROR), black), + ("}".into(), Some(lsp::DiagnosticSeverity::ERROR), black), ("\nconst c: ".into(), None, black), ("usize".into(), None, red), (" = ".into(), None, black), @@ -2350,6 +2364,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -2491,6 +2506,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -2573,6 +2589,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -2697,6 +2714,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ); let snapshot = map.buffer.read(cx).snapshot(cx); @@ -2734,6 +2752,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -2809,6 +2828,7 @@ pub mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); diff --git a/crates/editor/src/display_map/fold_map.rs b/crates/editor/src/display_map/fold_map.rs index 8281b7642c..8d199f5b3e 100644 --- a/crates/editor/src/display_map/fold_map.rs +++ b/crates/editor/src/display_map/fold_map.rs @@ -4,7 +4,6 @@ use super::{ }; use gpui::{AnyElement, App, ElementId, HighlightStyle, Pixels, Window}; use language::{Edit, HighlightId, Point, TextSummary}; -use lsp::DiagnosticSeverity; use multi_buffer::{ Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, RowInfo, ToOffset, }; @@ -1253,7 +1252,7 @@ pub struct Chunk<'a> { /// the editor. pub highlight_style: Option, /// The severity of diagnostic associated with this chunk, if any. - pub diagnostic_severity: Option, + pub diagnostic_severity: Option, /// Whether this chunk of text is marked as unnecessary. pub is_unnecessary: bool, /// Whether this chunk of text was originally a tab character. diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index ddf4743568..1d37d68a3f 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -129,6 +129,7 @@ use project::{ }, session::{Session, SessionEvent}, }, + project_settings::DiagnosticSeverity, }; pub use git::blame::BlameRenderer; @@ -141,8 +142,8 @@ use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables}; pub use lsp::CompletionContext; use lsp::{ - CodeActionKind, CompletionItemKind, CompletionTriggerKind, DiagnosticSeverity, - InsertTextFormat, InsertTextMode, LanguageServerId, LanguageServerName, + CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode, + LanguageServerId, LanguageServerName, }; use language::BufferSnapshot; @@ -628,7 +629,7 @@ struct InlineDiagnostic { group_id: usize, is_primary: bool, start: Point, - severity: DiagnosticSeverity, + severity: lsp::DiagnosticSeverity, } pub enum MenuInlineCompletionsPolicy { @@ -860,6 +861,7 @@ pub struct Editor { snippet_stack: InvalidationStack, select_syntax_node_history: SelectSyntaxNodeHistory, ime_transaction: Option, + pub diagnostics_max_severity: DiagnosticSeverity, active_diagnostics: ActiveDiagnostic, show_inline_diagnostics: bool, inline_diagnostics_update: Task<()>, @@ -1506,6 +1508,15 @@ impl Editor { display_map.is_none() || mode.is_minimap(), "Providing a display map for a new editor is only intended for the minimap and might have unindended side effects otherwise!" ); + + let full_mode = mode.is_full(); + let diagnostics_max_severity = if full_mode { + EditorSettings::get_global(cx) + .diagnostics_max_severity + .unwrap_or(DiagnosticSeverity::Hint) + } else { + DiagnosticSeverity::Off + }; let style = window.text_style(); let font_size = style.font_size.to_pixels(window.rem_size()); let editor = cx.entity().downgrade(); @@ -1539,7 +1550,7 @@ impl Editor { .into_any() }), merge_adjacent: true, - ..Default::default() + ..FoldPlaceholder::default() }; let display_map = display_map.unwrap_or_else(|| { cx.new(|cx| { @@ -1551,6 +1562,7 @@ impl Editor { FILE_HEADER_HEIGHT, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, fold_placeholder, + diagnostics_max_severity, cx, ) }) @@ -1678,8 +1690,6 @@ impl Editor { code_action_providers.push(Rc::new(project) as Rc<_>); } - let full_mode = mode.is_full(); - let mut this = Self { focus_handle, show_cursor_when_unfocused: false, @@ -1692,16 +1702,17 @@ impl Editor { add_selections_state: None, select_next_state: None, select_prev_state: None, - selection_history: Default::default(), - autoclose_regions: Default::default(), - snippet_stack: Default::default(), + selection_history: SelectionHistory::default(), + autoclose_regions: Vec::new(), + snippet_stack: InvalidationStack::default(), select_syntax_node_history: SelectSyntaxNodeHistory::default(), - ime_transaction: Default::default(), + ime_transaction: None, active_diagnostics: ActiveDiagnostic::None, show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled, inline_diagnostics_update: Task::ready(()), inline_diagnostics: Vec::new(), soft_wrap_mode_override, + diagnostics_max_severity, hard_wrap: None, completion_provider: project.clone().map(|project| Box::new(project) as _), semantics_provider: project.clone().map(|project| Rc::new(project) as _), @@ -1725,7 +1736,7 @@ impl Editor { placeholder_text: None, highlight_order: 0, highlighted_rows: HashMap::default(), - background_highlights: Default::default(), + background_highlights: TreeMap::default(), gutter_highlights: TreeMap::default(), scrollbar_marker_state: ScrollbarMarkerState::default(), active_indent_guides_state: ActiveIndentGuidesState::default(), @@ -1733,21 +1744,21 @@ impl Editor { context_menu: RefCell::new(None), context_menu_options: None, mouse_context_menu: None, - completion_tasks: Default::default(), - inline_blame_popover: Default::default(), + completion_tasks: Vec::new(), + inline_blame_popover: None, signature_help_state: SignatureHelpState::default(), auto_signature_help: None, find_all_references_task_sources: Vec::new(), next_completion_id: 0, next_inlay_id: 0, code_action_providers, - available_code_actions: Default::default(), - code_actions_task: Default::default(), - quick_selection_highlight_task: Default::default(), - debounced_selection_highlight_task: Default::default(), - document_highlights_task: Default::default(), - linked_editing_range_task: Default::default(), - pending_rename: Default::default(), + available_code_actions: None, + code_actions_task: None, + quick_selection_highlight_task: None, + debounced_selection_highlight_task: None, + document_highlights_task: None, + linked_editing_range_task: None, + pending_rename: None, searchable: true, cursor_shape: EditorSettings::get_global(cx) .cursor_shape @@ -1765,9 +1776,9 @@ impl Editor { jsx_tag_auto_close_enabled_in_any_buffer: false, leader_id: None, remote_id: None, - hover_state: Default::default(), + hover_state: HoverState::default(), pending_mouse_down: None, - hovered_link_state: Default::default(), + hovered_link_state: None, edit_prediction_provider: None, active_inline_completion: None, stale_inline_completion_in_menu: None, @@ -1786,7 +1797,7 @@ impl Editor { gutter_dimensions: GutterDimensions::default(), style: None, show_cursor_names: false, - hovered_cursors: Default::default(), + hovered_cursors: HashMap::default(), next_editor_action_id: EditorActionId::default(), editor_actions: Rc::default(), inline_completions_hidden_for_vim_mode: false, @@ -1808,7 +1819,7 @@ impl Editor { .restore_unsaved_buffers, blame: None, blame_subscription: None, - tasks: Default::default(), + tasks: BTreeMap::default(), breakpoint_store, gutter_breakpoint_indicator: (None, None), @@ -15093,8 +15104,12 @@ impl Editor { self.inline_diagnostics.clear(); } + pub fn diagnostics_enabled(&self) -> bool { + self.mode.is_full() + } + pub fn inline_diagnostics_enabled(&self) -> bool { - self.inline_diagnostics_enabled + self.diagnostics_enabled() && self.inline_diagnostics_enabled } pub fn show_inline_diagnostics(&self) -> bool { @@ -15111,6 +15126,43 @@ impl Editor { self.refresh_inline_diagnostics(false, window, cx); } + pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) { + self.diagnostics_max_severity = severity; + self.display_map.update(cx, |display_map, _| { + display_map.diagnostics_max_severity = self.diagnostics_max_severity; + }); + } + + pub fn toggle_diagnostics( + &mut self, + _: &ToggleDiagnostics, + window: &mut Window, + cx: &mut Context, + ) { + if !self.diagnostics_enabled() { + return; + } + + let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off { + EditorSettings::get_global(cx) + .diagnostics_max_severity + .filter(|severity| severity != &DiagnosticSeverity::Off) + .unwrap_or(DiagnosticSeverity::Hint) + } else { + DiagnosticSeverity::Off + }; + self.set_max_diagnostics_severity(new_severity, cx); + if self.diagnostics_max_severity == DiagnosticSeverity::Off { + self.active_diagnostics = ActiveDiagnostic::None; + self.inline_diagnostics_update = Task::ready(()); + self.inline_diagnostics.clear(); + } else { + self.refresh_inline_diagnostics(false, window, cx); + } + + cx.notify(); + } + pub fn toggle_minimap( &mut self, _: &ToggleMinimap, @@ -15128,9 +15180,16 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { + let max_severity = ProjectSettings::get_global(cx) + .diagnostics + .inline + .max_severity + .unwrap_or(self.diagnostics_max_severity); + if self.mode.is_minimap() - || !self.inline_diagnostics_enabled + || !self.inline_diagnostics_enabled() || !self.show_inline_diagnostics + || max_severity == DiagnosticSeverity::Off { self.inline_diagnostics_update = Task::ready(()); self.inline_diagnostics.clear(); @@ -18050,6 +18109,14 @@ impl Editor { } fn settings_changed(&mut self, window: &mut Window, cx: &mut Context) { + let new_severity = if self.diagnostics_enabled() { + EditorSettings::get_global(cx) + .diagnostics_max_severity + .unwrap_or(DiagnosticSeverity::Hint) + } else { + DiagnosticSeverity::Off + }; + self.set_max_diagnostics_severity(new_severity, cx); self.tasks_update_task = Some(self.refresh_runnables(window, cx)); self.update_edit_prediction_settings(cx); self.refresh_inline_completion(true, false, window, cx); @@ -20471,8 +20538,6 @@ impl Render for Editor { EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7), }; - let show_underlines = !self.mode.is_minimap(); - EditorElement::new( &cx.entity(), EditorStyle { @@ -20485,7 +20550,7 @@ impl Render for Editor { inlay_hints_style: make_inlay_hints_style(cx), inline_completion_styles: make_suggestion_styles(cx), unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade, - show_underlines, + show_underlines: !self.mode.is_minimap(), }, ) } @@ -20896,12 +20961,12 @@ fn inline_completion_edit_text( edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx) } -pub fn diagnostic_style(severity: DiagnosticSeverity, colors: &StatusColors) -> Hsla { +pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla { match severity { - DiagnosticSeverity::ERROR => colors.error, - DiagnosticSeverity::WARNING => colors.warning, - DiagnosticSeverity::INFORMATION => colors.info, - DiagnosticSeverity::HINT => colors.info, + lsp::DiagnosticSeverity::ERROR => colors.error, + lsp::DiagnosticSeverity::WARNING => colors.warning, + lsp::DiagnosticSeverity::INFORMATION => colors.info, + lsp::DiagnosticSeverity::HINT => colors.info, _ => colors.ignored, } } diff --git a/crates/editor/src/editor_settings.rs b/crates/editor/src/editor_settings.rs index 5f337d06d5..f4c0b3a755 100644 --- a/crates/editor/src/editor_settings.rs +++ b/crates/editor/src/editor_settings.rs @@ -1,5 +1,6 @@ use gpui::App; use language::CursorShape; +use project::project_settings::DiagnosticSeverity; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use settings::{Settings, SettingsSources, VsCodeSettings}; @@ -41,6 +42,8 @@ pub struct EditorSettings { pub jupyter: Jupyter, pub hide_mouse: Option, pub snippet_sort_order: SnippetSortOrder, + #[serde(default)] + pub diagnostics_max_severity: Option, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] @@ -451,6 +454,19 @@ pub struct EditorSettingsContent { /// Jupyter REPL settings. pub jupyter: Option, + + /// Which level to use to filter out diagnostics displayed in the editor. + /// + /// Affects the editor rendering only, and does not interrupt + /// the functionality of diagnostics fetching and project diagnostics editor. + /// Which files containing diagnostic errors/warnings to mark in the tabs. + /// Diagnostics are only shown when file icons are also active. + /// + /// Shows all diagnostics if not specified. + /// + /// Default: warning + #[serde(default)] + pub diagnostics_max_severity: Option, } // Toolbar related settings diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 7dda55f693..a9a40d20c7 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -54,7 +54,6 @@ use itertools::Itertools; use language::language_settings::{ IndentGuideBackgroundColoring, IndentGuideColoring, IndentGuideSettings, ShowWhitespaceSetting, }; -use lsp::DiagnosticSeverity; use markdown::Markdown; use multi_buffer::{ Anchor, ExcerptId, ExcerptInfo, ExpandExcerptDirection, ExpandInfo, MultiBufferPoint, @@ -64,7 +63,7 @@ use multi_buffer::{ use project::{ ProjectPath, debugger::breakpoint_store::Breakpoint, - project_settings::{self, GitGutterSetting, GitHunkStyleSetting, ProjectSettings}, + project_settings::{GitGutterSetting, GitHunkStyleSetting, ProjectSettings}, }; use settings::Settings; use smallvec::{SmallVec, smallvec}; @@ -1474,7 +1473,8 @@ impl EditorElement { }); } - let scrollbar_settings = EditorSettings::get_global(cx).scrollbar; + let editor_settings = EditorSettings::get_global(cx); + let scrollbar_settings = editor_settings.scrollbar; let show_scrollbars = match scrollbar_settings.show { ShowScrollbar::Auto => { let editor = self.editor.read(cx); @@ -1796,16 +1796,17 @@ impl EditorElement { if self.editor.read(cx).mode().is_minimap() { return HashMap::default(); } - let max_severity = ProjectSettings::get_global(cx) + + let max_severity = match ProjectSettings::get_global(cx) .diagnostics .inline .max_severity - .map_or(DiagnosticSeverity::HINT, |severity| match severity { - project_settings::DiagnosticSeverity::Error => DiagnosticSeverity::ERROR, - project_settings::DiagnosticSeverity::Warning => DiagnosticSeverity::WARNING, - project_settings::DiagnosticSeverity::Info => DiagnosticSeverity::INFORMATION, - project_settings::DiagnosticSeverity::Hint => DiagnosticSeverity::HINT, - }); + .unwrap_or_else(|| self.editor.read(cx).diagnostics_max_severity) + .into_lsp() + { + Some(max_severity) => max_severity, + None => return HashMap::default(), + }; let active_diagnostics_group = if let ActiveDiagnostic::Group(group) = &self.editor.read(cx).active_diagnostics { @@ -1843,11 +1844,11 @@ impl EditorElement { return HashMap::default(); } - let severity_to_color = |sev: &DiagnosticSeverity| match sev { - &DiagnosticSeverity::ERROR => Color::Error, - &DiagnosticSeverity::WARNING => Color::Warning, - &DiagnosticSeverity::INFORMATION => Color::Info, - &DiagnosticSeverity::HINT => Color::Hint, + let severity_to_color = |sev: &lsp::DiagnosticSeverity| match sev { + &lsp::DiagnosticSeverity::ERROR => Color::Error, + &lsp::DiagnosticSeverity::WARNING => Color::Warning, + &lsp::DiagnosticSeverity::INFORMATION => Color::Info, + &lsp::DiagnosticSeverity::HINT => Color::Hint, _ => Color::Error, }; @@ -2813,7 +2814,7 @@ impl EditorElement { font: style.text.font(), color: placeholder_color, background_color: None, - underline: Default::default(), + underline: None, strikethrough: None, }; window @@ -5587,18 +5588,18 @@ impl EditorElement { (ScrollbarDiagnostics::All, _) => true, ( ScrollbarDiagnostics::Error, - DiagnosticSeverity::ERROR, + lsp::DiagnosticSeverity::ERROR, ) => true, ( ScrollbarDiagnostics::Warning, - DiagnosticSeverity::ERROR - | DiagnosticSeverity::WARNING, + lsp::DiagnosticSeverity::ERROR + | lsp::DiagnosticSeverity::WARNING, ) => true, ( ScrollbarDiagnostics::Information, - DiagnosticSeverity::ERROR - | DiagnosticSeverity::WARNING - | DiagnosticSeverity::INFORMATION, + lsp::DiagnosticSeverity::ERROR + | lsp::DiagnosticSeverity::WARNING + | lsp::DiagnosticSeverity::INFORMATION, ) => true, (_, _) => false, } @@ -5618,9 +5619,9 @@ impl EditorElement { .end .to_display_point(&snapshot.display_snapshot); let color = match diagnostic.diagnostic.severity { - DiagnosticSeverity::ERROR => theme.status().error, - DiagnosticSeverity::WARNING => theme.status().warning, - DiagnosticSeverity::INFORMATION => theme.status().info, + lsp::DiagnosticSeverity::ERROR => theme.status().error, + lsp::DiagnosticSeverity::WARNING => theme.status().warning, + lsp::DiagnosticSeverity::INFORMATION => theme.status().info, _ => theme.status().hint, }; ColoredRange { diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 80abf4a9da..c6720d40ff 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -772,7 +772,7 @@ mod tests { }; use gpui::{AppContext as _, font, px}; use language::Capability; - use project::Project; + use project::{Project, project_settings::DiagnosticSeverity}; use settings::SettingsStore; use util::post_inc; @@ -896,6 +896,7 @@ mod tests { 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); @@ -1105,6 +1106,7 @@ mod tests { 0, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs index 9af7d1e25c..da2011a0c6 100644 --- a/crates/editor/src/test.rs +++ b/crates/editor/src/test.rs @@ -18,7 +18,7 @@ use gpui::{ }; use multi_buffer::ToPoint; use pretty_assertions::assert_eq; -use project::Project; +use project::{Project, project_settings::DiagnosticSeverity}; use ui::{App, BorrowAppContext, px}; use util::test::{marked_text_offsets, marked_text_ranges}; @@ -72,6 +72,7 @@ pub fn marked_display_snapshot( 1, 1, FoldPlaceholder::test(), + DiagnosticSeverity::Warning, cx, ) }); diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index 387bccbcd1..c3fb086dc2 100644 --- a/crates/project/src/project_settings.rs +++ b/crates/project/src/project_settings.rs @@ -181,15 +181,31 @@ pub struct CargoDiagnosticsSettings { pub fetch_cargo_diagnostics: bool, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema)] +#[derive( + Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, JsonSchema, +)] #[serde(rename_all = "snake_case")] pub enum DiagnosticSeverity { + // No diagnostics are shown. + Off, Error, Warning, Info, Hint, } +impl DiagnosticSeverity { + pub fn into_lsp(self) -> Option { + match self { + DiagnosticSeverity::Off => None, + DiagnosticSeverity::Error => Some(lsp::DiagnosticSeverity::ERROR), + DiagnosticSeverity::Warning => Some(lsp::DiagnosticSeverity::WARNING), + DiagnosticSeverity::Info => Some(lsp::DiagnosticSeverity::INFORMATION), + DiagnosticSeverity::Hint => Some(lsp::DiagnosticSeverity::HINT), + } + } +} + impl Default for InlineDiagnosticsSettings { fn default() -> Self { Self { diff --git a/crates/zed/src/zed/quick_action_bar.rs b/crates/zed/src/zed/quick_action_bar.rs index e75acc2d0c..d618d29af3 100644 --- a/crates/zed/src/zed/quick_action_bar.rs +++ b/crates/zed/src/zed/quick_action_bar.rs @@ -5,13 +5,15 @@ use assistant_settings::AssistantSettings; use editor::actions::{ AddSelectionAbove, AddSelectionBelow, DuplicateLineDown, GoToDiagnostic, GoToHunk, GoToPreviousDiagnostic, GoToPreviousHunk, MoveLineDown, MoveLineUp, SelectAll, - SelectLargerSyntaxNode, SelectNext, SelectSmallerSyntaxNode, ToggleGoToLine, + SelectLargerSyntaxNode, SelectNext, SelectSmallerSyntaxNode, ToggleDiagnostics, ToggleGoToLine, + ToggleInlineDiagnostics, }; use editor::{Editor, EditorSettings}; use gpui::{ Action, ClickEvent, Context, Corner, ElementId, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement, ParentElement, Render, Styled, Subscription, WeakEntity, Window, }; +use project::project_settings::DiagnosticSeverity; use search::{BufferSearchBar, buffer_search}; use settings::{Settings, SettingsStore}; use ui::{ @@ -91,8 +93,10 @@ impl Render for QuickActionBar { let selection_menu_enabled = editor_value.selection_menu_enabled(cx); let inlay_hints_enabled = editor_value.inlay_hints_enabled(); let inline_values_enabled = editor_value.inline_values_enabled(); - let inline_diagnostics_enabled = editor_value.show_inline_diagnostics(); + let supports_diagnostics = editor_value.mode().is_full(); + let diagnostics_enabled = editor_value.diagnostics_max_severity != DiagnosticSeverity::Off; let supports_inline_diagnostics = editor_value.inline_diagnostics_enabled(); + let inline_diagnostics_enabled = editor_value.show_inline_diagnostics(); let git_blame_inline_enabled = editor_value.git_blame_inline_enabled(); let show_git_blame_gutter = editor_value.show_git_blame_gutter(); let auto_signature_help_enabled = editor_value.auto_signature_help_enabled(cx); @@ -248,19 +252,19 @@ impl Render for QuickActionBar { ); } - if supports_inline_diagnostics { + if supports_diagnostics { menu = menu.toggleable_entry( - "Inline Diagnostics", - inline_diagnostics_enabled, + "Diagnostics", + diagnostics_enabled, IconPosition::Start, - Some(editor::actions::ToggleInlineDiagnostics.boxed_clone()), + Some(ToggleDiagnostics.boxed_clone()), { let editor = editor.clone(); move |window, cx| { editor .update(cx, |editor, cx| { - editor.toggle_inline_diagnostics( - &editor::actions::ToggleInlineDiagnostics, + editor.toggle_diagnostics( + &ToggleDiagnostics, window, cx, ); @@ -269,6 +273,29 @@ impl Render for QuickActionBar { } }, ); + + if supports_inline_diagnostics { + menu = menu.toggleable_entry( + "Inline Diagnostics", + inline_diagnostics_enabled, + IconPosition::Start, + Some(ToggleInlineDiagnostics.boxed_clone()), + { + let editor = editor.clone(); + move |window, cx| { + editor + .update(cx, |editor, cx| { + editor.toggle_inline_diagnostics( + &ToggleInlineDiagnostics, + window, + cx, + ); + }) + .ok(); + } + }, + ); + } } if supports_minimap {