@@ -8,6 +8,7 @@ use std::{
8
8
} ;
9
9
10
10
use anyhow:: Context ;
11
+
11
12
use ide:: {
12
13
AnnotationConfig , AssistKind , AssistResolveStrategy , Cancellable , FilePosition , FileRange ,
13
14
HoverAction , HoverGotoTypeData , Query , RangeInfo , ReferenceCategory , Runnable , RunnableKind ,
@@ -20,9 +21,9 @@ use lsp_types::{
20
21
CallHierarchyOutgoingCall , CallHierarchyOutgoingCallsParams , CallHierarchyPrepareParams ,
21
22
CodeLens , CompletionItem , FoldingRange , FoldingRangeParams , HoverContents , InlayHint ,
22
23
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 ,
26
27
} ;
27
28
use project_model:: { ManifestPath , ProjectWorkspace , TargetKind } ;
28
29
use serde_json:: json;
@@ -33,7 +34,7 @@ use vfs::{AbsPath, AbsPathBuf, VfsPath};
33
34
34
35
use crate :: {
35
36
cargo_target_spec:: CargoTargetSpec ,
36
- config:: { RustfmtConfig , WorkspaceSymbolConfig } ,
37
+ config:: { Config , RustfmtConfig , WorkspaceSymbolConfig } ,
37
38
diff:: diff,
38
39
from_proto,
39
40
global_state:: { GlobalState , GlobalStateSnapshot } ,
@@ -1030,7 +1031,23 @@ pub(crate) fn handle_rename(
1030
1031
if !change. file_system_edits . is_empty ( ) && snap. config . will_rename ( ) {
1031
1032
change. source_file_edits . clear ( ) ;
1032
1033
}
1034
+
1033
1035
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
+
1034
1051
Ok ( Some ( workspace_edit) )
1035
1052
}
1036
1053
@@ -1137,6 +1154,20 @@ pub(crate) fn handle_code_action(
1137
1154
let resolve_data =
1138
1155
if code_action_resolve_cap { Some ( ( index, params. clone ( ) ) ) } else { None } ;
1139
1156
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
+
1140
1171
res. push ( code_action)
1141
1172
}
1142
1173
@@ -1219,6 +1250,21 @@ pub(crate) fn handle_code_action_resolve(
1219
1250
let ca = to_proto:: code_action ( & snap, assist. clone ( ) , None ) ?;
1220
1251
code_action. edit = ca. edit ;
1221
1252
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
+
1222
1268
Ok ( code_action)
1223
1269
}
1224
1270
@@ -1990,3 +2036,43 @@ fn to_url(path: VfsPath) -> Option<Url> {
1990
2036
let str_path = path. as_os_str ( ) . to_str ( ) ?;
1991
2037
Url :: from_file_path ( str_path) . ok ( )
1992
2038
}
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