diagnostics: Show info count in status bar when include_warnings is true

This commit is contained in:
Oliver Azevedo Barnes 2026-03-25 18:34:29 +00:00
parent 91c703f3ca
commit 08d7f93140
No known key found for this signature in database
11 changed files with 165 additions and 6 deletions

View file

@ -156,6 +156,7 @@ CREATE TABLE "worktree_diagnostic_summaries" (
"language_server_id" INTEGER NOT NULL,
"error_count" INTEGER NOT NULL,
"warning_count" INTEGER NOT NULL,
"info_count" INTEGER NOT NULL,
PRIMARY KEY (project_id, worktree_id, path),
FOREIGN KEY (project_id, worktree_id) REFERENCES worktrees (project_id, id) ON DELETE CASCADE
);

View file

@ -443,7 +443,8 @@ CREATE TABLE public.worktree_diagnostic_summaries (
path character varying NOT NULL,
language_server_id bigint NOT NULL,
error_count integer NOT NULL,
warning_count integer NOT NULL
warning_count integer NOT NULL,
info_count integer NOT NULL
);
CREATE TABLE public.worktree_entries (

View file

@ -530,6 +530,7 @@ impl Database {
language_server_id: ActiveValue::set(summary.language_server_id as i64),
error_count: ActiveValue::set(summary.error_count as i32),
warning_count: ActiveValue::set(summary.warning_count as i32),
info_count: ActiveValue::set(summary.info_count as i32),
})
.on_conflict(
OnConflict::columns([
@ -541,6 +542,7 @@ impl Database {
worktree_diagnostic_summary::Column::LanguageServerId,
worktree_diagnostic_summary::Column::ErrorCount,
worktree_diagnostic_summary::Column::WarningCount,
worktree_diagnostic_summary::Column::InfoCount,
])
.to_owned(),
)
@ -913,6 +915,7 @@ impl Database {
language_server_id: db_summary.language_server_id as u64,
error_count: db_summary.error_count as u32,
warning_count: db_summary.warning_count as u32,
info_count: db_summary.info_count as u32,
});
}
}

View file

@ -13,6 +13,7 @@ pub struct Model {
pub language_server_id: i64,
pub error_count: i32,
pub warning_count: i32,
pub info_count: i32,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View file

@ -4128,6 +4128,7 @@ async fn test_collaborating_with_diagnostics(
DiagnosticSummary {
error_count: 1,
warning_count: 0,
info_count: 0,
},
)]
)
@ -4164,6 +4165,7 @@ async fn test_collaborating_with_diagnostics(
DiagnosticSummary {
error_count: 1,
warning_count: 0,
info_count: 0,
},
)]
);
@ -4205,6 +4207,7 @@ async fn test_collaborating_with_diagnostics(
DiagnosticSummary {
error_count: 1,
warning_count: 1,
info_count: 0,
},
)]
);
@ -4222,6 +4225,7 @@ async fn test_collaborating_with_diagnostics(
DiagnosticSummary {
error_count: 1,
warning_count: 1,
info_count: 0,
},
)]
);

View file

@ -2023,7 +2023,8 @@ async fn test_buffer_diagnostics_multiple_servers(cx: &mut TestAppContext) {
*buffer_diagnostics.summary(),
DiagnosticSummary {
warning_count: 2,
error_count: 0
error_count: 0,
info_count: 0,
}
);
})

View file

@ -33,8 +33,9 @@ impl Render for DiagnosticIndicator {
return indicator.hidden();
}
let include_warnings = ProjectSettings::get_global(cx).diagnostics.include_warnings;
let diagnostic_indicator = match (self.summary.error_count, self.summary.warning_count) {
(0, 0) => h_flex().child(
(0, 0) if !include_warnings || self.summary.info_count == 0 => h_flex().child(
Icon::new(IconName::Check)
.size(IconSize::Small)
.color(Color::Default),
@ -56,6 +57,14 @@ impl Render for DiagnosticIndicator {
.color(Color::Warning),
)
.child(Label::new(warning_count.to_string()).size(LabelSize::Small))
})
.when(self.summary.info_count > 0 && include_warnings, |this| {
this.child(
Icon::new(IconName::Info)
.size(IconSize::Small)
.color(Color::Info),
)
.child(Label::new(self.summary.info_count.to_string()).size(LabelSize::Small))
}),
};

View file

@ -7807,6 +7807,7 @@ impl LspStore {
for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
summary.error_count += path_summary.error_count;
summary.warning_count += path_summary.warning_count;
summary.info_count += path_summary.info_count;
}
summary
}
@ -7822,12 +7823,13 @@ impl LspStore {
.get(&project_path.worktree_id)
.and_then(|map| map.get(&project_path.path))
{
let (error_count, warning_count) = summaries.iter().fold(
(0, 0),
|(error_count, warning_count), (_language_server_id, summary)| {
let (error_count, warning_count, info_count) = summaries.iter().fold(
(0, 0, 0),
|(error_count, warning_count, info_count), (_language_server_id, summary)| {
(
error_count + summary.error_count,
warning_count + summary.warning_count,
info_count + summary.info_count,
)
},
);
@ -7835,6 +7837,7 @@ impl LspStore {
DiagnosticSummary {
error_count,
warning_count,
info_count,
}
} else {
DiagnosticSummary::default()
@ -8227,6 +8230,7 @@ impl LspStore {
language_server_id: server_id.0 as u64,
error_count: 0,
warning_count: 0,
info_count: 0,
}),
more_summaries: Vec::new(),
})
@ -8476,6 +8480,7 @@ impl LspStore {
language_server_id: server_id.0 as u64,
error_count: new_summary.error_count,
warning_count: new_summary.warning_count,
info_count: new_summary.info_count,
})
}
None => {
@ -8487,6 +8492,7 @@ impl LspStore {
language_server_id: server_id.0 as u64,
error_count: new_summary.error_count,
warning_count: new_summary.warning_count,
info_count: new_summary.info_count,
}),
more_summaries: Vec::new(),
})
@ -8571,6 +8577,7 @@ impl LspStore {
language_server_id: server_id.0 as u64,
error_count: new_summary.error_count as u32,
warning_count: new_summary.warning_count as u32,
info_count: new_summary.info_count as u32,
},
))))
} else {
@ -9433,6 +9440,7 @@ impl LspStore {
let summary = DiagnosticSummary {
error_count: message_summary.error_count as usize,
warning_count: message_summary.warning_count as usize,
info_count: message_summary.info_count as usize,
};
if summary.is_empty() {
@ -9465,6 +9473,7 @@ impl LspStore {
language_server_id: server_id.0 as u64,
error_count: summary.error_count as u32,
warning_count: summary.warning_count as u32,
info_count: summary.info_count as u32,
})
}
None => {
@ -9476,6 +9485,7 @@ impl LspStore {
language_server_id: server_id.0 as u64,
error_count: summary.error_count as u32,
warning_count: summary.warning_count as u32,
info_count: summary.info_count as u32,
}),
more_summaries: Vec::new(),
})
@ -10925,6 +10935,7 @@ impl LspStore {
language_server_id: server_id.0 as u64,
error_count: 0,
warning_count: 0,
info_count: 0,
}),
more_summaries: Vec::new(),
})
@ -13970,6 +13981,7 @@ pub struct LanguageServerProgress {
pub struct DiagnosticSummary {
pub error_count: usize,
pub warning_count: usize,
pub info_count: usize,
}
impl DiagnosticSummary {
@ -13977,6 +13989,7 @@ impl DiagnosticSummary {
let mut this = Self {
error_count: 0,
warning_count: 0,
info_count: 0,
};
for entry in diagnostics {
@ -13984,6 +13997,7 @@ impl DiagnosticSummary {
match entry.diagnostic.severity {
DiagnosticSeverity::ERROR => this.error_count += 1,
DiagnosticSeverity::WARNING => this.warning_count += 1,
DiagnosticSeverity::INFORMATION => this.info_count += 1,
_ => {}
}
}
@ -14006,6 +14020,7 @@ impl DiagnosticSummary {
language_server_id: language_server_id.0 as u64,
error_count: self.error_count as u32,
warning_count: self.warning_count as u32,
info_count: self.info_count as u32,
}
}
}

View file

@ -2700,6 +2700,7 @@ async fn test_omitted_diagnostics(cx: &mut gpui::TestAppContext) {
DiagnosticSummary {
error_count: 1,
warning_count: 0,
info_count: 0,
}
)]
);
@ -2996,6 +2997,7 @@ async fn test_restarting_server_with_diagnostics_published(cx: &mut gpui::TestAp
DiagnosticSummary {
error_count: 1,
warning_count: 0,
info_count: 0,
}
);
});
@ -3022,6 +3024,7 @@ async fn test_restarting_server_with_diagnostics_published(cx: &mut gpui::TestAp
DiagnosticSummary {
error_count: 0,
warning_count: 0,
info_count: 0,
}
);
});
@ -3683,6 +3686,7 @@ async fn test_diagnostics_from_multiple_language_servers(cx: &mut gpui::TestAppC
DiagnosticSummary {
error_count: 2,
warning_count: 0,
info_count: 0,
}
);
});
@ -3746,6 +3750,7 @@ async fn test_diagnostic_summaries_cleared_on_worktree_entry_removal(
DiagnosticSummary {
error_count: 1,
warning_count: 1,
info_count: 0,
}
);
});
@ -3761,6 +3766,7 @@ async fn test_diagnostic_summaries_cleared_on_worktree_entry_removal(
DiagnosticSummary {
error_count: 0,
warning_count: 1,
info_count: 0,
},
);
});
@ -3805,6 +3811,7 @@ async fn test_diagnostic_summaries_cleared_on_server_restart(cx: &mut gpui::Test
DiagnosticSummary {
error_count: 1,
warning_count: 0,
info_count: 0,
}
);
});
@ -3835,6 +3842,7 @@ async fn test_diagnostic_summaries_cleared_on_server_restart(cx: &mut gpui::Test
DiagnosticSummary {
error_count: 0,
warning_count: 0,
info_count: 0,
}
);
});
@ -3924,6 +3932,7 @@ async fn test_diagnostic_summaries_cleared_on_buffer_reload(cx: &mut gpui::TestA
DiagnosticSummary {
error_count: 1,
warning_count: 0,
info_count: 0,
}
);
});

View file

@ -562,6 +562,7 @@ message DiagnosticSummary {
uint64 language_server_id = 2;
uint32 error_count = 3;
uint32 warning_count = 4;
uint32 info_count = 5;
}
message UpdateLanguageServer {

View file

@ -0,0 +1,114 @@
# Plan: Show `info_count` in the Status Bar
The goal is consistency: the status bar should reflect what the diagnostics panel
shows. When `include_warnings` is true the panel now shows errors, warnings, and
info-level diagnostics, so the status bar counter should too.
No new icons, toolbar buttons, or actions. The `include_warnings` setting name
stays the same. Changes touch six areas.
---
## 1. Extend `DiagnosticSummary``crates/project/src/lsp_store.rs`
**Struct** — add `pub info_count: usize`.
**`DiagnosticSummary::new()`** — add an arm to the severity match:
```rust
DiagnosticSeverity::INFORMATION => this.info_count += 1,
```
**`is_empty()`** — no change. It gates the checkmark icon ("no errors or
warnings"). An info-only workspace still showing the checkmark is acceptable.
**`diagnostic_summary()`** — add `summary.info_count += path_summary.info_count`
alongside the existing error/warning accumulation.
**`diagnostic_summary_for_path()`** — expand the fold from a 2-tuple to a 3-tuple
`(error_count, warning_count, info_count)` and include it in the returned struct.
**`to_proto()`** — add `info_count: self.info_count as u32`.
---
## 2. Extend the proto message — `crates/proto/proto/lsp.proto`
Add a new field to `message DiagnosticSummary`:
```proto
uint32 info_count = 5;
```
Protobuf field ordering means old clients silently ignore the new field, so this
is backward-compatible. No DB schema or migration change is needed — diagnostics
are not persisted in the collab database.
After updating the schema, run the repo's normal proto regeneration/build path so
the Rust bindings for `proto::DiagnosticSummary` pick up the new field. Also keep
the proto change Buf-clean (`buf lint` / `buf format`) so CI passes.
---
## 3. Propagate `info_count` through proto serialization — `crates/project/src/lsp_store.rs`
Every site in `lsp_store.rs` that constructs `proto::DiagnosticSummary { ...,
error_count, warning_count }` needs `info_count` added as well.
Every site in `lsp_store.rs` that deserializes a proto message back into
`DiagnosticSummary { error_count, warning_count }` needs
`info_count: message_summary.info_count as usize`.
---
## 4. Show `info_count` in the status bar — `crates/diagnostics/src/items.rs`
In `render()`, keep the outer checkmark-vs-counts decision based on
`error_count` and `warning_count` only, so an info-only workspace still renders
the checkmark. Within the existing non-checkmark branch, after the existing
`.when(warning_count > 0, ...)` child, add:
```rust
let include_warnings = ProjectSettings::get_global(cx).diagnostics.include_warnings;
// ...
.when(self.summary.info_count > 0 && include_warnings, |this| {
this.child(
Icon::new(IconName::Info)
.size(IconSize::Small)
.color(Color::Info),
)
.child(Label::new(self.summary.info_count.to_string()).size(LabelSize::Small))
})
```
`IconName::Info` and `Color::Info` already exist and are used elsewhere; no new
icons are introduced.
The auto-enable logic in the `on_click` handler (which sets `include_warnings =
true` when the user clicks the status bar with errors = 0 and warnings > 0) does
not need to change — info-only scenarios are rare and can be handled in a follow-up.
---
## 5. Fix the collab integration test — `crates/collab/tests/integration/integration_tests.rs`
`test_collaborating_with_diagnostics` constructs `DiagnosticSummary` literals.
Add `info_count: 0` to each, or derive `Default` on the struct and use
`..Default::default()` struct-update syntax.
---
## 6. Fix the diagnostics unit test — `crates/diagnostics/src/diagnostics_tests.rs`
`test_buffer_diagnostics_multiple_servers` asserts on `*buffer_diagnostics.summary()`
using a `DiagnosticSummary` literal. Add `info_count: 0` there too.
---
## Summary of files touched
| File | Change |
|------|--------|
| `crates/project/src/lsp_store.rs` | Add `info_count` to struct, `new()`, `is_empty()` (no-op), `diagnostic_summary()`, `diagnostic_summary_for_path()`, `to_proto()`, and all proto construction/deserialization sites |
| `crates/proto/proto/lsp.proto` | Add `uint32 info_count = 5` to `DiagnosticSummary` message and regenerate/build the Rust bindings as required by the repo's proto pipeline |
| `crates/diagnostics/src/items.rs` | Render `info_count` in status bar when `include_warnings` is true |
| `crates/collab/tests/integration/integration_tests.rs` | Add `info_count: 0` to `DiagnosticSummary` literals |
| `crates/diagnostics/src/diagnostics_tests.rs` | Add `info_count: 0` to `DiagnosticSummary` literal |