Add severity argument to GoToDiagnostic actions (#33995)
This PR adds a `severity` argument so severity can be defined when navigating through diagnostics. This allows keybinds like the following: ```json { "] e": ["editor::GoToDiagnostic", { "severity": "error" }], "[ e": ["editor::GoToDiagnostic", { "severity": "error" }] } ``` I've added test comments and a test. Let me know if there's anything else you need! Release Notes: - Add `severity` argument to `editor::GoToDiagnostic`, `editor::GoToPreviousDiagnostic`, `project_panel::SelectNextDiagnostic` and `project_panel::SelectPrevDiagnostic` actions
This commit is contained in:
parent
858e176a1c
commit
050ed85d71
12 changed files with 312 additions and 51 deletions
|
@ -475,8 +475,8 @@
|
||||||
"ctrl-/": ["editor::ToggleComments", { "advance_downwards": false }],
|
"ctrl-/": ["editor::ToggleComments", { "advance_downwards": false }],
|
||||||
"ctrl-u": "editor::UndoSelection",
|
"ctrl-u": "editor::UndoSelection",
|
||||||
"ctrl-shift-u": "editor::RedoSelection",
|
"ctrl-shift-u": "editor::RedoSelection",
|
||||||
"f8": "editor::GoToDiagnostic",
|
"f8": ["editor::GoToDiagnostic", { "severity": { "min": "hint", "max": "error" } }],
|
||||||
"shift-f8": "editor::GoToPreviousDiagnostic",
|
"shift-f8": ["editor::GoToPreviousDiagnostic", { "severity": { "min": "hint", "max": "error" } }],
|
||||||
"f2": "editor::Rename",
|
"f2": "editor::Rename",
|
||||||
"f12": "editor::GoToDefinition",
|
"f12": "editor::GoToDefinition",
|
||||||
"alt-f12": "editor::GoToDefinitionSplit",
|
"alt-f12": "editor::GoToDefinitionSplit",
|
||||||
|
|
|
@ -528,8 +528,8 @@
|
||||||
"cmd-/": ["editor::ToggleComments", { "advance_downwards": false }],
|
"cmd-/": ["editor::ToggleComments", { "advance_downwards": false }],
|
||||||
"cmd-u": "editor::UndoSelection",
|
"cmd-u": "editor::UndoSelection",
|
||||||
"cmd-shift-u": "editor::RedoSelection",
|
"cmd-shift-u": "editor::RedoSelection",
|
||||||
"f8": "editor::GoToDiagnostic",
|
"f8": ["editor::GoToDiagnostic", { "severity": { "min": "hint", "max": "error" } }],
|
||||||
"shift-f8": "editor::GoToPreviousDiagnostic",
|
"shift-f8": ["editor::GoToPreviousDiagnostic", { "severity": { "min": "hint", "max": "error" } }],
|
||||||
"f2": "editor::Rename",
|
"f2": "editor::Rename",
|
||||||
"f12": "editor::GoToDefinition",
|
"f12": "editor::GoToDefinition",
|
||||||
"alt-f12": "editor::GoToDefinitionSplit",
|
"alt-f12": "editor::GoToDefinitionSplit",
|
||||||
|
|
|
@ -14,7 +14,10 @@ use indoc::indoc;
|
||||||
use language::{DiagnosticSourceKind, Rope};
|
use language::{DiagnosticSourceKind, Rope};
|
||||||
use lsp::LanguageServerId;
|
use lsp::LanguageServerId;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use project::FakeFs;
|
use project::{
|
||||||
|
FakeFs,
|
||||||
|
project_settings::{GoToDiagnosticSeverity, GoToDiagnosticSeverityFilter},
|
||||||
|
};
|
||||||
use rand::{Rng, rngs::StdRng, seq::IteratorRandom as _};
|
use rand::{Rng, rngs::StdRng, seq::IteratorRandom as _};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
|
@ -1005,7 +1008,7 @@ async fn active_diagnostics_dismiss_after_invalidation(cx: &mut TestAppContext)
|
||||||
cx.run_until_parked();
|
cx.run_until_parked();
|
||||||
|
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_diagnostic(&GoToDiagnostic, window, cx);
|
editor.go_to_diagnostic(&GoToDiagnostic::default(), window, cx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
editor
|
editor
|
||||||
.active_diagnostic_group()
|
.active_diagnostic_group()
|
||||||
|
@ -1047,7 +1050,7 @@ async fn active_diagnostics_dismiss_after_invalidation(cx: &mut TestAppContext)
|
||||||
"});
|
"});
|
||||||
|
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_diagnostic(&GoToDiagnostic, window, cx);
|
editor.go_to_diagnostic(&GoToDiagnostic::default(), window, cx);
|
||||||
assert_eq!(editor.active_diagnostic_group(), None);
|
assert_eq!(editor.active_diagnostic_group(), None);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
|
@ -1126,7 +1129,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// Fourth diagnostic
|
// Fourth diagnostic
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abc def: i32) -> ˇu32 {
|
fn func(abc def: i32) -> ˇu32 {
|
||||||
|
@ -1135,7 +1138,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// Third diagnostic
|
// Third diagnostic
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abc ˇdef: i32) -> u32 {
|
fn func(abc ˇdef: i32) -> u32 {
|
||||||
|
@ -1144,7 +1147,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// Second diagnostic, same place
|
// Second diagnostic, same place
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abc ˇdef: i32) -> u32 {
|
fn func(abc ˇdef: i32) -> u32 {
|
||||||
|
@ -1153,7 +1156,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// First diagnostic
|
// First diagnostic
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abcˇ def: i32) -> u32 {
|
fn func(abcˇ def: i32) -> u32 {
|
||||||
|
@ -1162,7 +1165,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// Wrapped over, fourth diagnostic
|
// Wrapped over, fourth diagnostic
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abc def: i32) -> ˇu32 {
|
fn func(abc def: i32) -> ˇu32 {
|
||||||
|
@ -1181,7 +1184,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// First diagnostic
|
// First diagnostic
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_diagnostic(&GoToDiagnostic, window, cx);
|
editor.go_to_diagnostic(&GoToDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abcˇ def: i32) -> u32 {
|
fn func(abcˇ def: i32) -> u32 {
|
||||||
|
@ -1190,7 +1193,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// Second diagnostic
|
// Second diagnostic
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_diagnostic(&GoToDiagnostic, window, cx);
|
editor.go_to_diagnostic(&GoToDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abc ˇdef: i32) -> u32 {
|
fn func(abc ˇdef: i32) -> u32 {
|
||||||
|
@ -1199,7 +1202,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// Third diagnostic, same place
|
// Third diagnostic, same place
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_diagnostic(&GoToDiagnostic, window, cx);
|
editor.go_to_diagnostic(&GoToDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abc ˇdef: i32) -> u32 {
|
fn func(abc ˇdef: i32) -> u32 {
|
||||||
|
@ -1208,7 +1211,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// Fourth diagnostic
|
// Fourth diagnostic
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_diagnostic(&GoToDiagnostic, window, cx);
|
editor.go_to_diagnostic(&GoToDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abc def: i32) -> ˇu32 {
|
fn func(abc def: i32) -> ˇu32 {
|
||||||
|
@ -1217,7 +1220,7 @@ async fn cycle_through_same_place_diagnostics(cx: &mut TestAppContext) {
|
||||||
|
|
||||||
// Wrapped around, first diagnostic
|
// Wrapped around, first diagnostic
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_diagnostic(&GoToDiagnostic, window, cx);
|
editor.go_to_diagnostic(&GoToDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
fn func(abcˇ def: i32) -> u32 {
|
fn func(abcˇ def: i32) -> u32 {
|
||||||
|
@ -1441,6 +1444,128 @@ async fn test_diagnostics_with_code(cx: &mut TestAppContext) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn go_to_diagnostic_with_severity(cx: &mut TestAppContext) {
|
||||||
|
init_test(cx);
|
||||||
|
|
||||||
|
let mut cx = EditorTestContext::new(cx).await;
|
||||||
|
let lsp_store =
|
||||||
|
cx.update_editor(|editor, _, cx| editor.project.as_ref().unwrap().read(cx).lsp_store());
|
||||||
|
|
||||||
|
cx.set_state(indoc! {"error warning info hiˇnt"});
|
||||||
|
|
||||||
|
cx.update(|_, cx| {
|
||||||
|
lsp_store.update(cx, |lsp_store, cx| {
|
||||||
|
lsp_store
|
||||||
|
.update_diagnostics(
|
||||||
|
LanguageServerId(0),
|
||||||
|
lsp::PublishDiagnosticsParams {
|
||||||
|
uri: lsp::Url::from_file_path(path!("/root/file")).unwrap(),
|
||||||
|
version: None,
|
||||||
|
diagnostics: vec![
|
||||||
|
lsp::Diagnostic {
|
||||||
|
range: lsp::Range::new(
|
||||||
|
lsp::Position::new(0, 0),
|
||||||
|
lsp::Position::new(0, 5),
|
||||||
|
),
|
||||||
|
severity: Some(lsp::DiagnosticSeverity::ERROR),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lsp::Diagnostic {
|
||||||
|
range: lsp::Range::new(
|
||||||
|
lsp::Position::new(0, 6),
|
||||||
|
lsp::Position::new(0, 13),
|
||||||
|
),
|
||||||
|
severity: Some(lsp::DiagnosticSeverity::WARNING),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lsp::Diagnostic {
|
||||||
|
range: lsp::Range::new(
|
||||||
|
lsp::Position::new(0, 14),
|
||||||
|
lsp::Position::new(0, 18),
|
||||||
|
),
|
||||||
|
severity: Some(lsp::DiagnosticSeverity::INFORMATION),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
lsp::Diagnostic {
|
||||||
|
range: lsp::Range::new(
|
||||||
|
lsp::Position::new(0, 19),
|
||||||
|
lsp::Position::new(0, 23),
|
||||||
|
),
|
||||||
|
severity: Some(lsp::DiagnosticSeverity::HINT),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
DiagnosticSourceKind::Pushed,
|
||||||
|
&[],
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
cx.run_until_parked();
|
||||||
|
|
||||||
|
macro_rules! go {
|
||||||
|
($severity:expr) => {
|
||||||
|
cx.update_editor(|editor, window, cx| {
|
||||||
|
editor.go_to_diagnostic(
|
||||||
|
&GoToDiagnostic {
|
||||||
|
severity: $severity,
|
||||||
|
},
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default, should cycle through all diagnostics
|
||||||
|
go!(GoToDiagnosticSeverityFilter::default());
|
||||||
|
cx.assert_editor_state(indoc! {"ˇerror warning info hint"});
|
||||||
|
go!(GoToDiagnosticSeverityFilter::default());
|
||||||
|
cx.assert_editor_state(indoc! {"error ˇwarning info hint"});
|
||||||
|
go!(GoToDiagnosticSeverityFilter::default());
|
||||||
|
cx.assert_editor_state(indoc! {"error warning ˇinfo hint"});
|
||||||
|
go!(GoToDiagnosticSeverityFilter::default());
|
||||||
|
cx.assert_editor_state(indoc! {"error warning info ˇhint"});
|
||||||
|
go!(GoToDiagnosticSeverityFilter::default());
|
||||||
|
cx.assert_editor_state(indoc! {"ˇerror warning info hint"});
|
||||||
|
|
||||||
|
let only_info = GoToDiagnosticSeverityFilter::Only(GoToDiagnosticSeverity::Information);
|
||||||
|
go!(only_info);
|
||||||
|
cx.assert_editor_state(indoc! {"error warning ˇinfo hint"});
|
||||||
|
go!(only_info);
|
||||||
|
cx.assert_editor_state(indoc! {"error warning ˇinfo hint"});
|
||||||
|
|
||||||
|
let no_hints = GoToDiagnosticSeverityFilter::Range {
|
||||||
|
min: GoToDiagnosticSeverity::Information,
|
||||||
|
max: GoToDiagnosticSeverity::Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
go!(no_hints);
|
||||||
|
cx.assert_editor_state(indoc! {"ˇerror warning info hint"});
|
||||||
|
go!(no_hints);
|
||||||
|
cx.assert_editor_state(indoc! {"error ˇwarning info hint"});
|
||||||
|
go!(no_hints);
|
||||||
|
cx.assert_editor_state(indoc! {"error warning ˇinfo hint"});
|
||||||
|
go!(no_hints);
|
||||||
|
cx.assert_editor_state(indoc! {"ˇerror warning info hint"});
|
||||||
|
|
||||||
|
let warning_info = GoToDiagnosticSeverityFilter::Range {
|
||||||
|
min: GoToDiagnosticSeverity::Information,
|
||||||
|
max: GoToDiagnosticSeverity::Warning,
|
||||||
|
};
|
||||||
|
|
||||||
|
go!(warning_info);
|
||||||
|
cx.assert_editor_state(indoc! {"error ˇwarning info hint"});
|
||||||
|
go!(warning_info);
|
||||||
|
cx.assert_editor_state(indoc! {"error warning ˇinfo hint"});
|
||||||
|
go!(warning_info);
|
||||||
|
cx.assert_editor_state(indoc! {"error ˇwarning info hint"});
|
||||||
|
}
|
||||||
|
|
||||||
fn init_test(cx: &mut TestAppContext) {
|
fn init_test(cx: &mut TestAppContext) {
|
||||||
cx.update(|cx| {
|
cx.update(|cx| {
|
||||||
zlog::init_test();
|
zlog::init_test();
|
||||||
|
|
|
@ -6,7 +6,7 @@ use gpui::{
|
||||||
WeakEntity, Window,
|
WeakEntity, Window,
|
||||||
};
|
};
|
||||||
use language::Diagnostic;
|
use language::Diagnostic;
|
||||||
use project::project_settings::ProjectSettings;
|
use project::project_settings::{GoToDiagnosticSeverityFilter, ProjectSettings};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use ui::{Button, ButtonLike, Color, Icon, IconName, Label, Tooltip, h_flex, prelude::*};
|
use ui::{Button, ButtonLike, Color, Icon, IconName, Label, Tooltip, h_flex, prelude::*};
|
||||||
use workspace::{StatusItemView, ToolbarItemEvent, Workspace, item::ItemHandle};
|
use workspace::{StatusItemView, ToolbarItemEvent, Workspace, item::ItemHandle};
|
||||||
|
@ -77,7 +77,7 @@ impl Render for DiagnosticIndicator {
|
||||||
.tooltip(|window, cx| {
|
.tooltip(|window, cx| {
|
||||||
Tooltip::for_action(
|
Tooltip::for_action(
|
||||||
"Next Diagnostic",
|
"Next Diagnostic",
|
||||||
&editor::actions::GoToDiagnostic,
|
&editor::actions::GoToDiagnostic::default(),
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -156,7 +156,12 @@ impl DiagnosticIndicator {
|
||||||
fn go_to_next_diagnostic(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn go_to_next_diagnostic(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
if let Some(editor) = self.active_editor.as_ref().and_then(|e| e.upgrade()) {
|
if let Some(editor) = self.active_editor.as_ref().and_then(|e| e.upgrade()) {
|
||||||
editor.update(cx, |editor, cx| {
|
editor.update(cx, |editor, cx| {
|
||||||
editor.go_to_diagnostic_impl(editor::Direction::Next, window, cx);
|
editor.go_to_diagnostic_impl(
|
||||||
|
editor::Direction::Next,
|
||||||
|
GoToDiagnosticSeverityFilter::default(),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! This module contains all actions supported by [`Editor`].
|
//! This module contains all actions supported by [`Editor`].
|
||||||
use super::*;
|
use super::*;
|
||||||
use gpui::{Action, actions};
|
use gpui::{Action, actions};
|
||||||
|
use project::project_settings::GoToDiagnosticSeverityFilter;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use util::serde::default_true;
|
use util::serde::default_true;
|
||||||
|
|
||||||
|
@ -265,6 +266,24 @@ pub enum UuidVersion {
|
||||||
V7,
|
V7,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Goes to the next diagnostic in the file.
|
||||||
|
#[derive(PartialEq, Clone, Default, Debug, Deserialize, JsonSchema, Action)]
|
||||||
|
#[action(namespace = editor)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct GoToDiagnostic {
|
||||||
|
#[serde(default)]
|
||||||
|
pub severity: GoToDiagnosticSeverityFilter,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Goes to the previous diagnostic in the file.
|
||||||
|
#[derive(PartialEq, Clone, Default, Debug, Deserialize, JsonSchema, Action)]
|
||||||
|
#[action(namespace = editor)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct GoToPreviousDiagnostic {
|
||||||
|
#[serde(default)]
|
||||||
|
pub severity: GoToDiagnosticSeverityFilter,
|
||||||
|
}
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
debugger,
|
debugger,
|
||||||
[
|
[
|
||||||
|
@ -424,8 +443,6 @@ actions!(
|
||||||
GoToDefinition,
|
GoToDefinition,
|
||||||
/// Goes to definition in a split pane.
|
/// Goes to definition in a split pane.
|
||||||
GoToDefinitionSplit,
|
GoToDefinitionSplit,
|
||||||
/// Goes to the next diagnostic in the file.
|
|
||||||
GoToDiagnostic,
|
|
||||||
/// Goes to the next diff hunk.
|
/// Goes to the next diff hunk.
|
||||||
GoToHunk,
|
GoToHunk,
|
||||||
/// Goes to the previous diff hunk.
|
/// Goes to the previous diff hunk.
|
||||||
|
@ -440,8 +457,6 @@ actions!(
|
||||||
GoToParentModule,
|
GoToParentModule,
|
||||||
/// Goes to the previous change in the file.
|
/// Goes to the previous change in the file.
|
||||||
GoToPreviousChange,
|
GoToPreviousChange,
|
||||||
/// Goes to the previous diagnostic in the file.
|
|
||||||
GoToPreviousDiagnostic,
|
|
||||||
/// Goes to the type definition of the symbol at cursor.
|
/// Goes to the type definition of the symbol at cursor.
|
||||||
GoToTypeDefinition,
|
GoToTypeDefinition,
|
||||||
/// Goes to type definition in a split pane.
|
/// Goes to type definition in a split pane.
|
||||||
|
|
|
@ -134,7 +134,7 @@ use project::{
|
||||||
session::{Session, SessionEvent},
|
session::{Session, SessionEvent},
|
||||||
},
|
},
|
||||||
git_store::{GitStoreEvent, RepositoryEvent},
|
git_store::{GitStoreEvent, RepositoryEvent},
|
||||||
project_settings::DiagnosticSeverity,
|
project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use git::blame::BlameRenderer;
|
pub use git::blame::BlameRenderer;
|
||||||
|
@ -15086,7 +15086,7 @@ impl Editor {
|
||||||
|
|
||||||
pub fn go_to_diagnostic(
|
pub fn go_to_diagnostic(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &GoToDiagnostic,
|
action: &GoToDiagnostic,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
|
@ -15094,12 +15094,12 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
|
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
|
||||||
self.go_to_diagnostic_impl(Direction::Next, window, cx)
|
self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn go_to_prev_diagnostic(
|
pub fn go_to_prev_diagnostic(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &GoToPreviousDiagnostic,
|
action: &GoToPreviousDiagnostic,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
|
@ -15107,12 +15107,13 @@ impl Editor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
|
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
|
||||||
self.go_to_diagnostic_impl(Direction::Prev, window, cx)
|
self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn go_to_diagnostic_impl(
|
pub fn go_to_diagnostic_impl(
|
||||||
&mut self,
|
&mut self,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
|
severity: GoToDiagnosticSeverityFilter,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
|
@ -15128,9 +15129,11 @@ impl Editor {
|
||||||
|
|
||||||
fn filtered(
|
fn filtered(
|
||||||
snapshot: EditorSnapshot,
|
snapshot: EditorSnapshot,
|
||||||
|
severity: GoToDiagnosticSeverityFilter,
|
||||||
diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
|
diagnostics: impl Iterator<Item = DiagnosticEntry<usize>>,
|
||||||
) -> impl Iterator<Item = DiagnosticEntry<usize>> {
|
) -> impl Iterator<Item = DiagnosticEntry<usize>> {
|
||||||
diagnostics
|
diagnostics
|
||||||
|
.filter(move |entry| severity.matches(entry.diagnostic.severity))
|
||||||
.filter(|entry| entry.range.start != entry.range.end)
|
.filter(|entry| entry.range.start != entry.range.end)
|
||||||
.filter(|entry| !entry.diagnostic.is_unnecessary)
|
.filter(|entry| !entry.diagnostic.is_unnecessary)
|
||||||
.filter(move |entry| !snapshot.intersects_fold(entry.range.start))
|
.filter(move |entry| !snapshot.intersects_fold(entry.range.start))
|
||||||
|
@ -15139,12 +15142,14 @@ impl Editor {
|
||||||
let snapshot = self.snapshot(window, cx);
|
let snapshot = self.snapshot(window, cx);
|
||||||
let before = filtered(
|
let before = filtered(
|
||||||
snapshot.clone(),
|
snapshot.clone(),
|
||||||
|
severity,
|
||||||
buffer
|
buffer
|
||||||
.diagnostics_in_range(0..selection.start)
|
.diagnostics_in_range(0..selection.start)
|
||||||
.filter(|entry| entry.range.start <= selection.start),
|
.filter(|entry| entry.range.start <= selection.start),
|
||||||
);
|
);
|
||||||
let after = filtered(
|
let after = filtered(
|
||||||
snapshot,
|
snapshot,
|
||||||
|
severity,
|
||||||
buffer
|
buffer
|
||||||
.diagnostics_in_range(selection.start..buffer.len())
|
.diagnostics_in_range(selection.start..buffer.len())
|
||||||
.filter(|entry| entry.range.start >= selection.start),
|
.filter(|entry| entry.range.start >= selection.start),
|
||||||
|
|
|
@ -14734,7 +14734,7 @@ async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mu
|
||||||
executor.run_until_parked();
|
executor.run_until_parked();
|
||||||
|
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
|
@ -14743,7 +14743,7 @@ async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mu
|
||||||
"});
|
"});
|
||||||
|
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
|
@ -14752,7 +14752,7 @@ async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mu
|
||||||
"});
|
"});
|
||||||
|
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
|
@ -14761,7 +14761,7 @@ async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mu
|
||||||
"});
|
"});
|
||||||
|
|
||||||
cx.update_editor(|editor, window, cx| {
|
cx.update_editor(|editor, window, cx| {
|
||||||
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic, window, cx);
|
editor.go_to_prev_diagnostic(&GoToPreviousDiagnostic::default(), window, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.assert_editor_state(indoc! {"
|
cx.assert_editor_state(indoc! {"
|
||||||
|
|
|
@ -326,6 +326,79 @@ impl DiagnosticSeverity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines the severity of the diagnostic that should be moved to.
|
||||||
|
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum GoToDiagnosticSeverity {
|
||||||
|
/// Errors
|
||||||
|
Error = 3,
|
||||||
|
/// Warnings
|
||||||
|
Warning = 2,
|
||||||
|
/// Information
|
||||||
|
Information = 1,
|
||||||
|
/// Hints
|
||||||
|
Hint = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lsp::DiagnosticSeverity> for GoToDiagnosticSeverity {
|
||||||
|
fn from(severity: lsp::DiagnosticSeverity) -> Self {
|
||||||
|
match severity {
|
||||||
|
lsp::DiagnosticSeverity::ERROR => Self::Error,
|
||||||
|
lsp::DiagnosticSeverity::WARNING => Self::Warning,
|
||||||
|
lsp::DiagnosticSeverity::INFORMATION => Self::Information,
|
||||||
|
lsp::DiagnosticSeverity::HINT => Self::Hint,
|
||||||
|
_ => Self::Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GoToDiagnosticSeverity {
|
||||||
|
pub fn min() -> Self {
|
||||||
|
Self::Hint
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max() -> Self {
|
||||||
|
Self::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows filtering diagnostics that should be moved to.
|
||||||
|
#[derive(PartialEq, Clone, Copy, Debug, Deserialize, JsonSchema)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum GoToDiagnosticSeverityFilter {
|
||||||
|
/// Move to diagnostics of a specific severity.
|
||||||
|
Only(GoToDiagnosticSeverity),
|
||||||
|
|
||||||
|
/// Specify a range of severities to include.
|
||||||
|
Range {
|
||||||
|
/// Minimum severity to move to. Defaults no "error".
|
||||||
|
#[serde(default = "GoToDiagnosticSeverity::min")]
|
||||||
|
min: GoToDiagnosticSeverity,
|
||||||
|
/// Maximum severity to move to. Defaults to "hint".
|
||||||
|
#[serde(default = "GoToDiagnosticSeverity::max")]
|
||||||
|
max: GoToDiagnosticSeverity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for GoToDiagnosticSeverityFilter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Range {
|
||||||
|
min: GoToDiagnosticSeverity::min(),
|
||||||
|
max: GoToDiagnosticSeverity::max(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GoToDiagnosticSeverityFilter {
|
||||||
|
pub fn matches(&self, severity: lsp::DiagnosticSeverity) -> bool {
|
||||||
|
let severity: GoToDiagnosticSeverity = severity.into();
|
||||||
|
match self {
|
||||||
|
Self::Only(target) => *target == severity,
|
||||||
|
Self::Range { min, max } => severity >= *min && severity <= *max,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct GitSettings {
|
pub struct GitSettings {
|
||||||
/// Whether or not to show the git gutter.
|
/// Whether or not to show the git gutter.
|
||||||
|
|
|
@ -33,6 +33,7 @@ use project::{
|
||||||
Entry, EntryKind, Fs, GitEntry, GitEntryRef, GitTraversal, Project, ProjectEntryId,
|
Entry, EntryKind, Fs, GitEntry, GitEntryRef, GitTraversal, Project, ProjectEntryId,
|
||||||
ProjectPath, Worktree, WorktreeId,
|
ProjectPath, Worktree, WorktreeId,
|
||||||
git_store::{GitStoreEvent, git_traversal::ChildEntriesGitIter},
|
git_store::{GitStoreEvent, git_traversal::ChildEntriesGitIter},
|
||||||
|
project_settings::GoToDiagnosticSeverityFilter,
|
||||||
relativize_path,
|
relativize_path,
|
||||||
};
|
};
|
||||||
use project_panel_settings::{
|
use project_panel_settings::{
|
||||||
|
@ -206,6 +207,24 @@ struct Trash {
|
||||||
pub skip_prompt: bool,
|
pub skip_prompt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Selects the next entry with diagnostics.
|
||||||
|
#[derive(PartialEq, Clone, Default, Debug, Deserialize, JsonSchema, Action)]
|
||||||
|
#[action(namespace = project_panel)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
struct SelectNextDiagnostic {
|
||||||
|
#[serde(default)]
|
||||||
|
pub severity: GoToDiagnosticSeverityFilter,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Selects the previous entry with diagnostics.
|
||||||
|
#[derive(PartialEq, Clone, Default, Debug, Deserialize, JsonSchema, Action)]
|
||||||
|
#[action(namespace = project_panel)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
struct SelectPrevDiagnostic {
|
||||||
|
#[serde(default)]
|
||||||
|
pub severity: GoToDiagnosticSeverityFilter,
|
||||||
|
}
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
project_panel,
|
project_panel,
|
||||||
[
|
[
|
||||||
|
@ -255,10 +274,6 @@ actions!(
|
||||||
SelectNextGitEntry,
|
SelectNextGitEntry,
|
||||||
/// Selects the previous entry with git changes.
|
/// Selects the previous entry with git changes.
|
||||||
SelectPrevGitEntry,
|
SelectPrevGitEntry,
|
||||||
/// Selects the next entry with diagnostics.
|
|
||||||
SelectNextDiagnostic,
|
|
||||||
/// Selects the previous entry with diagnostics.
|
|
||||||
SelectPrevDiagnostic,
|
|
||||||
/// Selects the next directory.
|
/// Selects the next directory.
|
||||||
SelectNextDirectory,
|
SelectNextDirectory,
|
||||||
/// Selects the previous directory.
|
/// Selects the previous directory.
|
||||||
|
@ -1954,7 +1969,7 @@ impl ProjectPanel {
|
||||||
|
|
||||||
fn select_prev_diagnostic(
|
fn select_prev_diagnostic(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &SelectPrevDiagnostic,
|
action: &SelectPrevDiagnostic,
|
||||||
_: &mut Window,
|
_: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
|
@ -1973,7 +1988,8 @@ impl ProjectPanel {
|
||||||
&& entry.is_file()
|
&& entry.is_file()
|
||||||
&& self
|
&& self
|
||||||
.diagnostics
|
.diagnostics
|
||||||
.contains_key(&(worktree_id, entry.path.to_path_buf()))
|
.get(&(worktree_id, entry.path.to_path_buf()))
|
||||||
|
.is_some_and(|severity| action.severity.matches(*severity))
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
@ -1989,7 +2005,7 @@ impl ProjectPanel {
|
||||||
|
|
||||||
fn select_next_diagnostic(
|
fn select_next_diagnostic(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: &SelectNextDiagnostic,
|
action: &SelectNextDiagnostic,
|
||||||
_: &mut Window,
|
_: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
|
@ -2008,7 +2024,8 @@ impl ProjectPanel {
|
||||||
&& entry.is_file()
|
&& entry.is_file()
|
||||||
&& self
|
&& self
|
||||||
.diagnostics
|
.diagnostics
|
||||||
.contains_key(&(worktree_id, entry.path.to_path_buf()))
|
.get(&(worktree_id, entry.path.to_path_buf()))
|
||||||
|
.is_some_and(|severity| action.severity.matches(*severity))
|
||||||
},
|
},
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1106,13 +1106,28 @@ fn generate_commands(_: &App) -> Vec<VimCommand> {
|
||||||
VimCommand::str(("cl", "ist"), "diagnostics::Deploy"),
|
VimCommand::str(("cl", "ist"), "diagnostics::Deploy"),
|
||||||
VimCommand::new(("cc", ""), editor::actions::Hover),
|
VimCommand::new(("cc", ""), editor::actions::Hover),
|
||||||
VimCommand::new(("ll", ""), editor::actions::Hover),
|
VimCommand::new(("ll", ""), editor::actions::Hover),
|
||||||
VimCommand::new(("cn", "ext"), editor::actions::GoToDiagnostic).range(wrap_count),
|
VimCommand::new(("cn", "ext"), editor::actions::GoToDiagnostic::default())
|
||||||
VimCommand::new(("cp", "revious"), editor::actions::GoToPreviousDiagnostic)
|
|
||||||
.range(wrap_count),
|
.range(wrap_count),
|
||||||
VimCommand::new(("cN", "ext"), editor::actions::GoToPreviousDiagnostic).range(wrap_count),
|
VimCommand::new(
|
||||||
VimCommand::new(("lp", "revious"), editor::actions::GoToPreviousDiagnostic)
|
("cp", "revious"),
|
||||||
|
editor::actions::GoToPreviousDiagnostic::default(),
|
||||||
|
)
|
||||||
|
.range(wrap_count),
|
||||||
|
VimCommand::new(
|
||||||
|
("cN", "ext"),
|
||||||
|
editor::actions::GoToPreviousDiagnostic::default(),
|
||||||
|
)
|
||||||
|
.range(wrap_count),
|
||||||
|
VimCommand::new(
|
||||||
|
("lp", "revious"),
|
||||||
|
editor::actions::GoToPreviousDiagnostic::default(),
|
||||||
|
)
|
||||||
|
.range(wrap_count),
|
||||||
|
VimCommand::new(
|
||||||
|
("lN", "ext"),
|
||||||
|
editor::actions::GoToPreviousDiagnostic::default(),
|
||||||
|
)
|
||||||
.range(wrap_count),
|
.range(wrap_count),
|
||||||
VimCommand::new(("lN", "ext"), editor::actions::GoToPreviousDiagnostic).range(wrap_count),
|
|
||||||
VimCommand::new(("j", "oin"), JoinLines).range(select_range),
|
VimCommand::new(("j", "oin"), JoinLines).range(select_range),
|
||||||
VimCommand::new(("fo", "ld"), editor::actions::FoldSelectedRanges).range(act_on_range),
|
VimCommand::new(("fo", "ld"), editor::actions::FoldSelectedRanges).range(act_on_range),
|
||||||
VimCommand::new(("foldo", "pen"), editor::actions::UnfoldLines)
|
VimCommand::new(("foldo", "pen"), editor::actions::UnfoldLines)
|
||||||
|
|
|
@ -199,8 +199,11 @@ pub fn app_menus() -> Vec<Menu> {
|
||||||
MenuItem::action("Go to Type Definition", editor::actions::GoToTypeDefinition),
|
MenuItem::action("Go to Type Definition", editor::actions::GoToTypeDefinition),
|
||||||
MenuItem::action("Find All References", editor::actions::FindAllReferences),
|
MenuItem::action("Find All References", editor::actions::FindAllReferences),
|
||||||
MenuItem::separator(),
|
MenuItem::separator(),
|
||||||
MenuItem::action("Next Problem", editor::actions::GoToDiagnostic),
|
MenuItem::action("Next Problem", editor::actions::GoToDiagnostic::default()),
|
||||||
MenuItem::action("Previous Problem", editor::actions::GoToPreviousDiagnostic),
|
MenuItem::action(
|
||||||
|
"Previous Problem",
|
||||||
|
editor::actions::GoToPreviousDiagnostic::default(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Menu {
|
Menu {
|
||||||
|
|
|
@ -255,8 +255,11 @@ impl Render for QuickActionBar {
|
||||||
.action("Go to Symbol", Box::new(ToggleOutline))
|
.action("Go to Symbol", Box::new(ToggleOutline))
|
||||||
.action("Go to Line/Column", Box::new(ToggleGoToLine))
|
.action("Go to Line/Column", Box::new(ToggleGoToLine))
|
||||||
.separator()
|
.separator()
|
||||||
.action("Next Problem", Box::new(GoToDiagnostic))
|
.action("Next Problem", Box::new(GoToDiagnostic::default()))
|
||||||
.action("Previous Problem", Box::new(GoToPreviousDiagnostic))
|
.action(
|
||||||
|
"Previous Problem",
|
||||||
|
Box::new(GoToPreviousDiagnostic::default()),
|
||||||
|
)
|
||||||
.separator()
|
.separator()
|
||||||
.action_disabled_when(!has_diff_hunks, "Next Hunk", Box::new(GoToHunk))
|
.action_disabled_when(!has_diff_hunks, "Next Hunk", Box::new(GoToHunk))
|
||||||
.action_disabled_when(
|
.action_disabled_when(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue