@@ -26,9 +26,22 @@ interface ParsedDiagnostic {
26
26
27
27
type DiagnosticsMap = Map < string , vscode . Diagnostic [ ] > ;
28
28
29
+ type SourcePredicate = ( source : string ) => boolean ;
30
+
31
+ type DiagnosticPredicate = ( diagnostic : vscode . Diagnostic ) => boolean ;
32
+
29
33
const isEqual = ( d1 : vscode . Diagnostic , d2 : vscode . Diagnostic ) =>
30
34
d1 . range . start . isEqual ( d2 . range . start ) && d1 . message === d2 . message ;
31
35
36
+ const isSource = ( diagnostic : vscode . Diagnostic , sourcesPredicate : SourcePredicate ) =>
37
+ sourcesPredicate ( diagnostic . source ?? "" ) ;
38
+
39
+ const isSwiftc : DiagnosticPredicate = diagnostic =>
40
+ isSource ( diagnostic , DiagnosticsManager . isSwiftc ) ;
41
+
42
+ const isSourceKit : DiagnosticPredicate = diagnostic =>
43
+ isSource ( diagnostic , DiagnosticsManager . isSourcekit ) ;
44
+
32
45
/**
33
46
* Handles the collection and deduplication of diagnostics from
34
47
* various {@link vscode.Diagnostic.source | Diagnostic sources}.
@@ -38,9 +51,9 @@ const isEqual = (d1: vscode.Diagnostic, d2: vscode.Diagnostic) =>
38
51
* thier own diagnostics.
39
52
*/
40
53
export class DiagnosticsManager implements vscode . Disposable {
41
- // Prior to Swift 6 "sourcekitd" was the source
42
- static sourcekit : string [ ] = [ "SourceKit" , "sourcekitd" ] ;
43
- static swiftc : string [ ] = [ " swiftc" ] ;
54
+ private static swiftc : string = "swiftc" ;
55
+ static isSourcekit : SourcePredicate = source => this . swiftc !== source ;
56
+ static isSwiftc : SourcePredicate = source => this . swiftc === source ;
44
57
45
58
private diagnosticCollection : vscode . DiagnosticCollection =
46
59
vscode . languages . createDiagnosticCollection ( "swift" ) ;
@@ -57,15 +70,15 @@ export class DiagnosticsManager implements vscode.Disposable {
57
70
} ) ;
58
71
this . onDidStartTaskDisposible = vscode . tasks . onDidStartTask ( event => {
59
72
// Will only try to provide diagnostics for `swift` tasks
60
- const execution = event . execution . task . execution ;
61
- if ( ! ( execution && execution instanceof SwiftExecution ) ) {
73
+ const task = event . execution . task ;
74
+ if ( task . definition . type !== "swift" ) {
62
75
return ;
63
76
}
64
77
if ( ! this . includeSwiftcDiagnostics ( ) ) {
65
78
return ;
66
79
}
67
80
// Provide new list of diagnostics
68
- const swiftExecution = execution as SwiftExecution ;
81
+ const swiftExecution = task . execution as SwiftExecution ;
69
82
const provideDiagnostics : Promise < DiagnosticsMap > =
70
83
this . parseDiagnostics ( swiftExecution ) ;
71
84
@@ -76,7 +89,7 @@ export class DiagnosticsManager implements vscode.Disposable {
76
89
map . forEach ( ( diagnostics , uri ) =>
77
90
this . handleDiagnostics (
78
91
vscode . Uri . file ( uri ) ,
79
- DiagnosticsManager . swiftc ,
92
+ DiagnosticsManager . isSwiftc ,
80
93
diagnostics
81
94
)
82
95
) ;
@@ -91,25 +104,25 @@ export class DiagnosticsManager implements vscode.Disposable {
91
104
* Provide a new list of diagnostics for a given file
92
105
*
93
106
* @param uri {@link vscode.Uri Uri } of the file these diagonstics apply to
94
- * @param sources The source of the diagnostics which will apply for cleaning
95
- * up diagnostics that have been removed. See {@link swiftc } and {@link sourcekit }
96
- * @param newDiagnostics Array of {@link vscode.Diagnostic}. This can be empty to remove old diagnostics for the specified `sources `.
107
+ * @param sourcePredicate Diagnostics of a source that satisfies the predicate will apply for cleaning
108
+ * up diagnostics that have been removed. See {@link isSwiftc } and {@link isSourceKit }
109
+ * @param newDiagnostics Array of {@link vscode.Diagnostic}. This can be empty to remove old diagnostics satisfying `sourcePredicate `.
97
110
*/
98
111
handleDiagnostics (
99
112
uri : vscode . Uri ,
100
- sources : string [ ] ,
113
+ sourcePredicate : SourcePredicate ,
101
114
newDiagnostics : vscode . Diagnostic [ ]
102
115
) : void {
103
- const isFromSourceKit = ! ! DiagnosticsManager . sourcekit . find ( s => sources . includes ( s ) ) ;
116
+ const isFromSourceKit = ! sourcePredicate ( DiagnosticsManager . swiftc ) ;
104
117
// Is a descrepency between SourceKit-LSP and older versions
105
118
// of Swift as to whether the first letter is capitalized or not,
106
119
// so we'll always display messages capitalized to user and this
107
120
// also will allow comparing messages when merging
108
- newDiagnostics = newDiagnostics . map ( this . capitalizeMessage ) ;
121
+ newDiagnostics = newDiagnostics . map ( this . capitalizeMessage ) . map ( this . cleanMessage ) ;
109
122
const allDiagnostics = this . allDiagnostics . get ( uri . fsPath ) ?. slice ( ) || [ ] ;
110
123
// Remove the old set of diagnostics from this source
111
124
const removedDiagnostics = this . removeDiagnostics ( allDiagnostics , d =>
112
- this . isSource ( d , sources )
125
+ isSource ( d , sourcePredicate )
113
126
) ;
114
127
// Clean up any "fixed" swiftc diagnostics
115
128
if ( isFromSourceKit ) {
@@ -119,7 +132,7 @@ export class DiagnosticsManager implements vscode.Disposable {
119
132
) ;
120
133
this . removeDiagnostics (
121
134
allDiagnostics ,
122
- d1 => this . isSwiftc ( d1 ) && ! ! removedDiagnostics . find ( d2 => isEqual ( d1 , d2 ) )
135
+ d1 => isSwiftc ( d1 ) && ! ! removedDiagnostics . find ( d2 => isEqual ( d1 , d2 ) )
123
136
) ;
124
137
}
125
138
// Append the new diagnostics we just received
@@ -131,25 +144,17 @@ export class DiagnosticsManager implements vscode.Disposable {
131
144
132
145
private updateDiagnosticsCollection ( uri : vscode . Uri ) : void {
133
146
const diagnostics = this . allDiagnostics . get ( uri . fsPath ) ?? [ ] ;
134
- const swiftcDiagnostics = diagnostics . filter ( d => this . isSwiftc ( d ) ) ;
135
- const sourceKitDiagnostics = diagnostics . filter ( d => this . isSourceKit ( d ) ) ;
147
+ const swiftcDiagnostics = diagnostics . filter ( isSwiftc ) ;
148
+ const sourceKitDiagnostics = diagnostics . filter ( isSourceKit ) ;
136
149
const mergedDiagnostics : vscode . Diagnostic [ ] = [ ] ;
137
150
switch ( configuration . diagnosticsCollection ) {
138
151
case "keepSourceKit" :
139
152
mergedDiagnostics . push ( ...swiftcDiagnostics ) ;
140
- this . mergeDiagnostics (
141
- mergedDiagnostics ,
142
- sourceKitDiagnostics ,
143
- DiagnosticsManager . sourcekit
144
- ) ;
153
+ this . mergeDiagnostics ( mergedDiagnostics , sourceKitDiagnostics , isSourceKit ) ;
145
154
break ;
146
155
case "keepSwiftc" :
147
156
mergedDiagnostics . push ( ...sourceKitDiagnostics ) ;
148
- this . mergeDiagnostics (
149
- mergedDiagnostics ,
150
- swiftcDiagnostics ,
151
- DiagnosticsManager . swiftc
152
- ) ;
157
+ this . mergeDiagnostics ( mergedDiagnostics , swiftcDiagnostics , isSwiftc ) ;
153
158
break ;
154
159
case "onlySourceKit" :
155
160
mergedDiagnostics . push ( ...sourceKitDiagnostics ) ;
@@ -168,7 +173,7 @@ export class DiagnosticsManager implements vscode.Disposable {
168
173
private mergeDiagnostics (
169
174
mergedDiagnostics : vscode . Diagnostic [ ] ,
170
175
newDiagnostics : vscode . Diagnostic [ ] ,
171
- precedence : string [ ]
176
+ precedencePredicate : DiagnosticPredicate
172
177
) : void {
173
178
for ( const diagnostic of newDiagnostics ) {
174
179
// See if a duplicate diagnostic exists
@@ -178,11 +183,11 @@ export class DiagnosticsManager implements vscode.Disposable {
178
183
}
179
184
180
185
// Perform de-duplication
181
- if ( precedence . includes ( diagnostic . source || "" ) ) {
186
+ if ( precedencePredicate ( diagnostic ) ) {
182
187
mergedDiagnostics . push ( diagnostic ) ;
183
188
continue ;
184
189
}
185
- if ( ! currentDiagnostic || ! precedence . includes ( currentDiagnostic . source || "" ) ) {
190
+ if ( ! currentDiagnostic || ! precedencePredicate ( currentDiagnostic ) ) {
186
191
mergedDiagnostics . push ( diagnostic ) ;
187
192
continue ;
188
193
}
@@ -193,29 +198,17 @@ export class DiagnosticsManager implements vscode.Disposable {
193
198
private removeSwiftcDiagnostics ( ) {
194
199
this . allDiagnostics . forEach ( ( diagnostics , path ) => {
195
200
const newDiagnostics = diagnostics . slice ( ) ;
196
- this . removeDiagnostics ( newDiagnostics , d => this . isSwiftc ( d ) ) ;
201
+ this . removeDiagnostics ( newDiagnostics , isSwiftc ) ;
197
202
if ( diagnostics . length !== newDiagnostics . length ) {
198
203
this . allDiagnostics . set ( path , newDiagnostics ) ;
199
204
}
200
205
this . updateDiagnosticsCollection ( vscode . Uri . file ( path ) ) ;
201
206
} ) ;
202
207
}
203
208
204
- private isSource ( diagnostic : vscode . Diagnostic , sources : string [ ] ) : boolean {
205
- return sources . includes ( diagnostic . source || "" ) ;
206
- }
207
-
208
- private isSwiftc ( diagnostic : vscode . Diagnostic ) : boolean {
209
- return this . isSource ( diagnostic , DiagnosticsManager . swiftc ) ;
210
- }
211
-
212
- private isSourceKit ( diagnostic : vscode . Diagnostic ) : boolean {
213
- return this . isSource ( diagnostic , DiagnosticsManager . sourcekit ) ;
214
- }
215
-
216
209
private removeDiagnostics (
217
210
diagnostics : vscode . Diagnostic [ ] ,
218
- matches : ( d : vscode . Diagnostic ) => boolean
211
+ matches : DiagnosticPredicate
219
212
) : vscode . Diagnostic [ ] {
220
213
const removed : vscode . Diagnostic [ ] = [ ] ;
221
214
let i = diagnostics . length ;
@@ -323,13 +316,13 @@ export class DiagnosticsManager implements vscode.Disposable {
323
316
private parseDiagnostic (
324
317
line : string
325
318
) : ParsedDiagnostic | vscode . DiagnosticRelatedInformation | undefined {
326
- const diagnosticRegex = / ^ ( .* ?) : ( \d + ) (?: : ( \d + ) ) ? : \s + ( w a r n i n g | e r r o r | n o t e ) : \s + ( . * ) $ / g;
319
+ const diagnosticRegex = / ^ ( .* ?) : ( \d + ) (?: : ( \d + ) ) ? : \s + ( w a r n i n g | e r r o r | n o t e ) : \s + ( [ ^ \\ [ ] * ) / g;
327
320
const match = diagnosticRegex . exec ( line ) ;
328
321
if ( ! match ) {
329
322
return ;
330
323
}
331
324
const uri = match [ 1 ] ;
332
- const message = this . capitalize ( match [ 5 ] ) ;
325
+ const message = this . capitalize ( match [ 5 ] ) . trim ( ) ;
333
326
const range = this . range ( match [ 2 ] , match [ 3 ] ) ;
334
327
const severity = this . severity ( match [ 4 ] ) ;
335
328
if ( severity === vscode . DiagnosticSeverity . Information ) {
@@ -339,7 +332,7 @@ export class DiagnosticsManager implements vscode.Disposable {
339
332
) ;
340
333
}
341
334
const diagnostic = new vscode . Diagnostic ( range , message , severity ) ;
342
- diagnostic . source = DiagnosticsManager . swiftc [ 0 ] ;
335
+ diagnostic . source = DiagnosticsManager . swiftc ;
343
336
return { uri, diagnostic } ;
344
337
}
345
338
@@ -377,6 +370,12 @@ export class DiagnosticsManager implements vscode.Disposable {
377
370
return diagnostic ;
378
371
} ;
379
372
373
+ private cleanMessage = ( diagnostic : vscode . Diagnostic ) => {
374
+ diagnostic = { ...diagnostic } ;
375
+ diagnostic . message = diagnostic . message . replace ( "(fix available)" , "" ) . trim ( ) ;
376
+ return diagnostic ;
377
+ } ;
378
+
380
379
private onDidStartTaskDisposible : vscode . Disposable ;
381
380
private onDidChangeConfigurationDisposible : vscode . Disposable ;
382
381
}
0 commit comments