@@ -452,43 +452,83 @@ pub fn code_action(cx: &mut Context) {
452
452
cx. callback (
453
453
future,
454
454
move |editor, compositor, response : Option < lsp:: CodeActionResponse > | {
455
- let actions = match response {
455
+ let mut actions = match response {
456
456
Some ( a) => a,
457
457
None => return ,
458
458
} ;
459
+
459
460
if actions. is_empty ( ) {
460
461
editor. set_status ( "No code actions available" ) ;
461
462
return ;
462
463
}
463
464
464
- let mut picker = ui:: Menu :: new ( actions, ( ) , move |editor, code_action, event| {
465
- if event != PromptEvent :: Validate {
466
- return ;
467
- }
465
+ // sort by CodeActionKind
466
+ // this ensures that the most relevant codeactions (quickfix) show up first
467
+ // while more situational commands (like refactors) show up later
468
+ // this behaviour is modeled after the behaviour of vscode (editor/contrib/codeAction/browser/codeActionWidget.ts)
469
+
470
+ let mut categories = vec ! [ Vec :: new( ) ; 8 ] ;
471
+ for action in actions. drain ( ..) {
472
+ let category = match & action {
473
+ lsp:: CodeActionOrCommand :: CodeAction ( lsp:: CodeAction {
474
+ kind : Some ( kind) ,
475
+ ..
476
+ } ) => {
477
+ let mut components = kind. as_str ( ) . split ( '.' ) ;
478
+
479
+ match components. next ( ) {
480
+ Some ( "quickfix" ) => 0 ,
481
+ Some ( "refactor" ) => match components. next ( ) {
482
+ Some ( "extract" ) => 1 ,
483
+ Some ( "inline" ) => 2 ,
484
+ Some ( "rewrite" ) => 3 ,
485
+ Some ( "move" ) => 4 ,
486
+ Some ( "surround" ) => 5 ,
487
+ _ => 7 ,
488
+ } ,
489
+ Some ( "source" ) => 6 ,
490
+ _ => 7 ,
491
+ }
492
+ }
493
+ _ => 7 ,
494
+ } ;
495
+
496
+ categories[ category] . push ( action) ;
497
+ }
468
498
469
- // always present here
470
- let code_action = code_action. unwrap ( ) ;
499
+ for category in categories {
500
+ actions. extend ( category. into_iter ( ) )
501
+ }
471
502
472
- match code_action {
473
- lsp :: CodeActionOrCommand :: Command ( command ) => {
474
- log :: debug! ( "code action command: {:?}" , command ) ;
475
- execute_lsp_command ( editor , command . clone ( ) ) ;
503
+ let mut picker =
504
+ ui :: Menu :: new ( actions , false , ( ) , move |editor , code_action , event| {
505
+ if event != PromptEvent :: Validate {
506
+ return ;
476
507
}
477
- lsp:: CodeActionOrCommand :: CodeAction ( code_action) => {
478
- log:: debug!( "code action: {:?}" , code_action) ;
479
- if let Some ( ref workspace_edit) = code_action. edit {
480
- log:: debug!( "edit: {:?}" , workspace_edit) ;
481
- apply_workspace_edit ( editor, offset_encoding, workspace_edit) ;
482
- }
483
508
484
- // if code action provides both edit and command first the edit
485
- // should be applied and then the command
486
- if let Some ( command) = & code_action. command {
509
+ // always present here
510
+ let code_action = code_action. unwrap ( ) ;
511
+
512
+ match code_action {
513
+ lsp:: CodeActionOrCommand :: Command ( command) => {
514
+ log:: debug!( "code action command: {:?}" , command) ;
487
515
execute_lsp_command ( editor, command. clone ( ) ) ;
488
516
}
517
+ lsp:: CodeActionOrCommand :: CodeAction ( code_action) => {
518
+ log:: debug!( "code action: {:?}" , code_action) ;
519
+ if let Some ( ref workspace_edit) = code_action. edit {
520
+ log:: debug!( "edit: {:?}" , workspace_edit) ;
521
+ apply_workspace_edit ( editor, offset_encoding, workspace_edit) ;
522
+ }
523
+
524
+ // if code action provides both edit and command first the edit
525
+ // should be applied and then the command
526
+ if let Some ( command) = & code_action. command {
527
+ execute_lsp_command ( editor, command. clone ( ) ) ;
528
+ }
529
+ }
489
530
}
490
- }
491
- } ) ;
531
+ } ) ;
492
532
picker. move_down ( ) ; // pre-select the first item
493
533
494
534
let popup = Popup :: new ( "code-action" , picker) ;
0 commit comments