@@ -3,7 +3,7 @@ import * as lc from "vscode-languageclient/node";
3
3
import * as vscode from "vscode" ;
4
4
import * as ra from "../src/lsp_ext" ;
5
5
import * as Is from "vscode-languageclient/lib/common/utils/is" ;
6
- import { assert , unwrapUndefinable } from "./util" ;
6
+ import { assert } from "./util" ;
7
7
import * as diagnostics from "./diagnostics" ;
8
8
import { WorkspaceEdit } from "vscode" ;
9
9
import { type Config , prepareVSCodeConfig } from "./config" ;
@@ -188,11 +188,17 @@ export async function createClient(
188
188
context : await client . code2ProtocolConverter . asCodeActionContext ( context , token ) ,
189
189
} ;
190
190
const callback = async (
191
- values : ( lc . Command | lc . CodeAction ) [ ] | null ,
191
+ values : ( lc . Command | lc . CodeAction | object ) [ ] | null ,
192
192
) : Promise < ( vscode . Command | vscode . CodeAction ) [ ] | undefined > => {
193
193
if ( values === null ) return undefined ;
194
194
const result : ( vscode . CodeAction | vscode . Command ) [ ] = [ ] ;
195
- const groups = new Map < string , { index : number ; items : vscode . CodeAction [ ] } > ( ) ;
195
+ const groups = new Map <
196
+ string ,
197
+ {
198
+ primary : vscode . CodeAction ;
199
+ items : { label : string ; arguments : lc . CodeAction } [ ] ;
200
+ }
201
+ > ( ) ;
196
202
for ( const item of values ) {
197
203
// In our case we expect to get code edits only from diagnostics
198
204
if ( lc . CodeAction . is ( item ) ) {
@@ -204,62 +210,55 @@ export async function createClient(
204
210
result . push ( action ) ;
205
211
continue ;
206
212
}
207
- assert (
208
- isCodeActionWithoutEditsAndCommands ( item ) ,
209
- "We don't expect edits or commands here" ,
210
- ) ;
211
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
212
- const kind = client . protocol2CodeConverter . asCodeActionKind ( ( item as any ) . kind ) ;
213
- const action = new vscode . CodeAction ( item . title , kind ) ;
214
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
215
- const group = ( item as any ) . group ;
216
- action . command = {
217
- command : "rust-analyzer.resolveCodeAction" ,
218
- title : item . title ,
219
- arguments : [ item ] ,
220
- } ;
213
+ assertIsCodeActionWithoutEditsAndCommands ( item ) ;
214
+ const kind = client . protocol2CodeConverter . asCodeActionKind ( item . kind ) ;
215
+ const group = item . group ;
221
216
222
- // Set a dummy edit, so that VS Code doesn't try to resolve this.
223
- action . edit = new WorkspaceEdit ( ) ;
217
+ const mkAction = ( ) => {
218
+ const action = new vscode . CodeAction ( item . title , kind ) ;
219
+ action . command = {
220
+ command : "rust-analyzer.resolveCodeAction" ,
221
+ title : item . title ,
222
+ arguments : [ item ] ,
223
+ } ;
224
+ // Set a dummy edit, so that VS Code doesn't try to resolve this.
225
+ action . edit = new WorkspaceEdit ( ) ;
226
+ return action ;
227
+ } ;
224
228
225
229
if ( group ) {
226
230
let entry = groups . get ( group ) ;
227
231
if ( ! entry ) {
228
- entry = { index : result . length , items : [ ] } ;
232
+ entry = { primary : mkAction ( ) , items : [ ] } ;
229
233
groups . set ( group , entry ) ;
230
- result . push ( action ) ;
234
+ } else {
235
+ entry . items . push ( {
236
+ label : item . title ,
237
+ arguments : item ,
238
+ } ) ;
231
239
}
232
- entry . items . push ( action ) ;
233
240
} else {
234
- result . push ( action ) ;
241
+ result . push ( mkAction ( ) ) ;
235
242
}
236
243
}
237
- for ( const [ group , { index, items } ] of groups ) {
238
- if ( items . length === 1 ) {
239
- const item = unwrapUndefinable ( items [ 0 ] ) ;
240
- result [ index ] = item ;
241
- } else {
242
- const action = new vscode . CodeAction ( group ) ;
243
- const item = unwrapUndefinable ( items [ 0 ] ) ;
244
- action . kind = item . kind ;
245
- action . command = {
244
+ for ( const [ group , { items, primary } ] of groups ) {
245
+ // This group contains more than one item, so rewrite it to be a group action
246
+ if ( items . length !== 0 ) {
247
+ const args = [
248
+ {
249
+ label : primary . title ,
250
+ arguments : primary . command ! . arguments ! [ 0 ] ,
251
+ } ,
252
+ ...items ,
253
+ ] ;
254
+ primary . title = group ;
255
+ primary . command = {
246
256
command : "rust-analyzer.applyActionGroup" ,
247
257
title : "" ,
248
- arguments : [
249
- items . map ( ( item ) => {
250
- return {
251
- label : item . title ,
252
- arguments : item . command ! . arguments ! [ 0 ] ,
253
- } ;
254
- } ) ,
255
- ] ,
258
+ arguments : [ args ] ,
256
259
} ;
257
-
258
- // Set a dummy edit, so that VS Code doesn't try to resolve this.
259
- action . edit = new WorkspaceEdit ( ) ;
260
-
261
- result [ index ] = action ;
262
260
}
261
+ result . push ( primary ) ;
263
262
}
264
263
return result ;
265
264
} ;
@@ -363,17 +362,22 @@ class OverrideFeatures implements lc.StaticFeature {
363
362
clear ( ) : void { }
364
363
}
365
364
366
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
- function isCodeActionWithoutEditsAndCommands ( value : any ) : boolean {
368
- const candidate : lc . CodeAction = value ;
369
- return (
365
+ function assertIsCodeActionWithoutEditsAndCommands (
366
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
+ candidate : any ,
368
+ ) : asserts candidate is lc . CodeAction & {
369
+ group ?: string ;
370
+ } {
371
+ assert (
370
372
candidate &&
371
- Is . string ( candidate . title ) &&
372
- ( candidate . diagnostics === void 0 ||
373
- Is . typedArray ( candidate . diagnostics , lc . Diagnostic . is ) ) &&
374
- ( candidate . kind === void 0 || Is . string ( candidate . kind ) ) &&
375
- candidate . edit === void 0 &&
376
- candidate . command === void 0
373
+ Is . string ( candidate . title ) &&
374
+ ( candidate . diagnostics === undefined ||
375
+ Is . typedArray ( candidate . diagnostics , lc . Diagnostic . is ) ) &&
376
+ ( candidate . group === undefined || Is . string ( candidate . group ) ) &&
377
+ ( candidate . kind === undefined || Is . string ( candidate . kind ) ) &&
378
+ candidate . edit === undefined &&
379
+ candidate . command === undefined ,
380
+ `Expected a CodeAction without edits or commands, got: ${ JSON . stringify ( candidate ) } ` ,
377
381
) ;
378
382
}
379
383
0 commit comments