@@ -569,6 +569,14 @@ fn action_fixes_diagnostics(action: &CodeActionOrCommand) -> bool {
569
569
}
570
570
571
571
pub fn code_action ( cx : & mut Context ) {
572
+ code_action_inner ( cx, false ) ;
573
+ }
574
+
575
+ pub fn code_action_picker ( cx : & mut Context ) {
576
+ code_action_inner ( cx, true ) ;
577
+ }
578
+
579
+ pub fn code_action_inner ( cx : & mut Context , use_picker : bool ) {
572
580
let ( view, doc) = current ! ( cx. editor) ;
573
581
574
582
let selection_range = doc. selection ( view. id ) . primary ( ) ;
@@ -676,61 +684,117 @@ pub fn code_action(cx: &mut Context) {
676
684
actions. append ( & mut lsp_items) ;
677
685
}
678
686
679
- let call = move |editor : & mut Editor , compositor : & mut Compositor | {
680
- if actions. is_empty ( ) {
681
- editor. set_error ( "No code actions available" ) ;
687
+ if use_picker {
688
+ code_action_inner_picker ( actions)
689
+ } else {
690
+ code_action_inner_menu ( actions)
691
+ }
692
+ } ) ;
693
+ }
694
+
695
+ fn code_action_inner_menu (
696
+ actions : Vec < CodeActionOrCommandItem > ,
697
+ ) -> Result < Callback , anyhow:: Error > {
698
+ let call = move |editor : & mut Editor , compositor : & mut Compositor | {
699
+ if actions. is_empty ( ) {
700
+ editor. set_error ( "No code actions available" ) ;
701
+ return ;
702
+ }
703
+ let mut picker = ui:: Menu :: new ( actions, ( ) , move |editor, action, event| {
704
+ if event != PromptEvent :: Validate {
682
705
return ;
683
706
}
684
- let picker = ui:: Picker :: new ( actions, ( ) , move |cx, lsp_item, _event| {
685
- let Some ( language_server) = cx. editor . language_server_by_id ( lsp_item. language_server_id )
686
- else {
687
- cx. editor . set_error ( "Language Server disappeared" ) ;
688
- return ;
689
- } ;
690
- let offset_encoding = language_server. offset_encoding ( ) ;
691
707
692
- match & lsp_item. lsp_item {
693
- lsp:: CodeActionOrCommand :: Command ( command) => {
694
- log:: debug!( "code action command: {:?}" , command) ;
695
- execute_lsp_command ( cx. editor , lsp_item. language_server_id , command. clone ( ) ) ;
696
- }
697
- lsp:: CodeActionOrCommand :: CodeAction ( code_action) => {
698
- log:: debug!( "code action: {:?}" , code_action) ;
699
- // we support lsp "codeAction/resolve" for `edit` and `command` fields
700
- let mut resolved_code_action = None ;
701
- if code_action. edit . is_none ( ) || code_action. command . is_none ( ) {
702
- if let Some ( future) =
703
- language_server. resolve_code_action ( code_action. clone ( ) )
704
- {
705
- if let Ok ( response) = helix_lsp:: block_on ( future) {
706
- if let Ok ( code_action) =
707
- serde_json:: from_value :: < CodeAction > ( response)
708
- {
709
- resolved_code_action = Some ( code_action) ;
710
- }
711
- }
712
- }
713
- }
714
- let resolved_code_action =
715
- resolved_code_action. as_ref ( ) . unwrap_or ( & code_action) ;
708
+ // always present here
709
+ let action = action. unwrap ( ) ;
716
710
717
- if let Some ( ref workspace_edit) = resolved_code_action. edit {
718
- let _ = cx. editor . apply_workspace_edit ( offset_encoding, workspace_edit) ;
719
- }
711
+ code_action_handle_lsp_item ( editor, & action. lsp_item , action. language_server_id ) ;
712
+ } ) ;
713
+ picker. move_down ( ) ; // pre-select the first item
714
+
715
+ let margin = if editor. menu_border ( ) {
716
+ Margin :: vertical ( 1 )
717
+ } else {
718
+ Margin :: none ( )
719
+ } ;
720
+
721
+ let popup = Popup :: new ( "code-action" , picker)
722
+ . with_scrollbar ( false )
723
+ . margin ( margin) ;
724
+
725
+ compositor. replace_or_push ( "code-action" , popup) ;
726
+ } ;
727
+
728
+ Ok ( Callback :: EditorCompositor ( Box :: new ( call) ) )
729
+ }
730
+
731
+ fn code_action_inner_picker (
732
+ actions : Vec < CodeActionOrCommandItem > ,
733
+ ) -> Result < Callback , anyhow:: Error > {
734
+ let call = move |editor : & mut Editor , compositor : & mut Compositor | {
735
+ if actions. is_empty ( ) {
736
+ editor. set_error ( "No code actions available" ) ;
737
+ return ;
738
+ }
739
+ let picker = ui:: Picker :: new (
740
+ actions,
741
+ ( ) ,
742
+ move |cx : & mut crate :: compositor:: Context , lsp_item, _event| {
743
+ code_action_handle_lsp_item (
744
+ & mut cx. editor ,
745
+ & lsp_item. lsp_item ,
746
+ lsp_item. language_server_id ,
747
+ ) ;
748
+ } ,
749
+ ) ;
750
+ compositor. push ( Box :: new ( overlaid ( picker) ) ) ;
751
+ } ;
752
+ Ok ( Callback :: EditorCompositor ( Box :: new ( call) ) )
753
+ }
720
754
721
- // if code action provides both edit and command first the edit
722
- // should be applied and then the command
723
- if let Some ( command) = & code_action. command {
724
- execute_lsp_command ( cx. editor , lsp_item. language_server_id , command. clone ( ) ) ;
755
+ fn code_action_handle_lsp_item (
756
+ editor : & mut Editor ,
757
+ lsp_item : & CodeActionOrCommand ,
758
+ language_server_id : usize ,
759
+ ) {
760
+ let Some ( language_server) = editor. language_server_by_id ( language_server_id)
761
+ else {
762
+ editor. set_error ( "Language Server disappeared" ) ;
763
+ return ;
764
+ } ;
765
+ let offset_encoding = language_server. offset_encoding ( ) ;
766
+
767
+ match lsp_item {
768
+ lsp:: CodeActionOrCommand :: Command ( command) => {
769
+ log:: debug!( "code action command: {:?}" , command) ;
770
+ execute_lsp_command ( editor, language_server_id, command. clone ( ) ) ;
771
+ }
772
+ lsp:: CodeActionOrCommand :: CodeAction ( code_action) => {
773
+ log:: debug!( "code action: {:?}" , code_action) ;
774
+ // we support lsp "codeAction/resolve" for `edit` and `command` fields
775
+ let mut resolved_code_action = None ;
776
+ if code_action. edit . is_none ( ) || code_action. command . is_none ( ) {
777
+ if let Some ( future) = language_server. resolve_code_action ( code_action. clone ( ) ) {
778
+ if let Ok ( response) = helix_lsp:: block_on ( future) {
779
+ if let Ok ( code_action) = serde_json:: from_value :: < CodeAction > ( response) {
780
+ resolved_code_action = Some ( code_action) ;
725
781
}
726
782
}
727
783
}
728
- } ) ;
729
- compositor. push ( Box :: new ( overlaid ( picker) ) ) ;
730
- } ;
784
+ }
785
+ let resolved_code_action = resolved_code_action. as_ref ( ) . unwrap_or ( & code_action) ;
731
786
732
- Ok ( Callback :: EditorCompositor ( Box :: new ( call) ) )
733
- } ) ;
787
+ if let Some ( ref workspace_edit) = resolved_code_action. edit {
788
+ let _ = editor. apply_workspace_edit ( offset_encoding, workspace_edit) ;
789
+ }
790
+
791
+ // if code action provides both edit and command first the edit
792
+ // should be applied and then the command
793
+ if let Some ( command) = & code_action. command {
794
+ execute_lsp_command ( editor, language_server_id, command. clone ( ) ) ;
795
+ }
796
+ }
797
+ }
734
798
}
735
799
736
800
impl ui:: menu:: Item for lsp:: Command {
0 commit comments