@@ -8,6 +8,7 @@ use std::{
88} ;
99
1010use anyhow:: Context ;
11+
1112use ide:: {
1213 AnnotationConfig , AssistKind , AssistResolveStrategy , Cancellable , FilePosition , FileRange ,
1314 HoverAction , HoverGotoTypeData , Query , RangeInfo , ReferenceCategory , Runnable , RunnableKind ,
@@ -20,9 +21,9 @@ use lsp_types::{
2021 CallHierarchyOutgoingCall , CallHierarchyOutgoingCallsParams , CallHierarchyPrepareParams ,
2122 CodeLens , CompletionItem , FoldingRange , FoldingRangeParams , HoverContents , InlayHint ,
2223 InlayHintParams , Location , LocationLink , Position , PrepareRenameResponse , Range , RenameParams ,
23- SemanticTokensDeltaParams , SemanticTokensFullDeltaResult , SemanticTokensParams ,
24- SemanticTokensRangeParams , SemanticTokensRangeResult , SemanticTokensResult , SymbolInformation ,
25- SymbolTag , TextDocumentIdentifier , Url , WorkspaceEdit ,
24+ ResourceOp , ResourceOperationKind , SemanticTokensDeltaParams , SemanticTokensFullDeltaResult ,
25+ SemanticTokensParams , SemanticTokensRangeParams , SemanticTokensRangeResult ,
26+ SemanticTokensResult , SymbolInformation , SymbolTag , TextDocumentIdentifier , Url , WorkspaceEdit ,
2627} ;
2728use project_model:: { ManifestPath , ProjectWorkspace , TargetKind } ;
2829use serde_json:: json;
@@ -33,7 +34,7 @@ use vfs::{AbsPath, AbsPathBuf, VfsPath};
3334
3435use crate :: {
3536 cargo_target_spec:: CargoTargetSpec ,
36- config:: { RustfmtConfig , WorkspaceSymbolConfig } ,
37+ config:: { Config , RustfmtConfig , WorkspaceSymbolConfig } ,
3738 diff:: diff,
3839 from_proto,
3940 global_state:: { GlobalState , GlobalStateSnapshot } ,
@@ -1030,7 +1031,23 @@ pub(crate) fn handle_rename(
10301031 if !change. file_system_edits . is_empty ( ) && snap. config . will_rename ( ) {
10311032 change. source_file_edits . clear ( ) ;
10321033 }
1034+
10331035 let workspace_edit = to_proto:: workspace_edit ( & snap, change) ?;
1036+
1037+ if let Some ( lsp_types:: DocumentChanges :: Operations ( ops) ) =
1038+ workspace_edit. document_changes . as_ref ( )
1039+ {
1040+ for op in ops {
1041+ if let lsp_types:: DocumentChangeOperation :: Op ( doc_change_op) = op {
1042+ if let Err ( err) =
1043+ resource_ops_supported ( & snap. config , resolve_resource_op ( doc_change_op) )
1044+ {
1045+ return Err ( err) ;
1046+ }
1047+ }
1048+ }
1049+ }
1050+
10341051 Ok ( Some ( workspace_edit) )
10351052}
10361053
@@ -1137,6 +1154,20 @@ pub(crate) fn handle_code_action(
11371154 let resolve_data =
11381155 if code_action_resolve_cap { Some ( ( index, params. clone ( ) ) ) } else { None } ;
11391156 let code_action = to_proto:: code_action ( & snap, assist, resolve_data) ?;
1157+
1158+ // Check if the client supports the necessary `ResourceOperation`s.
1159+ if let Some ( changes) = & code_action. edit . as_ref ( ) . unwrap ( ) . document_changes {
1160+ for change in changes {
1161+ if let lsp_ext:: SnippetDocumentChangeOperation :: Op ( res_op) = change {
1162+ if let Err ( err) =
1163+ resource_ops_supported ( & snap. config , resolve_resource_op ( res_op) )
1164+ {
1165+ return Err ( err) ;
1166+ }
1167+ }
1168+ }
1169+ }
1170+
11401171 res. push ( code_action)
11411172 }
11421173
@@ -1219,6 +1250,21 @@ pub(crate) fn handle_code_action_resolve(
12191250 let ca = to_proto:: code_action ( & snap, assist. clone ( ) , None ) ?;
12201251 code_action. edit = ca. edit ;
12211252 code_action. command = ca. command ;
1253+
1254+ if let Some ( edit) = code_action. edit . as_ref ( ) {
1255+ if let Some ( changes) = edit. document_changes . as_ref ( ) {
1256+ for change in changes {
1257+ if let lsp_ext:: SnippetDocumentChangeOperation :: Op ( res_op) = change {
1258+ if let Err ( err) =
1259+ resource_ops_supported ( & snap. config , resolve_resource_op ( res_op) )
1260+ {
1261+ return Err ( err) ;
1262+ }
1263+ }
1264+ }
1265+ }
1266+ }
1267+
12221268 Ok ( code_action)
12231269}
12241270
@@ -1990,3 +2036,43 @@ fn to_url(path: VfsPath) -> Option<Url> {
19902036 let str_path = path. as_os_str ( ) . to_str ( ) ?;
19912037 Url :: from_file_path ( str_path) . ok ( )
19922038}
2039+
2040+ fn resource_ops_supported ( config : & Config , kind : ResourceOperationKind ) -> anyhow:: Result < ( ) > {
2041+ let ctn = config
2042+ . caps ( )
2043+ . workspace
2044+ . as_ref ( )
2045+ . unwrap ( )
2046+ . workspace_edit
2047+ . as_ref ( )
2048+ . unwrap ( )
2049+ . resource_operations
2050+ . as_ref ( )
2051+ . unwrap ( )
2052+ . contains ( & kind) ;
2053+
2054+ if !ctn {
2055+ return Err ( LspError :: new (
2056+ ErrorCode :: RequestFailed as i32 ,
2057+ format ! (
2058+ "Client does not support {} capability." ,
2059+ match kind {
2060+ ResourceOperationKind :: Create => "create" ,
2061+ ResourceOperationKind :: Rename => "rename" ,
2062+ ResourceOperationKind :: Delete => "delete" ,
2063+ }
2064+ ) ,
2065+ )
2066+ . into ( ) ) ;
2067+ }
2068+
2069+ Ok ( ( ) )
2070+ }
2071+
2072+ fn resolve_resource_op ( op : & ResourceOp ) -> ResourceOperationKind {
2073+ match op {
2074+ ResourceOp :: Create ( _) => ResourceOperationKind :: Create ,
2075+ ResourceOp :: Rename ( _) => ResourceOperationKind :: Rename ,
2076+ ResourceOp :: Delete ( _) => ResourceOperationKind :: Delete ,
2077+ }
2078+ }
0 commit comments