@@ -2850,7 +2850,6 @@ def GetCodeActions( self, request_data ):
28502850                      cursor_range_ls ,
28512851                      matched_diagnostics  ),
28522852      REQUEST_TIMEOUT_COMMAND  )
2853- 
28542853    return  self .CodeActionResponseToFixIts ( request_data ,
28552854                                            code_actions [ 'result'  ] )
28562855
@@ -2861,28 +2860,22 @@ def CodeActionResponseToFixIts( self, request_data, code_actions ):
28612860
28622861    fixits  =  []
28632862    for  code_action  in  code_actions :
2864-       if  'edit'  in  code_action :
2865-         # TODO: Start supporting a mix of WorkspaceEdits and Commands 
2866-         # once there's a need for such 
2867-         assert  'command'  not  in   code_action 
2868- 
2869-         # This is a WorkspaceEdit literal 
2870-         fixits .append ( self .CodeActionLiteralToFixIt ( request_data ,
2871-                                                       code_action  ) )
2872-         continue 
2873- 
2874-       # Either a CodeAction or a Command 
2875-       assert  'command'  in  code_action 
2876- 
2877-       action_command  =  code_action [ 'command'  ]
2878-       if  isinstance ( action_command , dict  ):
2879-         # CodeAction with a 'command' rather than 'edit' 
2880-         fixits .append ( self .CodeActionCommandToFixIt ( request_data ,
2881-                                                       code_action  ) )
2863+       capabilities  =  self ._server_capabilities [ 'codeActionProvider'  ]
2864+       if  ( ( isinstance ( capabilities , dict  ) and 
2865+              capabilities .get ( 'resolveProvider'  ) ) or 
2866+            'command'  in  code_action  ):
2867+         # If server is a code action resolve provider, either we are obligated 
2868+         # to resolve, or we have a command in the code action response. 
2869+         # If server does not want us to resolve, but sends a command anyway, 
2870+         # we still need to lazily execute that command. 
2871+         fixits .append ( responses .UnresolvedFixIt ( code_action ,
2872+                                                   code_action [ 'title'  ],
2873+                                                   code_action .get ( 'kind'  ) ) )
28822874        continue 
2875+       # No resoving here - just a simple code action literal. 
2876+       fixits .append ( self .CodeActionLiteralToFixIt ( request_data ,
2877+                                                     code_action  ) )
28832878
2884-       # It is a Command 
2885-       fixits .append ( self .CommandToFixIt ( request_data , code_action  ) )
28862879
28872880    # Show a list of actions to the user to select which one to apply. 
28882881    # This is (probably) a more common workflow for "code action". 
@@ -2986,10 +2979,44 @@ def Format( self, request_data ):
29862979
29872980
29882981  def  _ResolveFixit ( self , request_data , fixit  ):
2989-     if  not  fixit [ 'resolve'  ]:
2990-       return  { 'fixits' : [ fixit  ] }
2982+     code_action  =  fixit [ 'command'  ]
2983+     capabilities  =  self ._server_capabilities [ 'codeActionProvider'  ]
2984+     if  ( isinstance ( capabilities , dict  ) and 
2985+          capabilities .get ( 'resolveProvider'  ) ):
2986+       # Resolve through codeAction/resolve request, before resolving commands. 
2987+       # If the server is an asshole, it might be a code action resolve 
2988+       # provider, but send a LSP Command instead. We can not resolve those with 
2989+       # codeAction/resolve! 
2990+       if  ( 'command'  not  in   code_action  or 
2991+            isinstance ( code_action [ 'command'  ], str  ) ):
2992+         request_id  =  self .GetConnection ().NextRequestId ()
2993+         msg  =  lsp .CodeActionResolve ( request_id , code_action  )
2994+         code_action  =  self .GetConnection ().GetResponse (
2995+             request_id ,
2996+             msg ,
2997+             REQUEST_TIMEOUT_COMMAND  )[ 'result'  ]
29912998
2992-     unresolved_fixit  =  fixit [ 'command'  ]
2999+     result  =  []
3000+     if  'edit'  in  code_action :
3001+       result .append ( self .CodeActionLiteralToFixIt ( request_data ,
3002+                                                     code_action  ) )
3003+ 
3004+     if  'command'  in  code_action :
3005+       assert  not  result , 'Code actions with edit and command is not supported.' 
3006+       if  isinstance ( code_action [ 'command'  ], str  ):
3007+         unresolved_command_fixit  =  self .CommandToFixIt ( request_data ,
3008+                                                         code_action  )
3009+       else :
3010+         unresolved_command_fixit  =  self .CodeActionCommandToFixIt ( request_data ,
3011+                                                                   code_action  )
3012+       result .append ( self ._ResolveFixitCommand ( request_data ,
3013+                                                 unresolved_command_fixit  ) )
3014+ 
3015+     return  responses .BuildFixItResponse ( result  )
3016+ 
3017+ 
3018+   def  _ResolveFixitCommand ( self , request_data , fixit  ):
3019+     unresolved_fixit  =  fixit .command 
29933020    collector  =  EditCollector ()
29943021    with  self .GetConnection ().CollectApplyEdits ( collector  ):
29953022      self .GetCommandResponse (
@@ -3001,19 +3028,23 @@ def _ResolveFixit( self, request_data, fixit ):
30013028    response  =  collector .requests 
30023029    assert  len ( response  ) <  2 
30033030    if  not  response :
3004-       return  responses .BuildFixItResponse ( [  responses . FixIt (
3031+       return  responses .FixIt (
30053032        responses .Location ( request_data [ 'line_num'  ],
30063033                            request_data [ 'column_num'  ],
30073034                            request_data [ 'filepath'  ] ),
3008-         [] ) ] ) 
3035+         [] )
30093036    fixit  =  WorkspaceEditToFixIt (
30103037      request_data ,
30113038      response [ 0  ][ 'edit'  ],
30123039      unresolved_fixit [ 'title'  ] )
3013-     return  responses . BuildFixItResponse ( [  fixit  ] ) 
3040+     return  fixit 
30143041
30153042
30163043  def  ResolveFixit ( self , request_data  ):
3044+     fixit  =  request_data [ 'fixit'  ]
3045+     if  'command'  not  in   fixit :
3046+       # Somebody has sent us an already resolved fixit. 
3047+       return  { 'fixits' : [ fixit  ] }
30173048    return  self ._ResolveFixit ( request_data , request_data [ 'fixit'  ] )
30183049
30193050
0 commit comments