From f4de32a0b8ddf00df0eedb4ccdf5ef60e6666c34 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 27 Apr 2023 20:57:34 -0300 Subject: [PATCH 01/10] feat(codeactions): open res/resi/js and create resi --- analysis/src/CodeActions.ml | 14 +- analysis/src/Commands.ml | 32 +-- analysis/src/FindFiles.ml | 43 ++++ analysis/src/Hint.ml | 1 + analysis/src/OpenCompiled.ml | 40 ++++ analysis/src/Protocol.ml | 64 ++++-- analysis/src/Xform.ml | 187 +++++++++++++++++- .../not_compiled/expected/DocTemplate.res.txt | 7 + .../expected/DocTemplate.resi.txt | 7 + analysis/tests/src/expected/CodeLens.res.txt | 20 +- analysis/tests/src/expected/Xform.res.txt | 12 ++ server/src/server.ts | 54 +++++ 12 files changed, 432 insertions(+), 49 deletions(-) create mode 100644 analysis/src/OpenCompiled.ml diff --git a/analysis/src/CodeActions.ml b/analysis/src/CodeActions.ml index 0d383685c..c944ab430 100644 --- a/analysis/src/CodeActions.ml +++ b/analysis/src/CodeActions.ml @@ -5,14 +5,6 @@ let stringifyCodeActions codeActions = Printf.sprintf {|%s|} (codeActions |> List.map Protocol.stringifyCodeAction |> Protocol.array) -let make ~title ~kind ~uri ~newText ~range = - let uri = uri |> Uri.fromPath |> Uri.toString in - { - Protocol.title; - codeActionKind = kind; - edit = - { - documentChanges = - [{textDocument = {version = None; uri}; edits = [{newText; range}]}]; - }; - } +let make ~title ~kind ~(edit : Protocol.codeActionEdit option) + ~(command : Protocol.command option) = + {Protocol.title; codeActionKind = kind; edit; command} diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 4341c4f82..83f20f196 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -220,7 +220,8 @@ let rename ~path ~pos ~newName ~debug = StringMap.fold (fun uri edits acc -> let textDocumentEdit = - Protocol.{textDocument = {uri; version = None}; edits} + Protocol.TextDocumentEdit + Protocol.{textDocument = {uri; version = None}; edits} in textDocumentEdit :: acc) textEditsByUri [] @@ -380,18 +381,25 @@ let test ~path = ~debug:true in codeActions - |> List.iter (fun {Protocol.title; edit = {documentChanges}} -> + |> List.iter (fun {Protocol.title; edit} -> Printf.printf "Hit: %s\n" title; - documentChanges - |> List.iter (fun {Protocol.edits} -> - edits - |> List.iter (fun {Protocol.range; newText} -> - let indent = - String.make range.start.character ' ' - in - Printf.printf "%s\nnewText:\n%s<--here\n%s%s\n" - (Protocol.stringifyRange range) - indent indent newText))) + match edit with + | Some {documentChanges} -> + documentChanges + |> List.iter (fun kindEdit -> + match kindEdit with + | Protocol.TextDocumentEdit {edits} -> + edits + |> List.iter (fun {Protocol.range; newText} -> + let indent = + String.make range.start.character ' ' + in + Printf.printf + "%s\nnewText:\n%s<--here\n%s%s\n" + (Protocol.stringifyRange range) + indent indent newText) + | _ -> ()) + | None -> ()) | "dia" -> diagnosticSyntax ~path | "hin" -> (* Get all inlay Hint between line 1 and n. diff --git a/analysis/src/FindFiles.ml b/analysis/src/FindFiles.ml index bc3219d30..b38cd8b06 100644 --- a/analysis/src/FindFiles.ml +++ b/analysis/src/FindFiles.ml @@ -258,3 +258,46 @@ let findDependencyFiles base config = in let allFiles = projectFiles @ collectFiles stdlibDirectory in Some (compiledDirectories, allFiles) + +let getSuffix config = + config |> Json.get "suffix" |> bind Json.string |> Option.value ~default:".js" + +type packageSpec = { + module_format: string; + in_source: bool; + suffix: string option; +} +let getPackageSpec config = + let get_spec obj = + let module_format = + obj |> Json.get "module" |> bind Json.string + |> Option.value ~default:"commonjs" + in + let in_source = + obj |> Json.get "in-source" |> bind Json.bool + |> Option.value ~default:false + in + let suffix = obj |> Json.get "suffix" |> bind Json.string in + {module_format; in_source; suffix} + in + + let spec = config |> Json.get "package-specs" in + match spec with + | Some s -> ( + let isArray = spec |> bind Json.array in + match isArray with + | Some arr -> ( + (* Get the first element *) + match arr with + | first :: _ -> Some (get_spec first) + | [] -> None) + (* Object config *) + | None -> Some (get_spec s)) + | None -> None + +let rec findProjectRoot ~dir = + let bsconfigFile = dir /+ "bsconfig.json" in + if Sys.file_exists bsconfigFile then Some dir + else + let parent = dir |> Filename.dirname in + if parent = dir then None else findProjectRoot ~dir:parent diff --git a/analysis/src/Hint.ml b/analysis/src/Hint.ml index 227d70f38..17d940929 100644 --- a/analysis/src/Hint.ml +++ b/analysis/src/Hint.ml @@ -166,6 +166,7 @@ let codeLens ~path ~debug = single line in the editor. *) title = typeExpr |> Shared.typeToString ~lineWidth:400; + arguments = None; }; }) | _ -> None) diff --git a/analysis/src/OpenCompiled.ml b/analysis/src/OpenCompiled.ml new file mode 100644 index 000000000..fc1e8a4a6 --- /dev/null +++ b/analysis/src/OpenCompiled.ml @@ -0,0 +1,40 @@ +let ( /+ ) = Filename.concat + +let command ~path = + let dir = Filename.dirname path in + let projDir = FindFiles.findProjectRoot ~dir in + match projDir with + | None -> None + | Some projDir -> ( + let bsconfig = projDir /+ "bsconfig.json" in + match Files.readFile bsconfig with + | None -> None + | Some text -> ( + match Json.parse text with + | None -> None + | Some config -> ( + let pkgSpecs = config |> FindFiles.getPackageSpec in + match pkgSpecs with + | None -> None + | Some {module_format; in_source; suffix} -> + let compiledFolderName = + match module_format with + | "es6" -> "es6" + | "es6-global" -> "es6_global" + | _ -> "js" + in + let suffix_file = + match suffix with + | Some s -> s + | None -> FindFiles.getSuffix config + in + let partialFileSplit = Files.split projDir path in + let partialFilePath = List.nth partialFileSplit 0 in + let pathFragment = + if not in_source then "/lib" /+ compiledFolderName else "" + in + let compileFilePath = + Filename.chop_extension partialFilePath ^ suffix_file + in + let path = projDir ^ pathFragment ^ compileFilePath in + Some path))) \ No newline at end of file diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index 1f23f522e..12ac1bdb8 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -3,7 +3,7 @@ type range = {start: position; end_: position} type markupContent = {kind: string; value: string} (* https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#command *) -type command = {title: string; command: string} +type command = {title: string; command: string; arguments: string list option} (* https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeLens *) type codeLens = {range: range; command: command option} @@ -74,13 +74,20 @@ type textDocumentEdit = { edits: textEdit list; } -type codeActionEdit = {documentChanges: textDocumentEdit list} +type createFile = {uri: string} + +type kindEdit = + | TextDocumentEdit of textDocumentEdit + | CreateFile of createFile + +type codeActionEdit = {documentChanges: kindEdit list} type codeActionKind = RefactorRewrite type codeAction = { title: string; codeActionKind: codeActionKind; - edit: codeActionEdit; + edit: codeActionEdit option; + command: command option; } let null = "null" @@ -212,13 +219,20 @@ let stringifyoptionalVersionedTextDocumentIdentifier td = | Some v -> string_of_int v) (Json.escape td.uri) -let stringifyTextDocumentEdit tde = - Printf.sprintf {|{ +let stringifyTextDocumentEdit (tde : kindEdit) = + match tde with + | TextDocumentEdit edit -> + Printf.sprintf {|{ "textDocument": %s, "edits": %s }|} - (stringifyoptionalVersionedTextDocumentIdentifier tde.textDocument) - (tde.edits |> List.map stringifyTextEdit |> array) + (stringifyoptionalVersionedTextDocumentIdentifier edit.textDocument) + (edit.edits |> List.map stringifyTextEdit |> array) + | CreateFile file -> + Printf.sprintf {|{ + "kind": "create", + "uri": "%s" + }|} file.uri let codeActionKindToString kind = match kind with @@ -228,10 +242,32 @@ let stringifyCodeActionEdit cae = Printf.sprintf {|{"documentChanges": %s}|} (cae.documentChanges |> List.map stringifyTextDocumentEdit |> array) -let stringifyCodeAction ca = - Printf.sprintf {|{"title": "%s", "kind": "%s", "edit": %s}|} ca.title - (codeActionKindToString ca.codeActionKind) - (ca.edit |> stringifyCodeActionEdit) +let stringifyCommand (command : command) = + stringifyObject + [ + ("title", Some (wrapInQuotes command.title)); + ("command", Some (wrapInQuotes command.command)); + ( "arguments", + match command.arguments with + | None -> None + | Some (hd :: _) -> Some (array [wrapInQuotes hd]) + | Some _ -> None ); + ] + +let stringifyCodeAction (ca : codeAction) = + stringifyObject + [ + ("title", Some (wrapInQuotes ca.title)); + ("kind", Some (wrapInQuotes (codeActionKindToString ca.codeActionKind))); + ( "edit", + match ca.edit with + | None -> None + | Some edit -> Some (edit |> stringifyCodeActionEdit) ); + ( "command", + match ca.command with + | None -> None + | Some command -> Some (command |> stringifyCommand) ); + ] let stringifyHint hint = Printf.sprintf @@ -244,12 +280,6 @@ let stringifyHint hint = }|} (stringifyPosition hint.position) (Json.escape hint.label) hint.kind hint.paddingLeft hint.paddingRight - -let stringifyCommand (command : command) = - Printf.sprintf {|{"title": "%s", "command": "%s"}|} - (Json.escape command.title) - (Json.escape command.command) - let stringifyCodeLens (codeLens : codeLens) = Printf.sprintf {|{ diff --git a/analysis/src/Xform.ml b/analysis/src/Xform.ml index 829b372a5..fad369aa4 100644 --- a/analysis/src/Xform.ml +++ b/analysis/src/Xform.ml @@ -112,7 +112,24 @@ module IfThenElse = struct let newText = printExpr ~range newExpr in let codeAction = CodeActions.make ~title:"Replace with switch" ~kind:RefactorRewrite - ~uri:path ~newText ~range + ~command:None + ~edit: + (Some + Protocol. + { + documentChanges = + [ + TextDocumentEdit + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; + ]; + }) in codeActions := codeAction :: !codeActions end @@ -176,7 +193,24 @@ module AddBracesToFn = struct let newText = printStructureItem ~range newStructureItem in let codeAction = CodeActions.make ~title:"Add braces to function" ~kind:RefactorRewrite - ~uri:path ~newText ~range + ~command:None + ~edit: + (Some + Protocol. + { + documentChanges = + [ + TextDocumentEdit + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; + ]; + }) in codeActions := codeAction :: !codeActions end @@ -246,7 +280,24 @@ module AddTypeAnnotation = struct in let codeAction = CodeActions.make ~title:"Add type annotation" ~kind:RefactorRewrite - ~uri:path ~newText ~range + ~command:None + ~edit: + (Some + Protocol. + { + documentChanges = + [ + TextDocumentEdit + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; + ]; + }) in codeActions := codeAction :: !codeActions | _ -> ())) @@ -344,7 +395,24 @@ module AddDocTemplate = struct let newText = printSignatureItem ~range signatureItem in let codeAction = CodeActions.make ~title:"Add Documentation template" - ~kind:RefactorRewrite ~uri:path ~newText ~range + ~kind:RefactorRewrite ~command:None + ~edit: + (Some + Protocol. + { + documentChanges = + [ + TextDocumentEdit + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; + ]; + }) in codeActions := codeAction :: !codeActions | None -> ()) @@ -429,13 +497,118 @@ module AddDocTemplate = struct let newText = printStructureItem ~range structureItem in let codeAction = CodeActions.make ~title:"Add Documentation template" - ~kind:RefactorRewrite ~uri:path ~newText ~range + ~kind:RefactorRewrite ~command:None + ~edit: + (Some + Protocol. + { + documentChanges = + [ + TextDocumentEdit + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; + ]; + }) in codeActions := codeAction :: !codeActions | None -> ()) end end +module ExecuteCommands = struct + let openCompiledJS = "rescriptls/open-compiled-js" + let openInterface = "rescriptls/open-interface-file" + let openImplementation = "rescriptls/open-implementation-file" + let createInterface = "rescriptls/create-interface-file" +end + +module OpenCompiledFile = struct + let xform ~path ~codeActions = + match OpenCompiled.command ~path with + | Some path -> + let uri = path |> Uri.fromPath |> Uri.toString in + let title = Filename.basename uri in + let codeAction = + CodeActions.make ~title:("Open " ^ title) ~kind:RefactorRewrite + ~edit:None + ~command: + (Some + Protocol. + { + title = "Open Compiled File"; + command = ExecuteCommands.openCompiledJS; + arguments = Some [uri]; + }) + in + codeActions := codeAction :: !codeActions + | None -> () +end + +module HandleImpltInter = struct + type t = Create | OpenImpl | OpenInter + let xform ~path ~codeActions = + match Files.classifySourceFile path with + | Res -> + let resiFile = path ^ "i" in + if Sys.file_exists resiFile then + let uri = resiFile |> Uri.fromPath |> Uri.toString in + let title = Filename.basename uri in + let openResi = + CodeActions.make ~title:("Open " ^ title) ~kind:RefactorRewrite + ~edit:None + ~command: + (Some + Protocol. + { + title = "Open Interface File"; + command = ExecuteCommands.openInterface; + arguments = Some [uri]; + }) + in + codeActions := openResi :: !codeActions + else + let uri = (path ^ "i") |> Uri.fromPath |> Uri.toString in + let title = Filename.basename uri in + let createResi = + CodeActions.make ~title:("Create " ^ title) ~kind:RefactorRewrite + ~edit:None + ~command: + (Some + Protocol. + { + title = "Create Interface File"; + command = ExecuteCommands.createInterface; + arguments = Some [uri]; + }) + in + codeActions := createResi :: !codeActions + | Resi -> + let resFile = Filename.remove_extension path ^ ".res" in + if Sys.file_exists resFile then + let uri = resFile |> Uri.fromPath |> Uri.toString in + let title = Filename.basename uri in + let openRes = + CodeActions.make ~title:("Open " ^ title) ~kind:RefactorRewrite + ~edit:None + ~command: + (Some + Protocol. + { + title = "Open Implementation File"; + command = ExecuteCommands.openImplementation; + arguments = Some [uri]; + }) + in + codeActions := openRes :: !codeActions + | Other -> () +end + let parseImplementation ~filename = let {Res_driver.parsetree = structure; comments} = Res_driver.parsingEngine.parseImplementation ~forPrinter:false ~filename @@ -496,6 +669,8 @@ let extractCodeActions ~path ~pos ~currentFile ~debug = AddBracesToFn.xform ~pos ~codeActions ~path ~printStructureItem structure; AddDocTemplate.Implementation.xform ~pos ~codeActions ~path ~printStructureItem ~structure; + OpenCompiledFile.xform ~path ~codeActions; + HandleImpltInter.xform ~path ~codeActions; (* This Code Action needs type info *) let () = @@ -510,5 +685,7 @@ let extractCodeActions ~path ~pos ~currentFile ~debug = let signature, printSignatureItem = parseInterface ~filename:currentFile in AddDocTemplate.Interface.xform ~pos ~codeActions ~path ~signature ~printSignatureItem; + HandleImpltInter.xform ~path ~codeActions; + OpenCompiledFile.xform ~path ~codeActions; !codeActions | Other -> [] diff --git a/analysis/tests/not_compiled/expected/DocTemplate.res.txt b/analysis/tests/not_compiled/expected/DocTemplate.res.txt index 5b7ed2a96..0ea8ea6cd 100644 --- a/analysis/tests/not_compiled/expected/DocTemplate.res.txt +++ b/analysis/tests/not_compiled/expected/DocTemplate.res.txt @@ -1,5 +1,6 @@ Xform not_compiled/DocTemplate.res 3:3 can't find module DocTemplate +Hit: Open DocTemplate.resi Hit: Add Documentation template {"start": {"line": 3, "character": 0}, "end": {"line": 5, "character": 9}} newText: @@ -13,6 +14,7 @@ and e = C Xform not_compiled/DocTemplate.res 6:15 can't find module DocTemplate +Hit: Open DocTemplate.resi Hit: Add Documentation template {"start": {"line": 6, "character": 0}, "end": {"line": 6, "character": 33}} newText: @@ -25,6 +27,7 @@ type name = Name(string) Xform not_compiled/DocTemplate.res 8:4 can't find module DocTemplate +Hit: Open DocTemplate.resi Hit: Add Documentation template {"start": {"line": 8, "character": 0}, "end": {"line": 8, "character": 9}} newText: @@ -36,6 +39,7 @@ let a = 1 Xform not_compiled/DocTemplate.res 10:4 can't find module DocTemplate +Hit: Open DocTemplate.resi Hit: Add Documentation template {"start": {"line": 10, "character": 0}, "end": {"line": 10, "character": 20}} newText: @@ -47,6 +51,7 @@ let inc = x => x + 1 Xform not_compiled/DocTemplate.res 12:7 can't find module DocTemplate +Hit: Open DocTemplate.resi Hit: Add Documentation template {"start": {"line": 12, "character": 0}, "end": {"line": 16, "character": 1}} newText: @@ -62,6 +67,7 @@ module T = { Xform not_compiled/DocTemplate.res 14:6 can't find module DocTemplate +Hit: Open DocTemplate.resi Hit: Add Documentation template {"start": {"line": 14, "character": 2}, "end": {"line": 14, "character": 11}} newText: @@ -73,6 +79,7 @@ newText: Xform not_compiled/DocTemplate.res 18:2 can't find module DocTemplate +Hit: Open DocTemplate.resi Hit: Add Documentation template {"start": {"line": 17, "character": 0}, "end": {"line": 18, "character": 46}} newText: diff --git a/analysis/tests/not_compiled/expected/DocTemplate.resi.txt b/analysis/tests/not_compiled/expected/DocTemplate.resi.txt index ed2be7f56..d59ebd08c 100644 --- a/analysis/tests/not_compiled/expected/DocTemplate.resi.txt +++ b/analysis/tests/not_compiled/expected/DocTemplate.resi.txt @@ -1,4 +1,5 @@ Xform not_compiled/DocTemplate.resi 3:3 +Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 3, "character": 0}, "end": {"line": 5, "character": 9}} newText: @@ -11,6 +12,7 @@ type rec t = A | B and e = C Xform not_compiled/DocTemplate.resi 6:15 +Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 6, "character": 0}, "end": {"line": 6, "character": 33}} newText: @@ -22,6 +24,7 @@ newText: type name = Name(string) Xform not_compiled/DocTemplate.resi 8:4 +Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 8, "character": 0}, "end": {"line": 8, "character": 10}} newText: @@ -32,6 +35,7 @@ newText: let a: int Xform not_compiled/DocTemplate.resi 10:4 +Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 10, "character": 0}, "end": {"line": 10, "character": 19}} newText: @@ -42,6 +46,7 @@ newText: let inc: int => int Xform not_compiled/DocTemplate.resi 12:7 +Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 12, "character": 0}, "end": {"line": 16, "character": 1}} newText: @@ -56,6 +61,7 @@ module T: { } Xform not_compiled/DocTemplate.resi 14:6 +Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 14, "character": 2}, "end": {"line": 14, "character": 12}} newText: @@ -66,6 +72,7 @@ newText: let b: int Xform not_compiled/DocTemplate.resi 18:2 +Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 17, "character": 0}, "end": {"line": 18, "character": 46}} newText: diff --git a/analysis/tests/src/expected/CodeLens.res.txt b/analysis/tests/src/expected/CodeLens.res.txt index 06472d5e4..24cec197b 100644 --- a/analysis/tests/src/expected/CodeLens.res.txt +++ b/analysis/tests/src/expected/CodeLens.res.txt @@ -1,15 +1,27 @@ Code Lens src/CodeLens.res [{ "range": {"start": {"line": 9, "character": 4}, "end": {"line": 9, "character": 8}}, - "command": {"title": "{\"name\": string} => React.element", "command": ""} + "command": { + "title": "{\"name\": string} => React.element", + "command": "" + } }, { "range": {"start": {"line": 4, "character": 4}, "end": {"line": 4, "character": 6}}, - "command": {"title": "(~opt1: int=?, ~a: int, ~b: int, unit, ~opt2: int=?, unit, ~c: int) => int", "command": ""} + "command": { + "title": "(~opt1: int=?, ~a: int, ~b: int, unit, ~opt2: int=?, unit, ~c: int) => int", + "command": "" + } }, { "range": {"start": {"line": 2, "character": 4}, "end": {"line": 2, "character": 7}}, - "command": {"title": "(~age: int, ~name: string) => string", "command": ""} + "command": { + "title": "(~age: int, ~name: string) => string", + "command": "" + } }, { "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 7}}, - "command": {"title": "(int, int) => int", "command": ""} + "command": { + "title": "(int, int) => int", + "command": "" + } }] diff --git a/analysis/tests/src/expected/Xform.res.txt b/analysis/tests/src/expected/Xform.res.txt index 9de1f9f2d..70a1cf923 100644 --- a/analysis/tests/src/expected/Xform.res.txt +++ b/analysis/tests/src/expected/Xform.res.txt @@ -1,4 +1,5 @@ Xform src/Xform.res 6:5 +Hit: Create Xform.resi Hit: Replace with switch {"start": {"line": 6, "character": 0}, "end": {"line": 11, "character": 1}} newText: @@ -11,6 +12,7 @@ switch kind { } Xform src/Xform.res 13:15 +Hit: Create Xform.resi Hit: Replace with switch {"start": {"line": 13, "character": 0}, "end": {"line": 13, "character": 79}} newText: @@ -26,6 +28,7 @@ Hit: Add type annotation newText: <--here : string +Hit: Create Xform.resi Hit: Add Documentation template {"start": {"line": 16, "character": 0}, "end": {"line": 16, "character": 18}} newText: @@ -36,6 +39,7 @@ newText: let name = "hello" Xform src/Xform.res 19:5 +Hit: Create Xform.resi Hit: Add Documentation template {"start": {"line": 19, "character": 0}, "end": {"line": 19, "character": 23}} newText: @@ -51,8 +55,10 @@ Hit: Add type annotation newText: <--here (x: option) +Hit: Create Xform.resi Xform src/Xform.res 30:9 +Hit: Create Xform.resi Hit: Add braces to function {"start": {"line": 26, "character": 0}, "end": {"line": 32, "character": 3}} newText: @@ -72,8 +78,10 @@ Hit: Add type annotation newText: <--here : int +Hit: Create Xform.resi Xform src/Xform.res 38:5 +Hit: Create Xform.resi Hit: Add Documentation template {"start": {"line": 37, "character": 0}, "end": {"line": 38, "character": 40}} newText: @@ -90,8 +98,10 @@ Hit: Add type annotation newText: <--here : int +Hit: Create Xform.resi Xform src/Xform.res 48:21 +Hit: Create Xform.resi Hit: Add braces to function {"start": {"line": 48, "character": 0}, "end": {"line": 48, "character": 25}} newText: @@ -101,6 +111,7 @@ let noBraces = () => { } Xform src/Xform.res 52:34 +Hit: Create Xform.resi Hit: Add braces to function {"start": {"line": 51, "character": 0}, "end": {"line": 54, "character": 1}} newText: @@ -113,6 +124,7 @@ let nested = () => { } Xform src/Xform.res 62:6 +Hit: Create Xform.resi Hit: Add braces to function {"start": {"line": 58, "character": 4}, "end": {"line": 62, "character": 7}} newText: diff --git a/server/src/server.ts b/server/src/server.ts index 98ec1779f..b9cb0800e 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1021,6 +1021,55 @@ function openCompiledFile(msg: p.RequestMessage): p.Message { return response; } +let executeCommands = [ + "rescriptls/open-compiled-js", + "rescriptls/open-interface-file", + "rescriptls/open-implementation-file", + "rescriptls/create-interface-file" +] + +function executeCommand(msg: p.RequestMessage): p.Message { + let params = msg.params as p.ExecuteCommandParams; + let command = params.command; + let args = params.arguments; + + let response: p.ResponseMessage = { + jsonrpc: c.jsonrpcVersion, + id: msg.id, + result: null, + }; + + if (!args) { + return response; + } + + + let reqParams: p.ShowDocumentParams = { + uri: args[0], + takeFocus: true, + } + + let request: p.RequestMessage = { + jsonrpc: c.jsonrpcVersion, + id: serverSentRequestIdCounter++, + method: "window/showDocument", + params: reqParams + } + + if (command === "rescriptls/open-compiled-js") { + send(request); + } else if (command === "rescriptls/open-interface-file") { + send(request); + } else if (command === "rescriptls/open-implementation-file") { + send(request); + } else if (command === "rescriptls/create-interface-file") { + let uri = lookup.replaceFileExtension(args[0], c.resExt); + send(createInterface({ ...msg, params: { uri } })) + } + + return response +} + function onMessage(msg: p.Message) { if (p.Message.isNotification(msg)) { // notification message, aka the client ends it and doesn't want a reply @@ -1121,6 +1170,9 @@ function onMessage(msg: p.Message) { completionProvider: { triggerCharacters: [".", ">", "@", "~", '"', "=", "("], }, + executeCommandProvider: { + commands: executeCommands + }, semanticTokensProvider: { legend: { tokenTypes: [ @@ -1248,6 +1300,8 @@ function onMessage(msg: p.Message) { if (extName === c.resExt) { send(signatureHelp(msg)); } + } else if (msg.method === p.ExecuteCommandRequest.type.method) { + send(executeCommand(msg)); } else { let response: p.ResponseMessage = { jsonrpc: c.jsonrpcVersion, From dbedb8a00641f62d631cfb4944c065bfa256cb76 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 27 Apr 2023 23:04:08 -0300 Subject: [PATCH 02/10] fix open compiled --- analysis/src/OpenCompiled.ml | 40 ---------------------------- analysis/src/Protocol.ml | 3 +-- analysis/src/Xform.ml | 51 ++++++++++++++++-------------------- server/src/server.ts | 28 +++++++++++++++----- 4 files changed, 44 insertions(+), 78 deletions(-) delete mode 100644 analysis/src/OpenCompiled.ml diff --git a/analysis/src/OpenCompiled.ml b/analysis/src/OpenCompiled.ml deleted file mode 100644 index fc1e8a4a6..000000000 --- a/analysis/src/OpenCompiled.ml +++ /dev/null @@ -1,40 +0,0 @@ -let ( /+ ) = Filename.concat - -let command ~path = - let dir = Filename.dirname path in - let projDir = FindFiles.findProjectRoot ~dir in - match projDir with - | None -> None - | Some projDir -> ( - let bsconfig = projDir /+ "bsconfig.json" in - match Files.readFile bsconfig with - | None -> None - | Some text -> ( - match Json.parse text with - | None -> None - | Some config -> ( - let pkgSpecs = config |> FindFiles.getPackageSpec in - match pkgSpecs with - | None -> None - | Some {module_format; in_source; suffix} -> - let compiledFolderName = - match module_format with - | "es6" -> "es6" - | "es6-global" -> "es6_global" - | _ -> "js" - in - let suffix_file = - match suffix with - | Some s -> s - | None -> FindFiles.getSuffix config - in - let partialFileSplit = Files.split projDir path in - let partialFilePath = List.nth partialFileSplit 0 in - let pathFragment = - if not in_source then "/lib" /+ compiledFolderName else "" - in - let compileFilePath = - Filename.chop_extension partialFilePath ^ suffix_file - in - let path = projDir ^ pathFragment ^ compileFilePath in - Some path))) \ No newline at end of file diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index 12ac1bdb8..f42d13fee 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -250,8 +250,7 @@ let stringifyCommand (command : command) = ( "arguments", match command.arguments with | None -> None - | Some (hd :: _) -> Some (array [wrapInQuotes hd]) - | Some _ -> None ); + | Some args -> Some (args |> List.map wrapInQuotes |> array) ); ] let stringifyCodeAction (ca : codeAction) = diff --git a/analysis/src/Xform.ml b/analysis/src/Xform.ml index fad369aa4..0e34557e9 100644 --- a/analysis/src/Xform.ml +++ b/analysis/src/Xform.ml @@ -522,7 +522,7 @@ module AddDocTemplate = struct end module ExecuteCommands = struct - let openCompiledJS = "rescriptls/open-compiled-js" + let openCompiled = "rescriptls/open-compiled-file" let openInterface = "rescriptls/open-interface-file" let openImplementation = "rescriptls/open-implementation-file" let createInterface = "rescriptls/create-interface-file" @@ -530,24 +530,20 @@ end module OpenCompiledFile = struct let xform ~path ~codeActions = - match OpenCompiled.command ~path with - | Some path -> - let uri = path |> Uri.fromPath |> Uri.toString in - let title = Filename.basename uri in - let codeAction = - CodeActions.make ~title:("Open " ^ title) ~kind:RefactorRewrite - ~edit:None - ~command: - (Some - Protocol. - { - title = "Open Compiled File"; - command = ExecuteCommands.openCompiledJS; - arguments = Some [uri]; - }) - in - codeActions := codeAction :: !codeActions - | None -> () + let uri = path |> Uri.fromPath |> Uri.toString in + let codeAction = + CodeActions.make ~title:"Open Compiled JS" ~kind:RefactorRewrite + ~edit:None + ~command: + (Some + Protocol. + { + title = "Open Compiled File"; + command = ExecuteCommands.openCompiled; + arguments = Some [uri]; + }) + in + codeActions := codeAction :: !codeActions end module HandleImpltInter = struct @@ -558,10 +554,9 @@ module HandleImpltInter = struct let resiFile = path ^ "i" in if Sys.file_exists resiFile then let uri = resiFile |> Uri.fromPath |> Uri.toString in - let title = Filename.basename uri in + let title = "Open " ^ Filename.basename uri in let openResi = - CodeActions.make ~title:("Open " ^ title) ~kind:RefactorRewrite - ~edit:None + CodeActions.make ~title ~kind:RefactorRewrite ~edit:None ~command: (Some Protocol. @@ -573,11 +568,10 @@ module HandleImpltInter = struct in codeActions := openResi :: !codeActions else - let uri = (path ^ "i") |> Uri.fromPath |> Uri.toString in - let title = Filename.basename uri in + let uri = path |> Uri.fromPath |> Uri.toString in + let title = "Create " ^ Filename.basename uri ^ "i" in let createResi = - CodeActions.make ~title:("Create " ^ title) ~kind:RefactorRewrite - ~edit:None + CodeActions.make ~title ~kind:RefactorRewrite ~edit:None ~command: (Some Protocol. @@ -592,10 +586,9 @@ module HandleImpltInter = struct let resFile = Filename.remove_extension path ^ ".res" in if Sys.file_exists resFile then let uri = resFile |> Uri.fromPath |> Uri.toString in - let title = Filename.basename uri in + let title = "Open " ^ Filename.basename uri in let openRes = - CodeActions.make ~title:("Open " ^ title) ~kind:RefactorRewrite - ~edit:None + CodeActions.make ~title ~kind:RefactorRewrite ~edit:None ~command: (Some Protocol. diff --git a/server/src/server.ts b/server/src/server.ts index b9cb0800e..58d1cc844 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1022,7 +1022,7 @@ function openCompiledFile(msg: p.RequestMessage): p.Message { } let executeCommands = [ - "rescriptls/open-compiled-js", + "rescriptls/open-compiled-file", "rescriptls/open-interface-file", "rescriptls/open-implementation-file", "rescriptls/create-interface-file" @@ -1043,9 +1043,10 @@ function executeCommand(msg: p.RequestMessage): p.Message { return response; } + let uri = args[0]; let reqParams: p.ShowDocumentParams = { - uri: args[0], + uri, takeFocus: true, } @@ -1056,15 +1057,28 @@ function executeCommand(msg: p.RequestMessage): p.Message { params: reqParams } - if (command === "rescriptls/open-compiled-js") { - send(request); + if (command === "rescriptls/open-compiled-file") { + let message = openCompiledFile({ ...msg, params: { uri } }) + if (p.Message.isResponse(message)) { + let { uri } = message.result as p.TextDocumentIdentifier + let showDocument: p.RequestMessage = { ...request, params: { uri } } + send(showDocument); + } else { + send(message) + } + } else if (command === "rescriptls/create-interface-file") { + let message = createInterface({ ...msg, params: { uri } }) + if (p.Message.isResponse(message)) { + let { uri } = message.result as p.TextDocumentIdentifier + let showDocument: p.RequestMessage = { ...request, params: { uri } } + send(showDocument); + } else { + send(message) + } } else if (command === "rescriptls/open-interface-file") { send(request); } else if (command === "rescriptls/open-implementation-file") { send(request); - } else if (command === "rescriptls/create-interface-file") { - let uri = lookup.replaceFileExtension(args[0], c.resExt); - send(createInterface({ ...msg, params: { uri } })) } return response From 80be0ab612e2017effc3530bd78a43b3613a4c81 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 27 Apr 2023 23:06:35 -0300 Subject: [PATCH 03/10] restore FindFiles --- analysis/src/FindFiles.ml | 43 ------------------- .../not_compiled/expected/DocTemplate.res.txt | 7 +++ .../expected/DocTemplate.resi.txt | 7 +++ analysis/tests/src/expected/Xform.res.txt | 12 ++++++ 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/analysis/src/FindFiles.ml b/analysis/src/FindFiles.ml index b38cd8b06..bc3219d30 100644 --- a/analysis/src/FindFiles.ml +++ b/analysis/src/FindFiles.ml @@ -258,46 +258,3 @@ let findDependencyFiles base config = in let allFiles = projectFiles @ collectFiles stdlibDirectory in Some (compiledDirectories, allFiles) - -let getSuffix config = - config |> Json.get "suffix" |> bind Json.string |> Option.value ~default:".js" - -type packageSpec = { - module_format: string; - in_source: bool; - suffix: string option; -} -let getPackageSpec config = - let get_spec obj = - let module_format = - obj |> Json.get "module" |> bind Json.string - |> Option.value ~default:"commonjs" - in - let in_source = - obj |> Json.get "in-source" |> bind Json.bool - |> Option.value ~default:false - in - let suffix = obj |> Json.get "suffix" |> bind Json.string in - {module_format; in_source; suffix} - in - - let spec = config |> Json.get "package-specs" in - match spec with - | Some s -> ( - let isArray = spec |> bind Json.array in - match isArray with - | Some arr -> ( - (* Get the first element *) - match arr with - | first :: _ -> Some (get_spec first) - | [] -> None) - (* Object config *) - | None -> Some (get_spec s)) - | None -> None - -let rec findProjectRoot ~dir = - let bsconfigFile = dir /+ "bsconfig.json" in - if Sys.file_exists bsconfigFile then Some dir - else - let parent = dir |> Filename.dirname in - if parent = dir then None else findProjectRoot ~dir:parent diff --git a/analysis/tests/not_compiled/expected/DocTemplate.res.txt b/analysis/tests/not_compiled/expected/DocTemplate.res.txt index 0ea8ea6cd..963bff76a 100644 --- a/analysis/tests/not_compiled/expected/DocTemplate.res.txt +++ b/analysis/tests/not_compiled/expected/DocTemplate.res.txt @@ -1,6 +1,7 @@ Xform not_compiled/DocTemplate.res 3:3 can't find module DocTemplate Hit: Open DocTemplate.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 3, "character": 0}, "end": {"line": 5, "character": 9}} newText: @@ -15,6 +16,7 @@ and e = C Xform not_compiled/DocTemplate.res 6:15 can't find module DocTemplate Hit: Open DocTemplate.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 6, "character": 0}, "end": {"line": 6, "character": 33}} newText: @@ -28,6 +30,7 @@ type name = Name(string) Xform not_compiled/DocTemplate.res 8:4 can't find module DocTemplate Hit: Open DocTemplate.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 8, "character": 0}, "end": {"line": 8, "character": 9}} newText: @@ -40,6 +43,7 @@ let a = 1 Xform not_compiled/DocTemplate.res 10:4 can't find module DocTemplate Hit: Open DocTemplate.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 10, "character": 0}, "end": {"line": 10, "character": 20}} newText: @@ -52,6 +56,7 @@ let inc = x => x + 1 Xform not_compiled/DocTemplate.res 12:7 can't find module DocTemplate Hit: Open DocTemplate.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 12, "character": 0}, "end": {"line": 16, "character": 1}} newText: @@ -68,6 +73,7 @@ module T = { Xform not_compiled/DocTemplate.res 14:6 can't find module DocTemplate Hit: Open DocTemplate.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 14, "character": 2}, "end": {"line": 14, "character": 11}} newText: @@ -80,6 +86,7 @@ newText: Xform not_compiled/DocTemplate.res 18:2 can't find module DocTemplate Hit: Open DocTemplate.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 17, "character": 0}, "end": {"line": 18, "character": 46}} newText: diff --git a/analysis/tests/not_compiled/expected/DocTemplate.resi.txt b/analysis/tests/not_compiled/expected/DocTemplate.resi.txt index d59ebd08c..67971149e 100644 --- a/analysis/tests/not_compiled/expected/DocTemplate.resi.txt +++ b/analysis/tests/not_compiled/expected/DocTemplate.resi.txt @@ -1,4 +1,5 @@ Xform not_compiled/DocTemplate.resi 3:3 +Hit: Open Compiled JS Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 3, "character": 0}, "end": {"line": 5, "character": 9}} @@ -12,6 +13,7 @@ type rec t = A | B and e = C Xform not_compiled/DocTemplate.resi 6:15 +Hit: Open Compiled JS Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 6, "character": 0}, "end": {"line": 6, "character": 33}} @@ -24,6 +26,7 @@ newText: type name = Name(string) Xform not_compiled/DocTemplate.resi 8:4 +Hit: Open Compiled JS Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 8, "character": 0}, "end": {"line": 8, "character": 10}} @@ -35,6 +38,7 @@ newText: let a: int Xform not_compiled/DocTemplate.resi 10:4 +Hit: Open Compiled JS Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 10, "character": 0}, "end": {"line": 10, "character": 19}} @@ -46,6 +50,7 @@ newText: let inc: int => int Xform not_compiled/DocTemplate.resi 12:7 +Hit: Open Compiled JS Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 12, "character": 0}, "end": {"line": 16, "character": 1}} @@ -61,6 +66,7 @@ module T: { } Xform not_compiled/DocTemplate.resi 14:6 +Hit: Open Compiled JS Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 14, "character": 2}, "end": {"line": 14, "character": 12}} @@ -72,6 +78,7 @@ newText: let b: int Xform not_compiled/DocTemplate.resi 18:2 +Hit: Open Compiled JS Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 17, "character": 0}, "end": {"line": 18, "character": 46}} diff --git a/analysis/tests/src/expected/Xform.res.txt b/analysis/tests/src/expected/Xform.res.txt index 70a1cf923..016253790 100644 --- a/analysis/tests/src/expected/Xform.res.txt +++ b/analysis/tests/src/expected/Xform.res.txt @@ -1,5 +1,6 @@ Xform src/Xform.res 6:5 Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Replace with switch {"start": {"line": 6, "character": 0}, "end": {"line": 11, "character": 1}} newText: @@ -13,6 +14,7 @@ switch kind { Xform src/Xform.res 13:15 Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Replace with switch {"start": {"line": 13, "character": 0}, "end": {"line": 13, "character": 79}} newText: @@ -29,6 +31,7 @@ newText: <--here : string Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 16, "character": 0}, "end": {"line": 16, "character": 18}} newText: @@ -40,6 +43,7 @@ let name = "hello" Xform src/Xform.res 19:5 Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 19, "character": 0}, "end": {"line": 19, "character": 23}} newText: @@ -56,9 +60,11 @@ newText: <--here (x: option) Hit: Create Xform.resi +Hit: Open Compiled JS Xform src/Xform.res 30:9 Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Add braces to function {"start": {"line": 26, "character": 0}, "end": {"line": 32, "character": 3}} newText: @@ -79,9 +85,11 @@ newText: <--here : int Hit: Create Xform.resi +Hit: Open Compiled JS Xform src/Xform.res 38:5 Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 37, "character": 0}, "end": {"line": 38, "character": 40}} newText: @@ -99,9 +107,11 @@ newText: <--here : int Hit: Create Xform.resi +Hit: Open Compiled JS Xform src/Xform.res 48:21 Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Add braces to function {"start": {"line": 48, "character": 0}, "end": {"line": 48, "character": 25}} newText: @@ -112,6 +122,7 @@ let noBraces = () => { Xform src/Xform.res 52:34 Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Add braces to function {"start": {"line": 51, "character": 0}, "end": {"line": 54, "character": 1}} newText: @@ -125,6 +136,7 @@ let nested = () => { Xform src/Xform.res 62:6 Hit: Create Xform.resi +Hit: Open Compiled JS Hit: Add braces to function {"start": {"line": 58, "character": 4}, "end": {"line": 62, "character": 7}} newText: From bc993303e177486ea06e6426851fb2aded88359e Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 27 Apr 2023 23:20:45 -0300 Subject: [PATCH 04/10] restore Protocol --- analysis/src/Commands.ml | 28 +++--- analysis/src/Protocol.ml | 23 ++--- analysis/src/Xform.ml | 85 +++++++++---------- .../not_compiled/expected/DocTemplate.res.txt | 14 --- .../expected/DocTemplate.resi.txt | 14 --- analysis/tests/src/expected/Xform.res.txt | 24 ------ 6 files changed, 57 insertions(+), 131 deletions(-) diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 83f20f196..998e48955 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -220,8 +220,7 @@ let rename ~path ~pos ~newName ~debug = StringMap.fold (fun uri edits acc -> let textDocumentEdit = - Protocol.TextDocumentEdit - Protocol.{textDocument = {uri; version = None}; edits} + Protocol.{textDocument = {uri; version = None}; edits} in textDocumentEdit :: acc) textEditsByUri [] @@ -382,23 +381,20 @@ let test ~path = in codeActions |> List.iter (fun {Protocol.title; edit} -> - Printf.printf "Hit: %s\n" title; match edit with | Some {documentChanges} -> + Printf.printf "Hit: %s\n" title; documentChanges - |> List.iter (fun kindEdit -> - match kindEdit with - | Protocol.TextDocumentEdit {edits} -> - edits - |> List.iter (fun {Protocol.range; newText} -> - let indent = - String.make range.start.character ' ' - in - Printf.printf - "%s\nnewText:\n%s<--here\n%s%s\n" - (Protocol.stringifyRange range) - indent indent newText) - | _ -> ()) + |> List.iter (fun {Protocol.edits} -> + edits + |> List.iter (fun {Protocol.range; newText} -> + let indent = + String.make range.start.character ' ' + in + Printf.printf + "%s\nnewText:\n%s<--here\n%s%s\n" + (Protocol.stringifyRange range) + indent indent newText)) | None -> ()) | "dia" -> diagnosticSyntax ~path | "hin" -> diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index f42d13fee..91d236787 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -74,13 +74,7 @@ type textDocumentEdit = { edits: textEdit list; } -type createFile = {uri: string} - -type kindEdit = - | TextDocumentEdit of textDocumentEdit - | CreateFile of createFile - -type codeActionEdit = {documentChanges: kindEdit list} +type codeActionEdit = {documentChanges: textDocumentEdit list} type codeActionKind = RefactorRewrite type codeAction = { @@ -219,20 +213,13 @@ let stringifyoptionalVersionedTextDocumentIdentifier td = | Some v -> string_of_int v) (Json.escape td.uri) -let stringifyTextDocumentEdit (tde : kindEdit) = - match tde with - | TextDocumentEdit edit -> - Printf.sprintf {|{ +let stringifyTextDocumentEdit (tde : textDocumentEdit) = + Printf.sprintf {|{ "textDocument": %s, "edits": %s }|} - (stringifyoptionalVersionedTextDocumentIdentifier edit.textDocument) - (edit.edits |> List.map stringifyTextEdit |> array) - | CreateFile file -> - Printf.sprintf {|{ - "kind": "create", - "uri": "%s" - }|} file.uri + (stringifyoptionalVersionedTextDocumentIdentifier tde.textDocument) + (tde.edits |> List.map stringifyTextEdit |> array) let codeActionKindToString kind = match kind with diff --git a/analysis/src/Xform.ml b/analysis/src/Xform.ml index 0e34557e9..101afbb61 100644 --- a/analysis/src/Xform.ml +++ b/analysis/src/Xform.ml @@ -119,15 +119,14 @@ module IfThenElse = struct { documentChanges = [ - TextDocumentEdit - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; ]; }) in @@ -200,15 +199,14 @@ module AddBracesToFn = struct { documentChanges = [ - TextDocumentEdit - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; ]; }) in @@ -287,15 +285,14 @@ module AddTypeAnnotation = struct { documentChanges = [ - TextDocumentEdit - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; ]; }) in @@ -402,15 +399,14 @@ module AddDocTemplate = struct { documentChanges = [ - TextDocumentEdit - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; ]; }) in @@ -504,15 +500,14 @@ module AddDocTemplate = struct { documentChanges = [ - TextDocumentEdit - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; ]; }) in diff --git a/analysis/tests/not_compiled/expected/DocTemplate.res.txt b/analysis/tests/not_compiled/expected/DocTemplate.res.txt index 963bff76a..5b7ed2a96 100644 --- a/analysis/tests/not_compiled/expected/DocTemplate.res.txt +++ b/analysis/tests/not_compiled/expected/DocTemplate.res.txt @@ -1,7 +1,5 @@ Xform not_compiled/DocTemplate.res 3:3 can't find module DocTemplate -Hit: Open DocTemplate.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 3, "character": 0}, "end": {"line": 5, "character": 9}} newText: @@ -15,8 +13,6 @@ and e = C Xform not_compiled/DocTemplate.res 6:15 can't find module DocTemplate -Hit: Open DocTemplate.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 6, "character": 0}, "end": {"line": 6, "character": 33}} newText: @@ -29,8 +25,6 @@ type name = Name(string) Xform not_compiled/DocTemplate.res 8:4 can't find module DocTemplate -Hit: Open DocTemplate.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 8, "character": 0}, "end": {"line": 8, "character": 9}} newText: @@ -42,8 +36,6 @@ let a = 1 Xform not_compiled/DocTemplate.res 10:4 can't find module DocTemplate -Hit: Open DocTemplate.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 10, "character": 0}, "end": {"line": 10, "character": 20}} newText: @@ -55,8 +47,6 @@ let inc = x => x + 1 Xform not_compiled/DocTemplate.res 12:7 can't find module DocTemplate -Hit: Open DocTemplate.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 12, "character": 0}, "end": {"line": 16, "character": 1}} newText: @@ -72,8 +62,6 @@ module T = { Xform not_compiled/DocTemplate.res 14:6 can't find module DocTemplate -Hit: Open DocTemplate.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 14, "character": 2}, "end": {"line": 14, "character": 11}} newText: @@ -85,8 +73,6 @@ newText: Xform not_compiled/DocTemplate.res 18:2 can't find module DocTemplate -Hit: Open DocTemplate.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 17, "character": 0}, "end": {"line": 18, "character": 46}} newText: diff --git a/analysis/tests/not_compiled/expected/DocTemplate.resi.txt b/analysis/tests/not_compiled/expected/DocTemplate.resi.txt index 67971149e..ed2be7f56 100644 --- a/analysis/tests/not_compiled/expected/DocTemplate.resi.txt +++ b/analysis/tests/not_compiled/expected/DocTemplate.resi.txt @@ -1,6 +1,4 @@ Xform not_compiled/DocTemplate.resi 3:3 -Hit: Open Compiled JS -Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 3, "character": 0}, "end": {"line": 5, "character": 9}} newText: @@ -13,8 +11,6 @@ type rec t = A | B and e = C Xform not_compiled/DocTemplate.resi 6:15 -Hit: Open Compiled JS -Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 6, "character": 0}, "end": {"line": 6, "character": 33}} newText: @@ -26,8 +22,6 @@ newText: type name = Name(string) Xform not_compiled/DocTemplate.resi 8:4 -Hit: Open Compiled JS -Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 8, "character": 0}, "end": {"line": 8, "character": 10}} newText: @@ -38,8 +32,6 @@ newText: let a: int Xform not_compiled/DocTemplate.resi 10:4 -Hit: Open Compiled JS -Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 10, "character": 0}, "end": {"line": 10, "character": 19}} newText: @@ -50,8 +42,6 @@ newText: let inc: int => int Xform not_compiled/DocTemplate.resi 12:7 -Hit: Open Compiled JS -Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 12, "character": 0}, "end": {"line": 16, "character": 1}} newText: @@ -66,8 +56,6 @@ module T: { } Xform not_compiled/DocTemplate.resi 14:6 -Hit: Open Compiled JS -Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 14, "character": 2}, "end": {"line": 14, "character": 12}} newText: @@ -78,8 +66,6 @@ newText: let b: int Xform not_compiled/DocTemplate.resi 18:2 -Hit: Open Compiled JS -Hit: Open DocTemplate.res Hit: Add Documentation template {"start": {"line": 17, "character": 0}, "end": {"line": 18, "character": 46}} newText: diff --git a/analysis/tests/src/expected/Xform.res.txt b/analysis/tests/src/expected/Xform.res.txt index 016253790..9de1f9f2d 100644 --- a/analysis/tests/src/expected/Xform.res.txt +++ b/analysis/tests/src/expected/Xform.res.txt @@ -1,6 +1,4 @@ Xform src/Xform.res 6:5 -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Replace with switch {"start": {"line": 6, "character": 0}, "end": {"line": 11, "character": 1}} newText: @@ -13,8 +11,6 @@ switch kind { } Xform src/Xform.res 13:15 -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Replace with switch {"start": {"line": 13, "character": 0}, "end": {"line": 13, "character": 79}} newText: @@ -30,8 +26,6 @@ Hit: Add type annotation newText: <--here : string -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 16, "character": 0}, "end": {"line": 16, "character": 18}} newText: @@ -42,8 +36,6 @@ newText: let name = "hello" Xform src/Xform.res 19:5 -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 19, "character": 0}, "end": {"line": 19, "character": 23}} newText: @@ -59,12 +51,8 @@ Hit: Add type annotation newText: <--here (x: option) -Hit: Create Xform.resi -Hit: Open Compiled JS Xform src/Xform.res 30:9 -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Add braces to function {"start": {"line": 26, "character": 0}, "end": {"line": 32, "character": 3}} newText: @@ -84,12 +72,8 @@ Hit: Add type annotation newText: <--here : int -Hit: Create Xform.resi -Hit: Open Compiled JS Xform src/Xform.res 38:5 -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Add Documentation template {"start": {"line": 37, "character": 0}, "end": {"line": 38, "character": 40}} newText: @@ -106,12 +90,8 @@ Hit: Add type annotation newText: <--here : int -Hit: Create Xform.resi -Hit: Open Compiled JS Xform src/Xform.res 48:21 -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Add braces to function {"start": {"line": 48, "character": 0}, "end": {"line": 48, "character": 25}} newText: @@ -121,8 +101,6 @@ let noBraces = () => { } Xform src/Xform.res 52:34 -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Add braces to function {"start": {"line": 51, "character": 0}, "end": {"line": 54, "character": 1}} newText: @@ -135,8 +113,6 @@ let nested = () => { } Xform src/Xform.res 62:6 -Hit: Create Xform.resi -Hit: Open Compiled JS Hit: Add braces to function {"start": {"line": 58, "character": 4}, "end": {"line": 62, "character": 7}} newText: From c986cdf13a396c063f5b820c7072018e0e5d1e17 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 27 Apr 2023 23:33:18 -0300 Subject: [PATCH 05/10] refactor --- analysis/src/CodeActions.ml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/analysis/src/CodeActions.ml b/analysis/src/CodeActions.ml index c944ab430..05a8fd342 100644 --- a/analysis/src/CodeActions.ml +++ b/analysis/src/CodeActions.ml @@ -5,6 +5,5 @@ let stringifyCodeActions codeActions = Printf.sprintf {|%s|} (codeActions |> List.map Protocol.stringifyCodeAction |> Protocol.array) -let make ~title ~kind ~(edit : Protocol.codeActionEdit option) - ~(command : Protocol.command option) = +let make ~title ~kind ~edit ~command = {Protocol.title; codeActionKind = kind; edit; command} From 6e7d33efbfcc4390c4a62675abd6b568ba3be5c7 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 27 Apr 2023 23:36:33 -0300 Subject: [PATCH 06/10] update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dc01a08a..e09bc2111 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ #### :rocket: New Feature - Docstring template Code Action. https://github.com/rescript-lang/rescript-vscode/pull/764 +- Code Actions: open Implementation/Interface/Compiled and create Interface file. https://github.com/rescript-lang/rescript-vscode/pull/767 #### :bug: Bug Fix From 7fc248f5af583127c9b0ff7251f6697a61148498 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Fri, 28 Apr 2023 02:11:03 -0300 Subject: [PATCH 07/10] use empty kind --- analysis/src/Protocol.ml | 3 ++- analysis/src/Xform.ml | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index 91d236787..17a7cbb1e 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -75,7 +75,7 @@ type textDocumentEdit = { } type codeActionEdit = {documentChanges: textDocumentEdit list} -type codeActionKind = RefactorRewrite +type codeActionKind = RefactorRewrite | Empty type codeAction = { title: string; @@ -224,6 +224,7 @@ let stringifyTextDocumentEdit (tde : textDocumentEdit) = let codeActionKindToString kind = match kind with | RefactorRewrite -> "refactor.rewrite" + | Empty -> "" let stringifyCodeActionEdit cae = Printf.sprintf {|{"documentChanges": %s}|} diff --git a/analysis/src/Xform.ml b/analysis/src/Xform.ml index 101afbb61..e75ebe74f 100644 --- a/analysis/src/Xform.ml +++ b/analysis/src/Xform.ml @@ -527,7 +527,7 @@ module OpenCompiledFile = struct let xform ~path ~codeActions = let uri = path |> Uri.fromPath |> Uri.toString in let codeAction = - CodeActions.make ~title:"Open Compiled JS" ~kind:RefactorRewrite + CodeActions.make ~title:"Open Compiled JS" ~kind:Empty ~edit:None ~command: (Some @@ -551,7 +551,7 @@ module HandleImpltInter = struct let uri = resiFile |> Uri.fromPath |> Uri.toString in let title = "Open " ^ Filename.basename uri in let openResi = - CodeActions.make ~title ~kind:RefactorRewrite ~edit:None + CodeActions.make ~title ~kind:Empty ~edit:None ~command: (Some Protocol. @@ -566,7 +566,7 @@ module HandleImpltInter = struct let uri = path |> Uri.fromPath |> Uri.toString in let title = "Create " ^ Filename.basename uri ^ "i" in let createResi = - CodeActions.make ~title ~kind:RefactorRewrite ~edit:None + CodeActions.make ~title ~kind:Empty ~edit:None ~command: (Some Protocol. @@ -583,7 +583,7 @@ module HandleImpltInter = struct let uri = resFile |> Uri.fromPath |> Uri.toString in let title = "Open " ^ Filename.basename uri in let openRes = - CodeActions.make ~title ~kind:RefactorRewrite ~edit:None + CodeActions.make ~title ~kind:Empty ~edit:None ~command: (Some Protocol. From 18b41c6b85e667e859954d21f020758f972ac765 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Tue, 23 Apr 2024 11:44:59 -0300 Subject: [PATCH 08/10] update CHANGELOG.md and fix tests --- CHANGELOG.md | 2 +- analysis/src/Commands.ml | 8 ++++ analysis/src/Xform.ml | 45 ++++++++++++++++--- .../src/expected/CompletionResolve.res.txt | 2 +- server/src/server.ts | 24 +++++----- 5 files changed, 60 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4258fce38..69f8d9bcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ #### :rocket: New Feature - Add support for the rewatch build system for incremental compilation. https://github.com/rescript-lang/rescript-vscode/pull/965 +- Code Actions: open Implementation/Interface/Compiled Js and create Interface file. https://github.com/rescript-lang/rescript-vscode/pull/767 ## 1.50.0 @@ -208,7 +209,6 @@ #### :rocket: New Feature - Docstring template Code Action. https://github.com/rescript-lang/rescript-vscode/pull/764 -- Code Actions: open Implementation/Interface/Compiled and create Interface file. https://github.com/rescript-lang/rescript-vscode/pull/767 - Improve unlabelled argument names in completion function templates. https://github.com/rescript-lang/rescript-vscode/pull/754 - Add `Some(fieldName)` case when completing in a pattern with an option on a record field. https://github.com/rescript-lang/rescript-vscode/pull/766 diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 5637678ac..f4113cd08 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -449,6 +449,14 @@ let test ~path = (Protocol.stringifyRange range) indent indent newText)) | None -> ()) + | "c-a" -> + let hint = String.sub rest 3 (String.length rest - 3) in + print_endline + ("Codemod AddMissingCases" ^ path ^ " " ^ string_of_int line ^ ":" + ^ string_of_int col); + Codemod.transform ~path ~pos:(line, col) ~debug:true + ~typ:AddMissingCases ~hint + |> print_endline | "dia" -> diagnosticSyntax ~path | "hin" -> (* Get all inlay Hint between line 1 and n. diff --git a/analysis/src/Xform.ml b/analysis/src/Xform.ml index c98757fba..40da93970 100644 --- a/analysis/src/Xform.ml +++ b/analysis/src/Xform.ml @@ -432,8 +432,24 @@ module ExhaustiveSwitch = struct printExpr ~range {expr with pexp_desc = Pexp_match (expr, cases)} in let codeAction = - CodeActions.make ~title:"Exhaustive switch" ~kind:RefactorRewrite - ~uri:path ~newText ~range + CodeActions.make ~command:None ~title:"Exhaustive switch" + ~kind:RefactorRewrite + ~edit: + (Some + Protocol. + { + documentChanges = + [ + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; + ]; + }) in codeActions := codeAction :: !codeActions)) | Some (Switch {switchExpr; completionExpr; pos}) -> ( @@ -458,8 +474,24 @@ module ExhaustiveSwitch = struct {switchExpr with pexp_desc = Pexp_match (completionExpr, cases)} in let codeAction = - CodeActions.make ~title:"Exhaustive switch" ~kind:RefactorRewrite - ~uri:path ~newText ~range + CodeActions.make ~title:"Exhaustive switch" ~command:None + ~kind:RefactorRewrite (* ~uri:path ~newText ~range *) + ~edit: + (Some + Protocol. + { + documentChanges = + [ + { + textDocument = + { + version = None; + uri = path |> Uri.fromPath |> Uri.toString; + }; + edits = [{newText; range}]; + }; + ]; + }) in codeActions := codeAction :: !codeActions)) end @@ -691,8 +723,7 @@ module OpenCompiledFile = struct let xform ~path ~codeActions = let uri = path |> Uri.fromPath |> Uri.toString in let codeAction = - CodeActions.make ~title:"Open Compiled JS" ~kind:Empty - ~edit:None + CodeActions.make ~title:"Open Compiled JS" ~kind:Empty ~edit:None ~command: (Some Protocol. @@ -843,7 +874,7 @@ let extractCodeActions ~path ~startPos ~endPos ~currentFile ~debug = let signature, printSignatureItem = parseInterface ~filename:currentFile in AddDocTemplate.Interface.xform ~pos ~codeActions ~path ~signature ~printSignatureItem; - HandleImpltInter.xform ~path ~codeActions; OpenCompiledFile.xform ~path ~codeActions; + HandleImpltInter.xform ~path ~codeActions; !codeActions | Other -> [] diff --git a/analysis/tests/src/expected/CompletionResolve.res.txt b/analysis/tests/src/expected/CompletionResolve.res.txt index d0492d217..22fdcd689 100644 --- a/analysis/tests/src/expected/CompletionResolve.res.txt +++ b/analysis/tests/src/expected/CompletionResolve.res.txt @@ -1,5 +1,5 @@ Completion resolve: Belt_Array -"\nUtilities for `Array` functions.\n\n### Note about index syntax\n\nCode like `arr[0]` does *not* compile to JavaScript `arr[0]`. Reason transforms\nthe `[]` index syntax into a function: `Array.get(arr, 0)`. By default, this\nuses the default standard library's `Array.get` function, which may raise an\nexception if the index isn't found. If you `open Belt`, it will use the\n`Belt.Array.get` function which returns options instead of raising exceptions. \n[See this for more information](../belt.mdx#array-access-runtime-safety).\n" +"\nUtililites for `Array` functions.\n\n### Note about index syntax\n\nCode like `arr[0]` does *not* compile to JavaScript `arr[0]`. Reason transforms\nthe `[]` index syntax into a function: `Array.get(arr, 0)`. By default, this\nuses the default standard library's `Array.get` function, which may raise an\nexception if the index isn't found. If you `open Belt`, it will use the\n`Belt.Array.get` function which returns options instead of raising exceptions. \n[See this for more information](../belt.mdx#array-access-runtime-safety).\n" Completion resolve: ModuleStuff " This is a top level module doc. " diff --git a/server/src/server.ts b/server/src/server.ts index cb839028c..836ea206b 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -1023,16 +1023,16 @@ function openCompiledFile(msg: p.RequestMessage): p.Message { return response; } -let executeCommands = [ - "rescriptls/open-compiled-file", - "rescriptls/open-interface-file", - "rescriptls/open-implementation-file", - "rescriptls/create-interface-file" -] +enum ExecuteCommands { + OpenCompiledFile = "rescriptls/open-compiled-file", + OpenInterfaceFile = "rescriptls/open-interface-file", + OpenImplentationFile = "rescriptls/open-implementation-file", + CreateInterfaceFile = "rescriptls/create-interface-file" +} function executeCommand(msg: p.RequestMessage): p.Message { let params = msg.params as p.ExecuteCommandParams; - let command = params.command; + let command = params.command as ExecuteCommands; let args = params.arguments; let response: p.ResponseMessage = { @@ -1059,7 +1059,7 @@ function executeCommand(msg: p.RequestMessage): p.Message { params: reqParams } - if (command === "rescriptls/open-compiled-file") { + if (command === ExecuteCommands.OpenCompiledFile) { let message = openCompiledFile({ ...msg, params: { uri } }) if (p.Message.isResponse(message)) { let { uri } = message.result as p.TextDocumentIdentifier @@ -1068,7 +1068,7 @@ function executeCommand(msg: p.RequestMessage): p.Message { } else { send(message) } - } else if (command === "rescriptls/create-interface-file") { + } else if (command === ExecuteCommands.CreateInterfaceFile) { let message = createInterface({ ...msg, params: { uri } }) if (p.Message.isResponse(message)) { let { uri } = message.result as p.TextDocumentIdentifier @@ -1077,9 +1077,9 @@ function executeCommand(msg: p.RequestMessage): p.Message { } else { send(message) } - } else if (command === "rescriptls/open-interface-file") { + } else if (command === ExecuteCommands.OpenInterfaceFile) { send(request); - } else if (command === "rescriptls/open-implementation-file") { + } else if (command === ExecuteCommands.OpenImplentationFile) { send(request); } @@ -1188,7 +1188,7 @@ function onMessage(msg: p.Message) { resolveProvider: true, }, executeCommandProvider: { - commands: executeCommands + commands: [ExecuteCommands.OpenImplentationFile, ExecuteCommands.OpenInterfaceFile, ExecuteCommands.OpenCompiledFile, ExecuteCommands.CreateInterfaceFile] }, semanticTokensProvider: { legend: { From 3eb0e28218c6c00d9ac3f7fa20d023e583d92d10 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 25 Apr 2024 10:54:59 -0300 Subject: [PATCH 09/10] fix tests --- analysis/tests/src/expected/CompletionResolve.res.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/tests/src/expected/CompletionResolve.res.txt b/analysis/tests/src/expected/CompletionResolve.res.txt index 22fdcd689..d0492d217 100644 --- a/analysis/tests/src/expected/CompletionResolve.res.txt +++ b/analysis/tests/src/expected/CompletionResolve.res.txt @@ -1,5 +1,5 @@ Completion resolve: Belt_Array -"\nUtililites for `Array` functions.\n\n### Note about index syntax\n\nCode like `arr[0]` does *not* compile to JavaScript `arr[0]`. Reason transforms\nthe `[]` index syntax into a function: `Array.get(arr, 0)`. By default, this\nuses the default standard library's `Array.get` function, which may raise an\nexception if the index isn't found. If you `open Belt`, it will use the\n`Belt.Array.get` function which returns options instead of raising exceptions. \n[See this for more information](../belt.mdx#array-access-runtime-safety).\n" +"\nUtilities for `Array` functions.\n\n### Note about index syntax\n\nCode like `arr[0]` does *not* compile to JavaScript `arr[0]`. Reason transforms\nthe `[]` index syntax into a function: `Array.get(arr, 0)`. By default, this\nuses the default standard library's `Array.get` function, which may raise an\nexception if the index isn't found. If you `open Belt`, it will use the\n`Belt.Array.get` function which returns options instead of raising exceptions. \n[See this for more information](../belt.mdx#array-access-runtime-safety).\n" Completion resolve: ModuleStuff " This is a top level module doc. " From 817460413b27be9fe7c0d89ebbea733216e4efa8 Mon Sep 17 00:00:00 2001 From: Pedro Castro Date: Thu, 25 Apr 2024 12:00:47 -0300 Subject: [PATCH 10/10] refactor code action edit --- analysis/src/CodeActions.ml | 13 ++++ analysis/src/Xform.ml | 119 +++--------------------------------- 2 files changed, 20 insertions(+), 112 deletions(-) diff --git a/analysis/src/CodeActions.ml b/analysis/src/CodeActions.ml index 05a8fd342..8fffec1ce 100644 --- a/analysis/src/CodeActions.ml +++ b/analysis/src/CodeActions.ml @@ -7,3 +7,16 @@ let stringifyCodeActions codeActions = let make ~title ~kind ~edit ~command = {Protocol.title; codeActionKind = kind; edit; command} + +let makeEdit edits uri = + Protocol. + { + documentChanges = + [ + { + textDocument = + {version = None; uri = uri |> Uri.fromPath |> Uri.toString}; + edits; + }; + ]; + } diff --git a/analysis/src/Xform.ml b/analysis/src/Xform.ml index 40da93970..eff8d37de 100644 --- a/analysis/src/Xform.ml +++ b/analysis/src/Xform.ml @@ -113,22 +113,7 @@ module IfThenElse = struct let codeAction = CodeActions.make ~title:"Replace with switch" ~kind:RefactorRewrite ~command:None - ~edit: - (Some - Protocol. - { - documentChanges = - [ - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; - ]; - }) + ~edit:(Some (CodeActions.makeEdit [{newText; range}] path)) in codeActions := codeAction :: !codeActions end @@ -193,22 +178,7 @@ module AddBracesToFn = struct let codeAction = CodeActions.make ~title:"Add braces to function" ~kind:RefactorRewrite ~command:None - ~edit: - (Some - Protocol. - { - documentChanges = - [ - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; - ]; - }) + ~edit:(Some (CodeActions.makeEdit [{newText; range}] path)) in codeActions := codeAction :: !codeActions end @@ -282,22 +252,7 @@ module AddTypeAnnotation = struct let codeAction = CodeActions.make ~title:"Add type annotation" ~kind:RefactorRewrite ~command:None - ~edit: - (Some - Protocol. - { - documentChanges = - [ - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; - ]; - }) + ~edit:(Some (CodeActions.makeEdit [{newText; range}] path)) in codeActions := codeAction :: !codeActions | _ -> ())) @@ -434,22 +389,7 @@ module ExhaustiveSwitch = struct let codeAction = CodeActions.make ~command:None ~title:"Exhaustive switch" ~kind:RefactorRewrite - ~edit: - (Some - Protocol. - { - documentChanges = - [ - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; - ]; - }) + ~edit:(Some (CodeActions.makeEdit [{newText; range}] path)) in codeActions := codeAction :: !codeActions)) | Some (Switch {switchExpr; completionExpr; pos}) -> ( @@ -476,22 +416,7 @@ module ExhaustiveSwitch = struct let codeAction = CodeActions.make ~title:"Exhaustive switch" ~command:None ~kind:RefactorRewrite (* ~uri:path ~newText ~range *) - ~edit: - (Some - Protocol. - { - documentChanges = - [ - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; - ]; - }) + ~edit:(Some (CodeActions.makeEdit [{newText; range}] path)) in codeActions := codeAction :: !codeActions)) end @@ -589,22 +514,7 @@ module AddDocTemplate = struct let codeAction = CodeActions.make ~title:"Add Documentation template" ~kind:RefactorRewrite ~command:None - ~edit: - (Some - Protocol. - { - documentChanges = - [ - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; - ]; - }) + ~edit:(Some (CodeActions.makeEdit [{newText; range}] path)) in codeActions := codeAction :: !codeActions | None -> ()) @@ -690,22 +600,7 @@ module AddDocTemplate = struct let codeAction = CodeActions.make ~title:"Add Documentation template" ~kind:RefactorRewrite ~command:None - ~edit: - (Some - Protocol. - { - documentChanges = - [ - { - textDocument = - { - version = None; - uri = path |> Uri.fromPath |> Uri.toString; - }; - edits = [{newText; range}]; - }; - ]; - }) + ~edit:(Some (CodeActions.makeEdit [{newText; range}] path)) in codeActions := codeAction :: !codeActions | None -> ())