1
- use std:: collections:: HashMap ;
1
+ use std:: collections:: { HashMap , HashSet } ;
2
2
use std:: time:: Duration ;
3
3
4
4
use helix_core:: syntax:: LanguageServerFeature ;
@@ -7,11 +7,13 @@ use helix_event::{register_hook, send_blocking};
7
7
use helix_lsp:: lsp:: { self , Diagnostic } ;
8
8
use helix_lsp:: LanguageServerId ;
9
9
use helix_view:: document:: Mode ;
10
- use helix_view:: events:: { DiagnosticsDidChange , DocumentDidChange } ;
10
+ use helix_view:: events:: { DiagnosticsDidChange , DocumentDidChange , DocumentDidOpen } ;
11
11
use helix_view:: handlers:: diagnostics:: DiagnosticEvent ;
12
- use helix_view:: handlers:: lsp:: PullDiagnosticsEvent ;
12
+ use helix_view:: handlers:: lsp:: {
13
+ PullDiagnosticsForDocumentsEvent , PullDiagnosticsForLanguageServersEvent ,
14
+ } ;
13
15
use helix_view:: handlers:: Handlers ;
14
- use helix_view:: Editor ;
16
+ use helix_view:: { DocumentId , Editor } ;
15
17
use tokio:: time:: Instant ;
16
18
17
19
use crate :: events:: OnModeSwitch ;
@@ -33,7 +35,7 @@ pub(super) fn register_hooks(handlers: &Handlers) {
33
35
Ok ( ( ) )
34
36
} ) ;
35
37
36
- let tx = handlers. pull_diagnostics . clone ( ) ;
38
+ let tx = handlers. pull_diagnostics_for_language_servers . clone ( ) ;
37
39
register_hook ! ( move |event: & mut DocumentDidChange <' _>| {
38
40
if event
39
41
. doc
@@ -47,117 +49,179 @@ pub(super) fn register_hooks(handlers: &Handlers) {
47
49
48
50
send_blocking(
49
51
& tx,
50
- PullDiagnosticsEvent {
52
+ PullDiagnosticsForLanguageServersEvent {
51
53
language_server_ids,
52
54
} ,
53
55
) ;
54
56
}
55
57
Ok ( ( ) )
56
58
} ) ;
57
- }
58
59
59
- const TIMEOUT : u64 = 120 ;
60
+ let tx = handlers. pull_diagnostics_for_documents . clone ( ) ;
61
+ register_hook ! ( move |event: & mut DocumentDidOpen <' _>| {
62
+ if event
63
+ . doc
64
+ . has_language_server_with_feature( LanguageServerFeature :: PullDiagnostics )
65
+ {
66
+ send_blocking(
67
+ & tx,
68
+ PullDiagnosticsForDocumentsEvent {
69
+ document_id: event. doc. id( ) ,
70
+ } ,
71
+ ) ;
72
+ }
73
+
74
+ Ok ( ( ) )
75
+ } ) ;
76
+ }
60
77
61
78
#[ derive( Debug ) ]
62
- pub ( super ) struct PullDiagnosticsHandler {
63
- language_server_ids : Vec < LanguageServerId > ,
79
+ pub ( super ) struct PullDiagnosticsForLanguageServersHandler {
80
+ language_server_ids : HashSet < LanguageServerId > ,
64
81
}
65
82
66
- impl PullDiagnosticsHandler {
67
- pub fn new ( ) -> PullDiagnosticsHandler {
68
- PullDiagnosticsHandler {
69
- language_server_ids : vec ! [ ] ,
83
+ impl PullDiagnosticsForLanguageServersHandler {
84
+ pub fn new ( ) -> PullDiagnosticsForLanguageServersHandler {
85
+ PullDiagnosticsForLanguageServersHandler {
86
+ language_server_ids : [ ] . into ( ) ,
70
87
}
71
88
}
72
89
}
90
+ pub ( super ) struct PullDiagnosticsForDocumentsHandler {
91
+ document_ids : HashSet < DocumentId > ,
92
+ }
73
93
74
- impl helix_event:: AsyncHook for PullDiagnosticsHandler {
75
- type Event = PullDiagnosticsEvent ;
94
+ impl PullDiagnosticsForDocumentsHandler {
95
+ pub fn new ( ) -> PullDiagnosticsForDocumentsHandler {
96
+ PullDiagnosticsForDocumentsHandler {
97
+ document_ids : [ ] . into ( ) ,
98
+ }
99
+ }
100
+ }
101
+
102
+ impl helix_event:: AsyncHook for PullDiagnosticsForLanguageServersHandler {
103
+ type Event = PullDiagnosticsForLanguageServersEvent ;
76
104
77
105
fn handle_event (
78
106
& mut self ,
79
107
event : Self :: Event ,
80
108
_: Option < tokio:: time:: Instant > ,
81
109
) -> Option < tokio:: time:: Instant > {
82
110
self . language_server_ids = event. language_server_ids ;
83
- Some ( Instant :: now ( ) + Duration :: from_millis ( TIMEOUT ) )
111
+ Some ( Instant :: now ( ) + Duration :: from_millis ( 120 ) )
84
112
}
85
113
86
114
fn finish_debounce ( & mut self ) {
87
115
let language_servers = self . language_server_ids . clone ( ) ;
88
116
job:: dispatch_blocking ( move |editor, _| {
89
- pull_diagnostic_for_document (
90
- editor,
91
- language_servers,
92
- editor. documents ( ) . map ( |x| x. id ( ) ) . collect ( ) ,
93
- )
117
+ pull_diagnostic_for_language_servers ( editor, language_servers)
94
118
} )
95
119
}
96
120
}
97
121
98
- fn pull_diagnostic_for_document (
122
+ impl helix_event:: AsyncHook for PullDiagnosticsForDocumentsHandler {
123
+ type Event = PullDiagnosticsForDocumentsEvent ;
124
+
125
+ fn handle_event (
126
+ & mut self ,
127
+ event : Self :: Event ,
128
+ _: Option < tokio:: time:: Instant > ,
129
+ ) -> Option < tokio:: time:: Instant > {
130
+ self . document_ids . insert ( event. document_id ) ;
131
+ Some ( Instant :: now ( ) + Duration :: from_millis ( 50 ) )
132
+ }
133
+
134
+ fn finish_debounce ( & mut self ) {
135
+ let document_ids = self . document_ids . clone ( ) ;
136
+ job:: dispatch_blocking ( move |editor, _| {
137
+ pull_diagnostics_for_documents ( editor, document_ids)
138
+ } )
139
+ }
140
+ }
141
+
142
+ fn pull_diagnostics_for_documents ( editor : & mut Editor , document_ids : HashSet < DocumentId > ) {
143
+ for document_id in document_ids {
144
+ let Some ( doc) = editor. document_mut ( document_id) else {
145
+ return ;
146
+ } ;
147
+
148
+ let language_servers =
149
+ doc. language_servers_with_feature ( LanguageServerFeature :: PullDiagnostics ) ;
150
+
151
+ for language_server in language_servers {
152
+ pull_diagnostics_for_document ( doc, language_server) ;
153
+ }
154
+ }
155
+ }
156
+
157
+ fn pull_diagnostic_for_language_servers (
99
158
editor : & mut Editor ,
100
- language_server_ids : Vec < LanguageServerId > ,
101
- document_ids : Vec < helix_view:: DocumentId > ,
159
+ language_server_ids : HashSet < LanguageServerId > ,
102
160
) {
103
- for document_id in document_ids. clone ( ) {
104
- let doc = doc_mut ! ( editor, & document_id) ;
161
+ let document_ids: Vec < _ > = editor. documents ( ) . map ( |x| x. id ( ) ) . collect ( ) ;
162
+
163
+ for document_id in document_ids {
164
+ let Some ( doc) = editor. document_mut ( document_id) else {
165
+ return ;
166
+ } ;
167
+
105
168
let language_servers = doc
106
169
. language_servers ( )
107
170
. filter ( |x| language_server_ids. contains ( & x. id ( ) ) ) ;
108
171
109
172
for language_server in language_servers {
110
- let Some ( future) = language_server
111
- . text_document_diagnostic ( doc. identifier ( ) , doc. previous_diagnostic_id . clone ( ) )
112
- else {
113
- return ;
114
- } ;
115
-
116
- let Some ( uri) = doc. uri ( ) else {
117
- return ;
118
- } ;
119
-
120
- let server_id = language_server. id ( ) ;
121
-
122
- tokio:: spawn ( async move {
123
- match future. await {
124
- Ok ( res) => {
125
- job:: dispatch ( move |editor, _| {
126
- log:: error!( "{}" , res) ;
127
-
128
- let parsed_response: Option < lsp:: DocumentDiagnosticReport > =
129
- match serde_json:: from_value ( res) {
130
- Ok ( result) => Some ( result) ,
131
- Err ( _) => None ,
132
- } ;
133
-
134
- let Some ( response) = parsed_response else {
135
- return ;
136
- } ;
137
-
138
- show_pull_diagnostics ( editor, response, server_id, uri, & document_id)
139
- } )
140
- . await
141
- }
142
- Err ( err) => log:: error!( "signature help request failed: {err}" ) ,
143
- }
144
- } ) ;
173
+ pull_diagnostics_for_document ( doc, language_server) ;
145
174
}
146
175
}
147
176
}
148
177
149
- fn show_pull_diagnostics (
178
+ fn pull_diagnostics_for_document ( doc : & helix_view:: Document , language_server : & helix_lsp:: Client ) {
179
+ let Some ( future) = language_server
180
+ . text_document_diagnostic ( doc. identifier ( ) , doc. previous_diagnostic_id . clone ( ) )
181
+ else {
182
+ return ;
183
+ } ;
184
+
185
+ let Some ( uri) = doc. uri ( ) else {
186
+ return ;
187
+ } ;
188
+
189
+ let server_id = language_server. id ( ) ;
190
+ let document_id = doc. id ( ) ;
191
+
192
+ tokio:: spawn ( async move {
193
+ match future. await {
194
+ Ok ( res) => {
195
+ job:: dispatch ( move |editor, _| {
196
+ let response = match serde_json:: from_value ( res) {
197
+ Ok ( result) => result,
198
+ Err ( _) => return ,
199
+ } ;
200
+
201
+ handle_pull_diagnostics_response ( editor, response, server_id, uri, document_id)
202
+ } )
203
+ . await
204
+ }
205
+ Err ( err) => log:: error!( "Pull diagnostic request failed: {err}" ) ,
206
+ }
207
+ } ) ;
208
+ }
209
+
210
+ fn handle_pull_diagnostics_response (
150
211
editor : & mut Editor ,
151
212
response : lsp:: DocumentDiagnosticReport ,
152
213
server_id : LanguageServerId ,
153
214
uri : Uri ,
154
- document_id : & helix_view:: DocumentId ,
215
+ document_id : helix_view:: DocumentId ,
155
216
) {
156
- let doc = doc_mut ! ( editor, document_id) ;
217
+ let Some ( doc) = editor. document_mut ( document_id) else {
218
+ return ;
219
+ } ;
220
+
157
221
match response {
158
222
lsp:: DocumentDiagnosticReport :: Full ( report) => {
159
223
// Original file diagnostic
160
- parse_diagnostic (
224
+ add_diagnostics_to_editor (
161
225
editor,
162
226
uri,
163
227
report. full_document_diagnostic_report . items ,
@@ -187,7 +251,7 @@ fn show_pull_diagnostics(
187
251
}
188
252
}
189
253
190
- fn parse_diagnostic (
254
+ fn add_diagnostics_to_editor (
191
255
editor : & mut Editor ,
192
256
uri : Uri ,
193
257
report : Vec < lsp:: Diagnostic > ,
@@ -202,7 +266,7 @@ fn parse_diagnostic(
202
266
203
267
fn handle_document_diagnostic_report_kind (
204
268
editor : & mut Editor ,
205
- document_id : & helix_view:: DocumentId ,
269
+ document_id : helix_view:: DocumentId ,
206
270
report : Option < HashMap < lsp:: Url , lsp:: DocumentDiagnosticReportKind > > ,
207
271
server_id : LanguageServerId ,
208
272
) {
@@ -213,10 +277,12 @@ fn handle_document_diagnostic_report_kind(
213
277
return ;
214
278
} ;
215
279
216
- parse_diagnostic ( editor, uri, report. items , report. result_id , server_id) ;
280
+ add_diagnostics_to_editor ( editor, uri, report. items , report. result_id , server_id) ;
217
281
}
218
282
lsp:: DocumentDiagnosticReportKind :: Unchanged ( report) => {
219
- let doc = doc_mut ! ( editor, & document_id) ;
283
+ let Some ( doc) = editor. document_mut ( document_id) else {
284
+ return ;
285
+ } ;
220
286
doc. previous_diagnostic_id = Some ( report. result_id ) ;
221
287
}
222
288
}
0 commit comments