@@ -18,8 +18,29 @@ use crate::{DocumentSnapshot, PositionEncoding};
1818
1919use super :: LSPResult ;
2020
21- /// A series of diagnostics across a single text document or an arbitrary number of notebook cells.
22- pub ( super ) type DiagnosticsMap = FxHashMap < Url , Vec < Diagnostic > > ;
21+ /// Represents the diagnostics for a text document or a notebook document.
22+ pub ( super ) enum Diagnostics {
23+ TextDocument ( Vec < Diagnostic > ) ,
24+
25+ /// A map of cell URLs to the diagnostics for that cell.
26+ NotebookDocument ( FxHashMap < Url , Vec < Diagnostic > > ) ,
27+ }
28+
29+ impl Diagnostics {
30+ /// Returns the diagnostics for a text document.
31+ ///
32+ /// # Panics
33+ ///
34+ /// Panics if the diagnostics are for a notebook document.
35+ pub ( super ) fn expect_text_document ( self ) -> Vec < Diagnostic > {
36+ match self {
37+ Diagnostics :: TextDocument ( diagnostics) => diagnostics,
38+ Diagnostics :: NotebookDocument ( _) => {
39+ panic ! ( "Expected a text document diagnostics, but got notebook diagnostics" )
40+ }
41+ }
42+ }
43+ }
2344
2445/// Clears the diagnostics for the document at `uri`.
2546///
@@ -44,14 +65,29 @@ pub(super) fn publish_diagnostics_for_document(
4465 snapshot : & DocumentSnapshot ,
4566 notifier : & Notifier ,
4667) -> Result < ( ) > {
47- for ( uri, diagnostics) in compute_diagnostics ( db, snapshot) {
68+ let Some ( diagnostics) = compute_diagnostics ( db, snapshot) else {
69+ return Ok ( ( ) ) ;
70+ } ;
71+
72+ let publish_diagnostics = |uri : Url , diagnostics : Vec < Diagnostic > | {
4873 notifier
4974 . notify :: < PublishDiagnostics > ( PublishDiagnosticsParams {
5075 uri,
5176 diagnostics,
5277 version : Some ( snapshot. query ( ) . version ( ) ) ,
5378 } )
54- . with_failure_code ( lsp_server:: ErrorCode :: InternalError ) ?;
79+ . with_failure_code ( lsp_server:: ErrorCode :: InternalError )
80+ } ;
81+
82+ match diagnostics {
83+ Diagnostics :: TextDocument ( diagnostics) => {
84+ publish_diagnostics ( snapshot. query ( ) . file_url ( ) . clone ( ) , diagnostics) ?;
85+ }
86+ Diagnostics :: NotebookDocument ( map) => {
87+ for ( cell_url, diagnostics) in map {
88+ publish_diagnostics ( cell_url, diagnostics) ?;
89+ }
90+ }
5591 }
5692
5793 Ok ( ( ) )
@@ -60,66 +96,60 @@ pub(super) fn publish_diagnostics_for_document(
6096pub ( super ) fn compute_diagnostics (
6197 db : & ProjectDatabase ,
6298 snapshot : & DocumentSnapshot ,
63- ) -> DiagnosticsMap {
99+ ) -> Option < Diagnostics > {
64100 let Some ( file) = snapshot. file ( db) else {
65101 tracing:: info!(
66102 "No file found for snapshot for `{}`" ,
67103 snapshot. query( ) . file_url( )
68104 ) ;
69- return DiagnosticsMap :: default ( ) ;
105+ return None ;
70106 } ;
71107
72108 let diagnostics = match db. check_file ( file) {
73109 Ok ( diagnostics) => diagnostics,
74110 Err ( cancelled) => {
75111 tracing:: info!( "Diagnostics computation {cancelled}" ) ;
76- return DiagnosticsMap :: default ( ) ;
112+ return None ;
77113 }
78114 } ;
79115
80- let mut diagnostics_map = DiagnosticsMap :: default ( ) ;
81116 let query = snapshot. query ( ) ;
82- // let source_kind = query.make_source_kind();
83117
84- // Populates all relevant URLs with an empty diagnostic list.
85- // This ensures that documents without diagnostics still get updated.
86118 if let Some ( notebook) = query. as_notebook ( ) {
87- for url in notebook. urls ( ) {
88- diagnostics_map. entry ( url. clone ( ) ) . or_default ( ) ;
89- }
90- } else {
91- diagnostics_map
92- . entry ( query. make_key ( ) . into_url ( ) )
93- . or_default ( ) ;
94- }
119+ let mut cell_diagnostics: FxHashMap < Url , Vec < Diagnostic > > = FxHashMap :: default ( ) ;
95120
96- let lsp_diagnostics = diagnostics. as_slice ( ) . iter ( ) . map ( |diagnostic| {
97- (
98- // TODO: Use the cell index instead using `source_kind`
99- usize:: default ( ) ,
100- to_lsp_diagnostic ( db, diagnostic, snapshot. encoding ( ) ) ,
101- )
102- } ) ;
121+ // Populates all relevant URLs with an empty diagnostic list. This ensures that documents
122+ // without diagnostics still get updated.
123+ for cell_url in notebook. cell_urls ( ) {
124+ cell_diagnostics. entry ( cell_url. clone ( ) ) . or_default ( ) ;
125+ }
103126
104- if let Some ( notebook) = query. as_notebook ( ) {
105- for ( index, diagnostic) in lsp_diagnostics {
106- let Some ( uri) = notebook. cell_uri_by_index ( index) else {
107- tracing:: warn!( "Unable to find notebook cell at index {index}" ) ;
127+ for ( cell_index, diagnostic) in diagnostics. iter ( ) . map ( |diagnostic| {
128+ (
129+ // TODO: Use the cell index instead using `SourceKind`
130+ usize:: default ( ) ,
131+ to_lsp_diagnostic ( db, diagnostic, snapshot. encoding ( ) ) ,
132+ )
133+ } ) {
134+ let Some ( cell_uri) = notebook. cell_uri_by_index ( cell_index) else {
135+ tracing:: warn!( "Unable to find notebook cell at index {cell_index}" ) ;
108136 continue ;
109137 } ;
110- diagnostics_map
111- . entry ( uri . clone ( ) )
138+ cell_diagnostics
139+ . entry ( cell_uri . clone ( ) )
112140 . or_default ( )
113141 . push ( diagnostic) ;
114142 }
143+
144+ Some ( Diagnostics :: NotebookDocument ( cell_diagnostics) )
115145 } else {
116- diagnostics_map
117- . entry ( query. make_key ( ) . into_url ( ) )
118- . or_default ( )
119- . extend ( lsp_diagnostics. map ( |( _, diagnostic) | diagnostic) ) ;
146+ Some ( Diagnostics :: TextDocument (
147+ diagnostics
148+ . iter ( )
149+ . map ( |diagnostic| to_lsp_diagnostic ( db, diagnostic, snapshot. encoding ( ) ) )
150+ . collect ( ) ,
151+ ) )
120152 }
121-
122- diagnostics_map
123153}
124154
125155/// Converts the tool specific [`Diagnostic`][ruff_db::diagnostic::Diagnostic] to an LSP
0 commit comments