Skip to content

Commit b206f48

Browse files
amiraliescristianoc
authored andcommitted
Add rename command
1 parent a2c8eff commit b206f48

File tree

4 files changed

+134
-3
lines changed

4 files changed

+134
-3
lines changed

analysis/src/Cli.ml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ API examples:
88
./rescript-editor-analysis.exe documentSymbol src/Foo.res
99
./rescript-editor-analysis.exe hover src/MyFile.res 10 2
1010
./rescript-editor-analysis.exe references src/MyFile.res 10 2
11+
./rescript-editor-analysis.exe rename src/MyFile.res 10 2 foo
1112

1213
Dev-time examples:
1314
./rescript-editor-analysis.exe dump src/MyFile.res src/MyFile2.res
@@ -38,6 +39,10 @@ Options:
3839

3940
./rescript-editor-analysis.exe references src/MyFile.res 10 2
4041

42+
rename: rename all appearances of item in MyFile.res at line 10 column 2 with foo:
43+
44+
./rescript-editor-analysis.exe rename src/MyFile.res 10 2 foo
45+
4146
dump: for debugging, show all definitions and hovers for MyFile.res and MyFile.res:
4247

4348
./rescript-editor-analysis.exe dump src/Foo.res src/MyFile.res
@@ -50,8 +55,8 @@ Options:
5055
let main () =
5156
match Array.to_list Sys.argv with
5257
| [_; "completion"; path; line; col; currentFile] ->
53-
Commands.completion ~path ~line:(int_of_string line) ~col:(int_of_string col)
54-
~currentFile
58+
Commands.completion ~path ~line:(int_of_string line)
59+
~col:(int_of_string col) ~currentFile
5560
| [_; "definition"; path; line; col] ->
5661
Commands.definition ~path ~line:(int_of_string line)
5762
~col:(int_of_string col)
@@ -62,6 +67,9 @@ let main () =
6267
| [_; "references"; path; line; col] ->
6368
Commands.references ~path ~line:(int_of_string line)
6469
~col:(int_of_string col)
70+
| [_; "rename"; path; line; col; newName] ->
71+
Commands.rename ~path ~line:(int_of_string line) ~col:(int_of_string col)
72+
~newName
6573
| [_; "test"; path] -> Commands.test ~path
6674
| args when List.mem "-h" args || List.mem "--help" args -> prerr_endline help
6775
| _ ->

analysis/src/Commands.ml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,78 @@ let documentSymbol ~path =
176176
in
177177
print_endline ("[\n" ^ (allSymbols |> String.concat ",\n") ^ "\n]")
178178

179+
let rename ~path ~line ~col ~newName =
180+
let uri = Uri2.fromPath path in
181+
let result =
182+
match ProcessCmt.getFullFromCmt ~uri with
183+
| None -> Protocol.null
184+
| Some full -> (
185+
let pos = Utils.protocolLineColToCmtLoc ~line ~col in
186+
match References.locItemForPos ~full pos with
187+
| None -> Protocol.null
188+
| Some locItem ->
189+
let allReferences = References.allReferencesForLocItem ~full locItem in
190+
let referencesToToplevelModules, referencesToItems =
191+
allReferences
192+
|> List.fold_left
193+
(fun acc (uri2, references) ->
194+
(references |> List.map (fun loc -> (uri2, loc))) @ acc)
195+
[]
196+
|> List.partition (fun (_, loc) -> Utils.isTopLoc loc)
197+
in
198+
let fileRenames =
199+
referencesToToplevelModules
200+
|> List.map (fun (uri, _) ->
201+
let path = Uri2.toPath uri in
202+
let dir = Filename.dirname path in
203+
let ext = Filename.extension path in
204+
let sep = Filename.dir_sep in
205+
let newPath = dir ^ sep ^ newName ^ ext in
206+
let newUri = Uri2.fromPath newPath in
207+
Protocol.
208+
{
209+
kind = `rename;
210+
oldUri = uri |> Uri2.toString;
211+
newUri = newUri |> Uri2.toString;
212+
})
213+
in
214+
let textDocumentEdits =
215+
let module StringMap = Misc.StringMap in
216+
let textEditsByUri =
217+
referencesToItems
218+
|> List.map (fun (uri, loc) -> (Uri2.toString uri, loc))
219+
|> List.fold_left
220+
(fun acc (uri, loc) ->
221+
let textEdit =
222+
Protocol.
223+
{range = Utils.cmtLocToRange loc; newText = newName}
224+
in
225+
match StringMap.find_opt uri acc with
226+
| None -> StringMap.add uri [textEdit] acc
227+
| Some prevEdits ->
228+
StringMap.add uri (textEdit :: prevEdits) acc)
229+
StringMap.empty
230+
in
231+
StringMap.fold
232+
(fun uri edits acc ->
233+
let textDocumentEdit =
234+
Protocol.{textDocument = {uri; version = None}; edits}
235+
in
236+
textDocumentEdit :: acc)
237+
textEditsByUri []
238+
in
239+
let fileRenamesString =
240+
fileRenames |> List.map Protocol.stringifyRenameFile
241+
in
242+
let textDocumentEditsString =
243+
textDocumentEdits |> List.map Protocol.stringifyTextDocumentEdit
244+
in
245+
"[\n"
246+
^ (fileRenamesString @ textDocumentEditsString |> String.concat ",\n")
247+
^ "\n]")
248+
in
249+
print_endline result
250+
179251
let test ~path =
180252
Uri2.stripPath := true;
181253
match Files.readFile path with

analysis/src/Protocol.ml

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ type location = {uri : string; range : range}
1818

1919
type documentSymbolItem = {name : string; kind : int; location : location}
2020

21+
type renameFile = {kind : [`rename]; oldUri : string; newUri : string}
22+
23+
type textEdit = {range : range; newText : string}
24+
25+
type optionalVersionedTextDocumentIdentifier = {
26+
version : int option;
27+
uri : string;
28+
}
29+
30+
type textDocumentEdit = {
31+
textDocument : optionalVersionedTextDocumentIdentifier;
32+
edits : textEdit list;
33+
}
34+
2135
let null = "null"
2236

2337
let array l = "[" ^ String.concat ", " l ^ "]"
@@ -52,7 +66,7 @@ let stringifyCompletionItem c =
5266
let stringifyHover h =
5367
Printf.sprintf {|{"contents": "%s"}|} (Json.escape h.contents)
5468

55-
let stringifyLocation h =
69+
let stringifyLocation (h : location) =
5670
Printf.sprintf {|{"uri": "%s", "range": %s}|} (Json.escape h.uri)
5771
(stringifyRange h.range)
5872

@@ -65,3 +79,34 @@ let stringifyDocumentSymbolItem i =
6579
}|}
6680
(Json.escape i.name) i.kind
6781
(stringifyLocation i.location)
82+
83+
let stringifyRenameFile rf =
84+
Printf.sprintf {|{
85+
"kind": "rename",
86+
"oldUri": "%s",
87+
"newUri": "%s"
88+
}|}
89+
(Json.escape rf.oldUri) (Json.escape rf.newUri)
90+
91+
let stringifyTextEdit te =
92+
Printf.sprintf {|{
93+
"range": %s,
94+
"newText": "%s"
95+
}|}
96+
(stringifyRange te.range) (Json.escape te.newText)
97+
98+
let stringifyoptionalVersionedTextDocumentIdentifier td =
99+
Printf.sprintf {|{
100+
"version": %s,
101+
"uri": "%s"
102+
}|}
103+
(match td.version with None -> null | Some v -> string_of_int v)
104+
(Json.escape td.uri)
105+
106+
let stringifyTextDocumentEdit tde =
107+
Printf.sprintf {|{
108+
"textDocument": %s,
109+
"edits": %s
110+
}|}
111+
(stringifyoptionalVersionedTextDocumentIdentifier tde.textDocument)
112+
(tde.edits |> List.map stringifyTextEdit |> array)

analysis/src/Utils.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ let topLoc fname =
77
loc_ghost = false;
88
}
99

10+
let isTopLoc (loc : Warnings.loc) =
11+
let isTopPos (pos : Lexing.position) =
12+
pos.pos_lnum = 1 && pos.pos_bol = 0 && pos.pos_cnum = 0
13+
in
14+
isTopPos loc.loc_start && isTopPos loc.loc_end && loc.loc_ghost = false
15+
1016
(**
1117
* `startsWith(string, prefix)`
1218
* true if the string starts with the prefix

0 commit comments

Comments
 (0)