diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e186337a0..c8ab15d50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,6 @@ jobs: node-version: 16 - run: npm ci - - run: opam install dune cppo - run: npm run compile # These 2 runs (or just the second?) are for when you have opam dependencies. We don't. @@ -63,9 +62,11 @@ jobs: # - run: opam pin add rescript-editor-analysis.dev . --no-action # - run: opam install . --deps-only --with-doc --with-test + - name: Install opam deps + run: opam install . --deps-only + - name: Build and test run: opam exec -- make test - working-directory: analysis # Also avoids artifacts upload permission loss: # https://github.com/actions/upload-artifact/tree/ee69f02b3dfdecd58bb31b4d133da38ba6fe3700#permission-loss diff --git a/.gitignore b/.gitignore index 8590b9e9a..fdb06b70b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ node_modules examples/*/lib analysis/tests/lib analysis/tests/.bsb.lock -analysis/_build analysis/tests/.merlin analysis/rescript-editor-analysis.exe -analysis/_opam +_build +_opam diff --git a/.vscode/settings.json b/.vscode/settings.json index 11909bf1d..c9a75752e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,6 @@ }, "ocaml.sandbox": { "kind": "opam", - "switch": "${workspaceFolder:rescript-vscode}/analysis" + "switch": "${workspaceFolder:rescript-vscode}" } } \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9bbc16c1e..ffd3cee56 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,8 @@ Thanks for your interest. Below is an informal spec of how the plugin's server c │ └── src │ └── extension.ts // Language Client entry point ├── analysis // Native binary powering hover, autocomplete, etc. -│ ├── src +│ ├── bin // Analysis binary +│ ├── src // Analysis Library │ └── rescript-editor-analysis.exe // Dev-time analysis binary ├── package.json // The extension manifest └── server // Language Server. Usable standalone @@ -32,7 +33,7 @@ This is needed for the `analysis` folder, which is native code. ```sh # If you haven't created the switch, do it. OPAM(https://opam.ocaml.org) -opam switch 4.14.0 # can also create local switch with opam switch create . 4.14.0 +opam switch create . --deps-only # Install dev dependencies from OPAM opam install . --deps-only diff --git a/analysis/rescript-vscode.opam b/analysis.opam similarity index 84% rename from analysis/rescript-vscode.opam rename to analysis.opam index 1645dea53..ed9d431a1 100644 --- a/analysis/rescript-vscode.opam +++ b/analysis.opam @@ -1,19 +1,20 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -synopsis: "ReScript vscode support" +synopsis: "ReScript Analysis" maintainer: ["Cristiano Calcagno"] authors: ["Cristiano Calcagno"] homepage: "https://github.com/rescript-lang/rescript-vscode" bug-reports: "https://github.com/rescript-lang/rescript-vscode/issues" depends: [ + "dune" {>= "3.0"} "ocaml" {>= "4.10"} "ocamlformat" {= "0.22.4"} "cppo" {= "1.6.9"} "reanalyze" {= "2.23.0"} - "dune" + "odoc" {with-doc} ] build: [ - ["dune" "subst"] {pinned} + ["dune" "subst"] {dev} [ "dune" "build" diff --git a/analysis/Makefile b/analysis/Makefile index 069dbbbe4..7dea0b02f 100644 --- a/analysis/Makefile +++ b/analysis/Makefile @@ -3,7 +3,7 @@ SHELL = /bin/bash build-analysis-binary: rm -f rescript-editor-analysis.exe dune build - cp _build/install/default/bin/rescript-editor-analysis rescript-editor-analysis.exe + cp ../_build/default/analysis/bin/main.exe rescript-editor-analysis.exe build-tests: make -C tests build diff --git a/analysis/bin/dune b/analysis/bin/dune new file mode 100644 index 000000000..2005419d5 --- /dev/null +++ b/analysis/bin/dune @@ -0,0 +1,6 @@ +(executable + (name main) + (public_name analysis) + (package analysis) + (modes byte exe) + (libraries analysis)) diff --git a/analysis/src/Cli.ml b/analysis/bin/main.ml similarity index 94% rename from analysis/src/Cli.ml rename to analysis/bin/main.ml index 407e9cde2..ca1595145 100644 --- a/analysis/src/Cli.ml +++ b/analysis/bin/main.ml @@ -1,3 +1,4 @@ +open Analysis let help = {| **Private CLI For rescript-vscode usage only** @@ -102,7 +103,7 @@ let main () = Commands.typeDefinition ~path ~pos:(int_of_string line, int_of_string col) ~debug:false - | [_; "documentSymbol"; path] -> DocumentSymbol.command ~path + | [_; "documentSymbol"; path] -> Commands.documentSymbol ~path | [_; "hover"; path; line; col; currentFile; supportsMarkdownLinks] -> Commands.hover ~path ~pos:(int_of_string line, int_of_string col) @@ -140,13 +141,10 @@ let main () = Commands.rename ~path ~pos:(int_of_string line, int_of_string col) ~newName ~debug:false - | [_; "semanticTokens"; currentFile] -> - SemanticTokens.semanticTokens ~currentFile + | [_; "semanticTokens"; currentFile] -> Commands.semanticTokens ~currentFile | [_; "createInterface"; path; cmiFile] -> - Printf.printf "\"%s\"" - (Json.escape (CreateInterface.command ~path ~cmiFile)) - | [_; "format"; path] -> - Printf.printf "\"%s\"" (Json.escape (Commands.format ~path)) + Commands.createInterface ~path ~cmiFile + | [_; "format"; path] -> Commands.format ~path | [_; "test"; path] -> Cfg.supportsSnippets := true; Commands.test ~path diff --git a/analysis/dune b/analysis/dune index 5ce956be5..67bb821b5 100644 --- a/analysis/dune +++ b/analysis/dune @@ -1,4 +1,4 @@ -(dirs src reanalyze vendor) +(dirs src bin reanalyze vendor) (env (dev diff --git a/analysis/reanalyze/examples/deadcode/test.sh b/analysis/reanalyze/examples/deadcode/test.sh index ea28ad778..358a7ffe6 100755 --- a/analysis/reanalyze/examples/deadcode/test.sh +++ b/analysis/reanalyze/examples/deadcode/test.sh @@ -6,7 +6,7 @@ else exclude_dirs="src/exception" suppress="src/ToSuppress.res" fi -dune exec rescript-editor-analysis -- reanalyze -config -debug -ci -exclude-paths $exclude_dirs -live-names globallyLive1 -live-names globallyLive2,globallyLive3 -suppress $suppress > $output +dune exec analysis -- reanalyze -config -debug -ci -exclude-paths $exclude_dirs -live-names globallyLive1 -live-names globallyLive2,globallyLive3 -suppress $suppress > $output # CI. We use LF, and the CI OCaml fork prints CRLF. Convert. if [ "$RUNNER_OS" == "Windows" ]; then perl -pi -e 's/\r\n/\n/g' -- $output @@ -18,7 +18,7 @@ if [ "$RUNNER_OS" == "Windows" ]; then else unsuppress_dirs="src/exception" fi -dune exec rescript-editor-analysis -- reanalyze -exception -ci -suppress src -unsuppress $unsuppress_dirs > $output +dune exec analysis -- reanalyze -exception -ci -suppress src -unsuppress $unsuppress_dirs > $output # CI. We use LF, and the CI OCaml fork prints CRLF. Convert. if [ "$RUNNER_OS" == "Windows" ]; then perl -pi -e 's/\r\n/\n/g' -- $output diff --git a/analysis/reanalyze/examples/termination/test.sh b/analysis/reanalyze/examples/termination/test.sh index 3897ae695..eeb05a3d6 100755 --- a/analysis/reanalyze/examples/termination/test.sh +++ b/analysis/reanalyze/examples/termination/test.sh @@ -1,5 +1,5 @@ output="expected/termination.txt" -dune exec rescript-editor-analysis -- reanalyze -config -ci -debug > $output +dune exec analysis -- reanalyze -config -ci -debug > $output # CI. We use LF, and the CI OCaml fork prints CRLF. Convert. if [ "$RUNNER_OS" == "Windows" ]; then perl -pi -e 's/\r\n/\n/g' -- $output diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 65fe589c5..4297d2f93 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -1,21 +1,12 @@ let completion ~debug ~path ~pos ~currentFile = - let completions = - match - Completions.getCompletions ~debug ~path ~pos ~currentFile ~forHover:false - with - | None -> [] - | Some (completions, _, _) -> completions - in - print_endline - (completions - |> List.map CompletionBackEnd.completionToItem - |> List.map Protocol.stringifyCompletionItem - |> Protocol.array) + Completions.complete ~debug ~path ~pos ~currentFile + |> List.map Protocol.stringifyCompletionItem + |> Protocol.array |> print_endline let inlayhint ~path ~pos ~maxLength ~debug = let result = match Hint.inlay ~path ~pos ~maxLength ~debug with - | Some hints -> hints |> Protocol.array + | Some hints -> hints |> List.map Protocol.stringifyHint |> Protocol.array | None -> Protocol.null in print_endline result @@ -23,53 +14,16 @@ let inlayhint ~path ~pos ~maxLength ~debug = let codeLens ~path ~debug = let result = match Hint.codeLens ~path ~debug with - | Some lens -> lens |> Protocol.array + | Some lens -> lens |> List.map Protocol.stringifyCodeLens |> Protocol.array | None -> Protocol.null in print_endline result let hover ~path ~pos ~currentFile ~debug ~supportsMarkdownLinks = - let result = - match Cmt.loadFullCmtFromPath ~path with - | None -> Protocol.null - | Some full -> ( - match References.getLocItem ~full ~pos ~debug with - | None -> ( - if debug then - Printf.printf - "Nothing at that position. Now trying to use completion.\n"; - match - Hover.getHoverViaCompletions ~debug ~path ~pos ~currentFile - ~forHover:true ~supportsMarkdownLinks - with - | None -> Protocol.null - | Some hover -> hover) - | Some locItem -> ( - let isModule = - match locItem.locType with - | LModule _ | TopLevelModule _ -> true - | TypeDefinition _ | Typed _ | Constant _ -> false - in - let uriLocOpt = References.definitionForLocItem ~full locItem in - let skipZero = - match uriLocOpt with - | None -> false - | Some (_, loc) -> - let isInterface = full.file.uri |> Uri.isInterface in - let posIsZero {Lexing.pos_lnum; pos_bol; pos_cnum} = - (not isInterface) && pos_lnum = 1 && pos_cnum - pos_bol = 0 - in - (* Skip if range is all zero, unless it's a module *) - (not isModule) && posIsZero loc.loc_start && posIsZero loc.loc_end - in - if skipZero then Protocol.null - else - let hoverText = Hover.newHover ~supportsMarkdownLinks ~full locItem in - match hoverText with - | None -> Protocol.null - | Some s -> Protocol.stringifyHover s)) - in - print_endline result + (match Hover.hover ~path ~pos ~currentFile ~debug ~supportsMarkdownLinks with + | None -> Protocol.null + | Some content -> content |> Protocol.stringifyHover) + |> print_endline let signatureHelp ~path ~pos ~currentFile ~debug = let result = @@ -85,180 +39,64 @@ let codeAction ~path ~pos ~currentFile ~debug = |> CodeActions.stringifyCodeActions |> print_endline let definition ~path ~pos ~debug = - let locationOpt = - match Cmt.loadFullCmtFromPath ~path with - | None -> None - | Some full -> ( - match References.getLocItem ~full ~pos ~debug with - | None -> None - | Some locItem -> ( - match References.definitionForLocItem ~full locItem with - | None -> None - | Some (uri, loc) when not loc.loc_ghost -> - let isInterface = full.file.uri |> Uri.isInterface in - let posIsZero {Lexing.pos_lnum; pos_bol; pos_cnum} = - (* range is zero *) - pos_lnum = 1 && pos_cnum - pos_bol = 0 - in - let isModule = - match locItem.locType with - | LModule _ | TopLevelModule _ -> true - | TypeDefinition _ | Typed _ | Constant _ -> false - in - let skipLoc = - (not isModule) && (not isInterface) && posIsZero loc.loc_start - && posIsZero loc.loc_end - in - if skipLoc then None - else - Some - {Protocol.uri = Uri.toString uri; range = Utils.cmtLocToRange loc} - | Some _ -> None)) - in - print_endline - (match locationOpt with - | None -> Protocol.null - | Some location -> location |> Protocol.stringifyLocation) + (match Definition.definition ~path ~pos ~debug with + | Some loc -> loc |> Protocol.stringifyLocation + | None -> Protocol.null) + |> print_endline let typeDefinition ~path ~pos ~debug = - let maybeLocation = - match Cmt.loadFullCmtFromPath ~path with - | None -> None - | Some full -> ( - match References.getLocItem ~full ~pos ~debug with - | None -> None - | Some locItem -> ( - match References.typeDefinitionForLocItem ~full locItem with - | None -> None - | Some (uri, loc) -> - Some - {Protocol.uri = Uri.toString uri; range = Utils.cmtLocToRange loc})) - in - print_endline - (match maybeLocation with - | None -> Protocol.null - | Some location -> location |> Protocol.stringifyLocation) + (match TypeDefinition.typeDefinition ~path ~pos ~debug with + | None -> Protocol.null + | Some location -> location |> Protocol.stringifyLocation) + |> print_endline let references ~path ~pos ~debug = - let allLocs = - match Cmt.loadFullCmtFromPath ~path with - | None -> [] - | Some full -> ( - match References.getLocItem ~full ~pos ~debug with - | None -> [] - | Some locItem -> - let allReferences = References.allReferencesForLocItem ~full locItem in - allReferences - |> List.fold_left - (fun acc {References.uri = uri2; locOpt} -> - let loc = - match locOpt with - | Some loc -> loc - | None -> Uri.toTopLevelLoc uri2 - in - Protocol.stringifyLocation - {uri = Uri.toString uri2; range = Utils.cmtLocToRange loc} - :: acc) - []) - in - print_endline - (if allLocs = [] then Protocol.null - else "[\n" ^ (allLocs |> String.concat ",\n") ^ "\n]") + (match References.references ~path ~pos ~debug with + | [] -> Protocol.null + | locs -> locs |> List.map Protocol.stringifyLocation |> Protocol.array) + |> print_endline let rename ~path ~pos ~newName ~debug = let result = - match Cmt.loadFullCmtFromPath ~path with + match Rename.rename ~path ~pos ~newName ~debug with | None -> Protocol.null - | Some full -> ( - match References.getLocItem ~full ~pos ~debug with - | None -> Protocol.null - | Some locItem -> - let allReferences = References.allReferencesForLocItem ~full locItem in - let referencesToToplevelModules = - allReferences - |> Utils.filterMap (fun {References.uri = uri2; locOpt} -> - if locOpt = None then Some uri2 else None) - in - let referencesToItems = - allReferences - |> Utils.filterMap (function - | {References.uri = uri2; locOpt = Some loc} -> Some (uri2, loc) - | {locOpt = None} -> None) - in - let fileRenames = - referencesToToplevelModules - |> List.map (fun uri -> - let path = Uri.toPath uri in - let dir = Filename.dirname path in - let newPath = - Filename.concat dir (newName ^ Filename.extension path) - in - let newUri = Uri.fromPath newPath in - Protocol. - { - oldUri = uri |> Uri.toString; - newUri = newUri |> Uri.toString; - }) - in - let textDocumentEdits = - let module StringMap = Misc.StringMap in - let textEditsByUri = - referencesToItems - |> List.map (fun (uri, loc) -> (Uri.toString uri, loc)) - |> List.fold_left - (fun acc (uri, loc) -> - let textEdit = - Protocol. - {range = Utils.cmtLocToRange loc; newText = newName} - in - match StringMap.find_opt uri acc with - | None -> StringMap.add uri [textEdit] acc - | Some prevEdits -> - StringMap.add uri (textEdit :: prevEdits) acc) - StringMap.empty - in - StringMap.fold - (fun uri edits acc -> - let textDocumentEdit = - Protocol.{textDocument = {uri; version = None}; edits} - in - textDocumentEdit :: acc) - textEditsByUri [] - in - let fileRenamesString = - fileRenames |> List.map Protocol.stringifyRenameFile - in - let textDocumentEditsString = - textDocumentEdits |> List.map Protocol.stringifyTextDocumentEdit - in - "[\n" - ^ (fileRenamesString @ textDocumentEditsString |> String.concat ",\n") - ^ "\n]") + | Some documentChanges -> + documentChanges + |> List.map (fun (changes : Protocol.documentChanges) -> + match changes with + | RenameFile renames -> + renames |> List.map Protocol.stringifyRenameFile + | TextDocumentEdit textDocumentEdits -> + textDocumentEdits |> List.map Protocol.stringifyTextDocumentEdit) + |> List.flatten |> Protocol.array in print_endline result let format ~path = - if Filename.check_suffix path ".res" then - let {Res_driver.parsetree = structure; comments; diagnostics} = - Res_driver.parsingEngine.parseImplementation ~forPrinter:true - ~filename:path - in - if List.length diagnostics > 0 then "" - else - Res_printer.printImplementation ~width:!Res_cli.ResClflags.width ~comments - structure - else if Filename.check_suffix path ".resi" then - let {Res_driver.parsetree = signature; comments; diagnostics} = - Res_driver.parsingEngine.parseInterface ~forPrinter:true ~filename:path - in - if List.length diagnostics > 0 then "" - else - Res_printer.printInterface ~width:!Res_cli.ResClflags.width ~comments - signature - else "" + let result = + match Formatter.format ~path with + | Some text -> text + | None -> "" + in + Printf.printf "\"%s\"" (Json.escape result) let diagnosticSyntax ~path = - print_endline (Diagnostics.document_syntax ~path |> Protocol.array) + Diagnostics.document_syntax ~path + |> List.map Protocol.stringifyDiagnostic + |> Protocol.array |> print_endline + +let semanticTokens ~currentFile = + Printf.printf "{\"data\":[%s]}" (SemanticTokens.semanticTokens ~currentFile) + +let createInterface ~path ~cmiFile = + (match CreateInterface.command ~path ~cmiFile with + | Some text -> text + | None -> "") + |> Json.escape |> Printf.printf "\"%s\"" + +let documentSymbol ~path = + DocumentSymbol.command ~path + |> Protocol.stringifyDocumentSymbolItems |> print_endline let test ~path = Uri.stripPath := true; @@ -322,7 +160,7 @@ let test ~path = DceCommand.command () | "doc" -> print_endline ("DocumentSymbol " ^ path); - DocumentSymbol.command ~path + documentSymbol ~path | "hig" -> print_endline ("Highlight " ^ path); SemanticTokens.command ~debug:true @@ -352,7 +190,10 @@ let test ~path = let dir = dirname path in dir ++ parent_dir_name ++ "lib" ++ "bs" ++ "src" ++ name in - Printf.printf "%s" (CreateInterface.command ~path ~cmiFile) + Printf.printf "%s" + (match CreateInterface.command ~path ~cmiFile with + | Some text -> text + | None -> "") | "ref" -> print_endline ("References " ^ path ^ " " ^ string_of_int line ^ ":" diff --git a/analysis/src/Completions.ml b/analysis/src/Completions.ml index 42176bb3b..23bcb176a 100644 --- a/analysis/src/Completions.ml +++ b/analysis/src/Completions.ml @@ -20,3 +20,11 @@ let getCompletions ~debug ~path ~pos ~currentFile ~forHover = ~forHover in Some (completables, full, scope))) + +let complete ~debug ~path ~pos ~currentFile = + let completions = + match getCompletions ~debug ~path ~pos ~currentFile ~forHover:false with + | None -> [] + | Some (completions, _, _) -> completions + in + completions |> List.map CompletionBackEnd.completionToItem diff --git a/analysis/src/CreateInterface.ml b/analysis/src/CreateInterface.ml index 25048d4e8..b49a69e13 100644 --- a/analysis/src/CreateInterface.ml +++ b/analysis/src/CreateInterface.ml @@ -411,5 +411,5 @@ let command ~path ~cmiFile = match Shared.tryReadCmi cmiFile with | Some cmi_info -> let extractor = SourceFileExtractor.create ~path in - printSignature ~extractor ~signature:cmi_info.cmi_sign - | None -> "" + Some (printSignature ~extractor ~signature:cmi_info.cmi_sign) + | None -> None diff --git a/analysis/src/Definition.ml b/analysis/src/Definition.ml new file mode 100644 index 000000000..32494fe63 --- /dev/null +++ b/analysis/src/Definition.ml @@ -0,0 +1,28 @@ +let definition ~path ~pos ~debug = + match Cmt.loadFullCmtFromPath ~path with + | None -> None + | Some full -> ( + match References.getLocItem ~full ~pos ~debug with + | None -> None + | Some locItem -> ( + match References.definitionForLocItem ~full locItem with + | None -> None + | Some (uri, loc) -> + let isInterface = full.file.uri |> Uri.isInterface in + let posIsZero {Lexing.pos_lnum; pos_bol; pos_cnum} = + (* range is zero *) + pos_lnum = 1 && pos_cnum - pos_bol = 0 + in + let isModule = + match locItem.locType with + | LModule _ | TopLevelModule _ -> true + | TypeDefinition _ | Typed _ | Constant _ -> false + in + let skipLoc = + (not isModule) && (not isInterface) && posIsZero loc.loc_start + && posIsZero loc.loc_end + in + if skipLoc then None + else + Some + {Protocol.uri = Uri.toString uri; range = Utils.cmtLocToRange loc})) diff --git a/analysis/src/Diagnostics.ml b/analysis/src/Diagnostics.ml index b4c073425..ea28c2f08 100644 --- a/analysis/src/Diagnostics.ml +++ b/analysis/src/Diagnostics.ml @@ -2,19 +2,15 @@ let document_syntax ~path = let get_diagnostics diagnostics = diagnostics |> List.map (fun diagnostic -> - let _, startline, startcol = - Location.get_pos_info (Res_diagnostics.getStartPos diagnostic) + let start = + Utils.cmtPosToPosition (Res_diagnostics.getStartPos diagnostic) in - let _, endline, endcol = - Location.get_pos_info (Res_diagnostics.getEndPos diagnostic) + let end_ = + Utils.cmtPosToPosition (Res_diagnostics.getEndPos diagnostic) in - Protocol.stringifyDiagnostic + Protocol. { - range = - { - start = {line = startline - 1; character = startcol}; - end_ = {line = endline - 1; character = endcol}; - }; + range = {start; end_}; message = Res_diagnostics.explain diagnostic; severity = 1; }) diff --git a/analysis/src/DocumentSymbol.ml b/analysis/src/DocumentSymbol.ml index 356541c5f..3ea3f8b21 100644 --- a/analysis/src/DocumentSymbol.ml +++ b/analysis/src/DocumentSymbol.ml @@ -197,4 +197,4 @@ let command ~path = in let sortedSymbols = !symbols |> List.sort compareSymbol in let symbolsWithChildren = [] |> addSortedSymbolsToChildren ~sortedSymbols in - print_endline (Protocol.stringifyDocumentSymbolItems symbolsWithChildren) + symbolsWithChildren diff --git a/analysis/src/Formatter.ml b/analysis/src/Formatter.ml new file mode 100644 index 000000000..7e732ba54 --- /dev/null +++ b/analysis/src/Formatter.ml @@ -0,0 +1,21 @@ +let format ~path = + if Filename.check_suffix path ".res" then + let {Res_driver.parsetree = structure; comments; diagnostics} = + Res_driver.parsingEngine.parseImplementation ~forPrinter:true + ~filename:path + in + if List.length diagnostics > 0 then None + else + Some + (Res_printer.printImplementation ~width:!Res_cli.ResClflags.width + ~comments structure) + else if Filename.check_suffix path ".resi" then + let {Res_driver.parsetree = signature; comments; diagnostics} = + Res_driver.parsingEngine.parseInterface ~forPrinter:true ~filename:path + in + if List.length diagnostics > 0 then None + else + Some + (Res_printer.printInterface ~width:!Res_cli.ResClflags.width ~comments + signature) + else None diff --git a/analysis/src/Hint.ml b/analysis/src/Hint.ml index 227d70f38..06f59a431 100644 --- a/analysis/src/Hint.ml +++ b/analysis/src/Hint.ml @@ -95,7 +95,7 @@ let inlay ~path ~pos ~maxLength ~debug = match locItemToTypeHint locItem ~full with | Some label -> ( let result = - Protocol.stringifyHint + Protocol. { kind = inlayKindToNumber hintKind; position; @@ -153,21 +153,21 @@ let codeLens ~path ~debug = with | Some {locType = Typed (_, typeExpr, _)} -> Some - (Protocol.stringifyCodeLens - { - range; - command = - Some - { - (* Code lenses can run commands. An empty command string means we just want the editor - to print the text, not link to running a command. *) - command = ""; - (* Print the type with a huge line width, because the code lens always prints on a - single line in the editor. *) - title = - typeExpr |> Shared.typeToString ~lineWidth:400; - }; - }) + Protocol. + { + range; + command = + Some + { + (* Code lenses can run commands. An empty command string means we just want the editor + to print the text, not link to running a command. *) + command = ""; + (* Print the type with a huge line width, because the code lens always prints on a + single line in the editor. *) + title = + typeExpr |> Shared.typeToString ~lineWidth:400; + }; + } | _ -> None) in Some result diff --git a/analysis/src/Hover.ml b/analysis/src/Hover.ml index d0df179a9..beac31095 100644 --- a/analysis/src/Hover.ml +++ b/analysis/src/Hover.ml @@ -133,7 +133,7 @@ let getHoverViaCompletions ~debug ~path ~pos ~currentFile ~forHover (if typString = "" then [] else [Markdown.codeBlock typString]) @ docstring in - Some (Protocol.stringifyHover (String.concat "\n\n" parts)) + Some (String.concat "\n\n" parts) | {kind = Field _; env; docstring} :: _ -> ( let opens = CompletionBackEnd.getOpens ~debug ~rawOpens ~package ~env in match @@ -145,7 +145,7 @@ let getHoverViaCompletions ~debug ~path ~pos ~currentFile ~forHover hoverWithExpandedTypes ~file ~package ~supportsMarkdownLinks typ in let parts = typeString :: docstring in - Some (Protocol.stringifyHover (String.concat "\n\n" parts)) + Some (String.concat "\n\n" parts) | None -> None) | {env} :: _ -> ( let opens = CompletionBackEnd.getOpens ~debug ~rawOpens ~package ~env in @@ -157,7 +157,7 @@ let getHoverViaCompletions ~debug ~path ~pos ~currentFile ~forHover let typeString = hoverWithExpandedTypes ~file ~package ~supportsMarkdownLinks typ in - Some (Protocol.stringifyHover typeString) + Some typeString | None -> None) | _ -> None) @@ -250,3 +250,44 @@ let newHover ~full:{file; package} ~supportsMarkdownLinks locItem = typeString :: docstring) in Some (String.concat "\n\n" parts) + +let hover ~path ~pos ~currentFile ~debug ~supportsMarkdownLinks = + let value = + match Cmt.loadFullCmtFromPath ~path with + | None -> None + | Some full -> ( + match References.getLocItem ~full ~pos ~debug with + | None -> ( + if debug then + Printf.printf + "Nothing at that position. Now trying to use completion.\n"; + match + getHoverViaCompletions ~debug ~path ~pos ~currentFile ~forHover:true + ~supportsMarkdownLinks + with + | None -> None + | Some hover -> Some hover) + | Some locItem -> + let isModule = + match locItem.locType with + | LModule _ | TopLevelModule _ -> true + | TypeDefinition _ | Typed _ | Constant _ -> false + in + let uriLocOpt = References.definitionForLocItem ~full locItem in + let skipZero = + match uriLocOpt with + | None -> false + | Some (_, loc) -> + let isInterface = full.file.uri |> Uri.isInterface in + let posIsZero {Lexing.pos_lnum; pos_bol; pos_cnum} = + (not isInterface) && pos_lnum = 1 && pos_cnum - pos_bol = 0 + in + (* Skip if range is all zero, unless it's a module *) + (not isModule) && posIsZero loc.loc_start && posIsZero loc.loc_end + in + if skipZero then None else newHover ~supportsMarkdownLinks ~full locItem + ) + in + match value with + | Some value -> Some Protocol.{kind = "markdown"; value} + | None -> None diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index 1f23f522e..381c1e2ee 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -74,6 +74,12 @@ type textDocumentEdit = { edits: textEdit list; } +type documentChanges = + | RenameFile of renameFile list + | TextDocumentEdit of textDocumentEdit list + +type workspaceEdit = {documentChanges: documentChanges} + type codeActionEdit = {documentChanges: textDocumentEdit list} type codeActionKind = RefactorRewrite @@ -138,9 +144,8 @@ let stringifyCompletionItem c = Some (Printf.sprintf "%i" (insertTextFormatToInt insertTextFormat)) ); ] -let stringifyHover value = - Printf.sprintf {|{"contents": %s}|} - (stringifyMarkupContent {kind = "markdown"; value}) +let stringifyHover {kind; value} = + Printf.sprintf {|{"contents": %s}|} (stringifyMarkupContent {kind; value}) let stringifyLocation (h : location) = Printf.sprintf {|{"uri": "%s", "range": %s}|} (Json.escape h.uri) diff --git a/analysis/src/References.ml b/analysis/src/References.ml index e19439a20..28cbbd613 100644 --- a/analysis/src/References.ml +++ b/analysis/src/References.ml @@ -571,3 +571,23 @@ let allReferencesForLocItem ~full:({file; package} as full) locItem = ^ " and stamp " ^ string_of_int stamp ^ " and tip " ^ Tip.toString tip); forLocalStamp ~full stamp tip))) + +let references ~path ~pos ~debug = + match Cmt.loadFullCmtFromPath ~path with + | None -> [] + | Some full -> ( + match getLocItem ~full ~pos ~debug with + | None -> [] + | Some locItem -> + let allReferences = allReferencesForLocItem ~full locItem in + allReferences + |> List.fold_left + (fun acc {uri = uri2; locOpt} -> + let loc = + match locOpt with + | Some loc -> loc + | None -> Uri.toTopLevelLoc uri2 + in + Protocol.{uri = Uri.toString uri2; range = Utils.cmtLocToRange loc} + :: acc) + []) diff --git a/analysis/src/Rename.ml b/analysis/src/Rename.ml new file mode 100644 index 000000000..27fa421e2 --- /dev/null +++ b/analysis/src/Rename.ml @@ -0,0 +1,58 @@ +let rename ~path ~pos ~newName ~debug = + match Cmt.loadFullCmtFromPath ~path with + | None -> None + | Some full -> ( + match References.getLocItem ~full ~pos ~debug with + | None -> None + | Some locItem -> + let allReferences = References.allReferencesForLocItem ~full locItem in + let referencesToToplevelModules = + allReferences + |> Utils.filterMap (fun {References.uri = uri2; locOpt} -> + if locOpt = None then Some uri2 else None) + in + let referencesToItems = + allReferences + |> Utils.filterMap (function + | {References.uri = uri2; locOpt = Some loc} -> Some (uri2, loc) + | {locOpt = None} -> None) + in + let fileRenames = + referencesToToplevelModules + |> List.map (fun uri -> + let path = Uri.toPath uri in + let dir = Filename.dirname path in + let newPath = + Filename.concat dir (newName ^ Filename.extension path) + in + let newUri = Uri.fromPath newPath in + Protocol. + {oldUri = uri |> Uri.toString; newUri = newUri |> Uri.toString}) + in + let textDocumentEdits = + let module StringMap = Misc.StringMap in + let textEditsByUri = + referencesToItems + |> List.map (fun (uri, loc) -> (Uri.toString uri, loc)) + |> List.fold_left + (fun acc (uri, loc) -> + let textEdit = + Protocol.{range = Utils.cmtLocToRange loc; newText = newName} + in + match StringMap.find_opt uri acc with + | None -> StringMap.add uri [textEdit] acc + | Some prevEdits -> + StringMap.add uri (textEdit :: prevEdits) acc) + StringMap.empty + in + StringMap.fold + (fun uri edits acc -> + let textDocumentEdit = + Protocol.{textDocument = {uri; version = None}; edits} + in + textDocumentEdit :: acc) + textEditsByUri [] + in + let renames = Protocol.RenameFile fileRenames in + let textDocumentEdits = Protocol.TextDocumentEdit textDocumentEdits in + Some ([renames] @ [textDocumentEdits])) diff --git a/analysis/src/SemanticTokens.ml b/analysis/src/SemanticTokens.ml index bb1f0d822..910dd76c3 100644 --- a/analysis/src/SemanticTokens.ml +++ b/analysis/src/SemanticTokens.ml @@ -457,4 +457,4 @@ let command ~debug ~emitter ~path = let semanticTokens ~currentFile = let emitter = Token.createEmitter () in command ~emitter ~debug:false ~path:currentFile; - Printf.printf "{\"data\":[%s]}" (Token.emit emitter) + Token.emit emitter diff --git a/analysis/src/TypeDefinition.ml b/analysis/src/TypeDefinition.ml new file mode 100644 index 000000000..858b5bfb5 --- /dev/null +++ b/analysis/src/TypeDefinition.ml @@ -0,0 +1,12 @@ +let typeDefinition ~path ~pos ~debug = + match Cmt.loadFullCmtFromPath ~path with + | None -> None + | Some full -> ( + match References.getLocItem ~full ~pos ~debug with + | None -> None + | Some locItem -> ( + match References.typeDefinitionForLocItem ~full locItem with + | None -> None + | Some (uri, loc) -> + Some {Protocol.uri = Uri.toString uri; range = Utils.cmtLocToRange loc}) + ) diff --git a/analysis/src/dune b/analysis/src/dune index bc16552c3..c1bd828c1 100644 --- a/analysis/src/dune +++ b/analysis/src/dune @@ -1,9 +1,5 @@ -(executable - (public_name rescript-editor-analysis) - (modes byte exe) - ; The main module that will become the binary. - (name Cli) +(library + (name analysis) (flags (-w "+6+26+27+32+33+39")) - ; Depends on: (libraries unix str ext ml jsonlib syntax reanalyze)) diff --git a/analysis/tests/src/expected/Cross.res.txt b/analysis/tests/src/expected/Cross.res.txt index 6f5ad3e43..24baaed54 100644 --- a/analysis/tests/src/expected/Cross.res.txt +++ b/analysis/tests/src/expected/Cross.res.txt @@ -1,35 +1,19 @@ References src/Cross.res 0:17 -[ -{"uri": "Cross.res", "range": {"start": {"line": 0, "character": 15}, "end": {"line": 0, "character": 25}}}, -{"uri": "Cross.res", "range": {"start": {"line": 3, "character": 16}, "end": {"line": 3, "character": 26}}}, -{"uri": "Cross.res", "range": {"start": {"line": 5, "character": 13}, "end": {"line": 5, "character": 23}}}, -{"uri": "Cross.res", "range": {"start": {"line": 7, "character": 16}, "end": {"line": 7, "character": 26}}}, -{"uri": "References.res", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 0}}} -] +[{"uri": "Cross.res", "range": {"start": {"line": 0, "character": 15}, "end": {"line": 0, "character": 25}}}, {"uri": "Cross.res", "range": {"start": {"line": 3, "character": 16}, "end": {"line": 3, "character": 26}}}, {"uri": "Cross.res", "range": {"start": {"line": 5, "character": 13}, "end": {"line": 5, "character": 23}}}, {"uri": "Cross.res", "range": {"start": {"line": 7, "character": 16}, "end": {"line": 7, "character": 26}}}, {"uri": "References.res", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 0}}}] References src/Cross.res 9:31 -[ -{"uri": "Cross.res", "range": {"start": {"line": 9, "character": 28}, "end": {"line": 9, "character": 51}}}, -{"uri": "Cross.res", "range": {"start": {"line": 12, "character": 29}, "end": {"line": 12, "character": 52}}}, -{"uri": "Cross.res", "range": {"start": {"line": 14, "character": 26}, "end": {"line": 14, "character": 49}}}, -{"uri": "Cross.res", "range": {"start": {"line": 16, "character": 29}, "end": {"line": 16, "character": 52}}}, -{"uri": "ReferencesWithInterface.res", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 0}}}, -{"uri": "ReferencesWithInterface.resi", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 0}}} -] +[{"uri": "Cross.res", "range": {"start": {"line": 9, "character": 28}, "end": {"line": 9, "character": 51}}}, {"uri": "Cross.res", "range": {"start": {"line": 12, "character": 29}, "end": {"line": 12, "character": 52}}}, {"uri": "Cross.res", "range": {"start": {"line": 14, "character": 26}, "end": {"line": 14, "character": 49}}}, {"uri": "Cross.res", "range": {"start": {"line": 16, "character": 29}, "end": {"line": 16, "character": 52}}}, {"uri": "ReferencesWithInterface.res", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 0}}}, {"uri": "ReferencesWithInterface.resi", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 0, "character": 0}}}] Rename src/Cross.res 18:13 RenameWithInterfacePrime -[ -{ +[{ "kind": "rename", "oldUri": "RenameWithInterface.resi", "newUri": "RenameWithInterfacePrime.resi" -}, -{ +}, { "kind": "rename", "oldUri": "RenameWithInterface.res", "newUri": "RenameWithInterfacePrime.res" -}, -{ +}, { "textDocument": { "version": null, "uri": "Cross.res" @@ -41,12 +25,10 @@ Rename src/Cross.res 18:13 RenameWithInterfacePrime "range": {"start": {"line": 21, "character": 8}, "end": {"line": 21, "character": 27}}, "newText": "RenameWithInterfacePrime" }] - } -] + }] Rename src/Cross.res 21:28 xPrime -[ -{ +[{ "textDocument": { "version": null, "uri": "RenameWithInterface.resi" @@ -55,8 +37,7 @@ Rename src/Cross.res 21:28 xPrime "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}, "newText": "xPrime" }] - }, -{ + }, { "textDocument": { "version": null, "uri": "RenameWithInterface.res" @@ -65,8 +46,7 @@ Rename src/Cross.res 21:28 xPrime "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}, "newText": "xPrime" }] - }, -{ + }, { "textDocument": { "version": null, "uri": "Cross.res" @@ -78,8 +58,7 @@ Rename src/Cross.res 21:28 xPrime "range": {"start": {"line": 21, "character": 28}, "end": {"line": 21, "character": 29}}, "newText": "xPrime" }] - } -] + }] TypeDefinition src/Cross.res 24:5 {"uri": "TypeDefinition.res", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 28}}} diff --git a/analysis/tests/src/expected/References.res.txt b/analysis/tests/src/expected/References.res.txt index ea3108dae..6467a9d3e 100644 --- a/analysis/tests/src/expected/References.res.txt +++ b/analysis/tests/src/expected/References.res.txt @@ -1,33 +1,14 @@ References src/References.res 0:4 -[ -{"uri": "Cross.res", "range": {"start": {"line": 0, "character": 26}, "end": {"line": 0, "character": 27}}}, -{"uri": "Cross.res", "range": {"start": {"line": 3, "character": 27}, "end": {"line": 3, "character": 28}}}, -{"uri": "Cross.res", "range": {"start": {"line": 7, "character": 27}, "end": {"line": 7, "character": 28}}}, -{"uri": "References.res", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}}, -{"uri": "References.res", "range": {"start": {"line": 3, "character": 8}, "end": {"line": 3, "character": 9}}}, -{"uri": "References.res", "range": {"start": {"line": 7, "character": 8}, "end": {"line": 7, "character": 9}}} -] +[{"uri": "Cross.res", "range": {"start": {"line": 0, "character": 26}, "end": {"line": 0, "character": 27}}}, {"uri": "Cross.res", "range": {"start": {"line": 3, "character": 27}, "end": {"line": 3, "character": 28}}}, {"uri": "Cross.res", "range": {"start": {"line": 7, "character": 27}, "end": {"line": 7, "character": 28}}}, {"uri": "References.res", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}}, {"uri": "References.res", "range": {"start": {"line": 3, "character": 8}, "end": {"line": 3, "character": 9}}}, {"uri": "References.res", "range": {"start": {"line": 7, "character": 8}, "end": {"line": 7, "character": 9}}}] References src/References.res 9:19 -[ -{"uri": "References.res", "range": {"start": {"line": 9, "character": 11}, "end": {"line": 9, "character": 14}}}, -{"uri": "References.res", "range": {"start": {"line": 9, "character": 19}, "end": {"line": 9, "character": 21}}} -] +[{"uri": "References.res", "range": {"start": {"line": 9, "character": 11}, "end": {"line": 9, "character": 14}}}, {"uri": "References.res", "range": {"start": {"line": 9, "character": 19}, "end": {"line": 9, "character": 21}}}] References src/References.res 20:12 -[ -{"uri": "References.res", "range": {"start": {"line": 13, "character": 2}, "end": {"line": 13, "character": 13}}}, -{"uri": "References.res", "range": {"start": {"line": 18, "character": 11}, "end": {"line": 18, "character": 13}}}, -{"uri": "References.res", "range": {"start": {"line": 20, "character": 11}, "end": {"line": 20, "character": 13}}} -] +[{"uri": "References.res", "range": {"start": {"line": 13, "character": 2}, "end": {"line": 13, "character": 13}}}, {"uri": "References.res", "range": {"start": {"line": 18, "character": 11}, "end": {"line": 18, "character": 13}}}, {"uri": "References.res", "range": {"start": {"line": 20, "character": 11}, "end": {"line": 20, "character": 13}}}] References src/References.res 23:15 getLocItem #4: heuristic for within fragments: take make as makeProps does not work the type is not great but jump to definition works -[ -{"uri": "ReferencesInner.res", "range": {"start": {"line": 1, "character": 28}, "end": {"line": 1, "character": 32}}}, -{"uri": "References.res", "range": {"start": {"line": 23, "character": 19}, "end": {"line": 23, "character": 23}}}, -{"uri": "ComponentInner.res", "range": {"start": {"line": 1, "character": 4}, "end": {"line": 1, "character": 8}}}, -{"uri": "ComponentInner.resi", "range": {"start": {"line": 1, "character": 4}, "end": {"line": 1, "character": 8}}} -] +[{"uri": "ReferencesInner.res", "range": {"start": {"line": 1, "character": 28}, "end": {"line": 1, "character": 32}}}, {"uri": "References.res", "range": {"start": {"line": 23, "character": 19}, "end": {"line": 23, "character": 23}}}, {"uri": "ComponentInner.res", "range": {"start": {"line": 1, "character": 4}, "end": {"line": 1, "character": 8}}}, {"uri": "ComponentInner.resi", "range": {"start": {"line": 1, "character": 4}, "end": {"line": 1, "character": 8}}}] diff --git a/analysis/tests/src/expected/ReferencesWithInterface.res.txt b/analysis/tests/src/expected/ReferencesWithInterface.res.txt index 33f2d105d..4b49191f7 100644 --- a/analysis/tests/src/expected/ReferencesWithInterface.res.txt +++ b/analysis/tests/src/expected/ReferencesWithInterface.res.txt @@ -1,9 +1,3 @@ References src/ReferencesWithInterface.res 0:4 -[ -{"uri": "Cross.res", "range": {"start": {"line": 9, "character": 52}, "end": {"line": 9, "character": 53}}}, -{"uri": "Cross.res", "range": {"start": {"line": 12, "character": 53}, "end": {"line": 12, "character": 54}}}, -{"uri": "Cross.res", "range": {"start": {"line": 16, "character": 53}, "end": {"line": 16, "character": 54}}}, -{"uri": "ReferencesWithInterface.resi", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}}, -{"uri": "ReferencesWithInterface.res", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}} -] +[{"uri": "Cross.res", "range": {"start": {"line": 9, "character": 52}, "end": {"line": 9, "character": 53}}}, {"uri": "Cross.res", "range": {"start": {"line": 12, "character": 53}, "end": {"line": 12, "character": 54}}}, {"uri": "Cross.res", "range": {"start": {"line": 16, "character": 53}, "end": {"line": 16, "character": 54}}}, {"uri": "ReferencesWithInterface.resi", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}}, {"uri": "ReferencesWithInterface.res", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}}] diff --git a/analysis/tests/src/expected/ReferencesWithInterface.resi.txt b/analysis/tests/src/expected/ReferencesWithInterface.resi.txt index 3e96fbc75..4846393b6 100644 --- a/analysis/tests/src/expected/ReferencesWithInterface.resi.txt +++ b/analysis/tests/src/expected/ReferencesWithInterface.resi.txt @@ -1,9 +1,3 @@ References src/ReferencesWithInterface.resi 0:4 -[ -{"uri": "Cross.res", "range": {"start": {"line": 9, "character": 52}, "end": {"line": 9, "character": 53}}}, -{"uri": "Cross.res", "range": {"start": {"line": 12, "character": 53}, "end": {"line": 12, "character": 54}}}, -{"uri": "Cross.res", "range": {"start": {"line": 16, "character": 53}, "end": {"line": 16, "character": 54}}}, -{"uri": "ReferencesWithInterface.res", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}}, -{"uri": "ReferencesWithInterface.resi", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}} -] +[{"uri": "Cross.res", "range": {"start": {"line": 9, "character": 52}, "end": {"line": 9, "character": 53}}}, {"uri": "Cross.res", "range": {"start": {"line": 12, "character": 53}, "end": {"line": 12, "character": 54}}}, {"uri": "Cross.res", "range": {"start": {"line": 16, "character": 53}, "end": {"line": 16, "character": 54}}}, {"uri": "ReferencesWithInterface.res", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}}, {"uri": "ReferencesWithInterface.resi", "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}}] diff --git a/analysis/tests/src/expected/Rename.res.txt b/analysis/tests/src/expected/Rename.res.txt index 5cd2adfee..1685cd283 100644 --- a/analysis/tests/src/expected/Rename.res.txt +++ b/analysis/tests/src/expected/Rename.res.txt @@ -1,6 +1,5 @@ Rename src/Rename.res 0:4 y -[ -{ +[{ "textDocument": { "version": null, "uri": "Rename.res" @@ -15,12 +14,10 @@ Rename src/Rename.res 0:4 y "range": {"start": {"line": 7, "character": 8}, "end": {"line": 7, "character": 9}}, "newText": "y" }] - } -] + }] Rename src/Rename.res 9:19 yy -[ -{ +[{ "textDocument": { "version": null, "uri": "Rename.res" @@ -32,6 +29,5 @@ Rename src/Rename.res 9:19 yy "range": {"start": {"line": 9, "character": 19}, "end": {"line": 9, "character": 21}}, "newText": "yy" }] - } -] + }] diff --git a/analysis/tests/src/expected/RenameWithInterface.res.txt b/analysis/tests/src/expected/RenameWithInterface.res.txt index a13988fa9..aa95ad7dc 100644 --- a/analysis/tests/src/expected/RenameWithInterface.res.txt +++ b/analysis/tests/src/expected/RenameWithInterface.res.txt @@ -1,6 +1,5 @@ Rename src/RenameWithInterface.res 0:4 y -[ -{ +[{ "textDocument": { "version": null, "uri": "RenameWithInterface.resi" @@ -9,8 +8,7 @@ Rename src/RenameWithInterface.res 0:4 y "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}, "newText": "y" }] - }, -{ + }, { "textDocument": { "version": null, "uri": "RenameWithInterface.res" @@ -19,8 +17,7 @@ Rename src/RenameWithInterface.res 0:4 y "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}, "newText": "y" }] - }, -{ + }, { "textDocument": { "version": null, "uri": "Cross.res" @@ -32,6 +29,5 @@ Rename src/RenameWithInterface.res 0:4 y "range": {"start": {"line": 21, "character": 28}, "end": {"line": 21, "character": 29}}, "newText": "y" }] - } -] + }] diff --git a/analysis/tests/src/expected/RenameWithInterface.resi.txt b/analysis/tests/src/expected/RenameWithInterface.resi.txt index 2a1dabb44..0c2f6ae56 100644 --- a/analysis/tests/src/expected/RenameWithInterface.resi.txt +++ b/analysis/tests/src/expected/RenameWithInterface.resi.txt @@ -1,6 +1,5 @@ Rename src/RenameWithInterface.resi 0:4 y -[ -{ +[{ "textDocument": { "version": null, "uri": "RenameWithInterface.resi" @@ -9,8 +8,7 @@ Rename src/RenameWithInterface.resi 0:4 y "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}, "newText": "y" }] - }, -{ + }, { "textDocument": { "version": null, "uri": "RenameWithInterface.res" @@ -19,8 +17,7 @@ Rename src/RenameWithInterface.resi 0:4 y "range": {"start": {"line": 0, "character": 4}, "end": {"line": 0, "character": 5}}, "newText": "y" }] - }, -{ + }, { "textDocument": { "version": null, "uri": "Cross.res" @@ -32,6 +29,5 @@ Rename src/RenameWithInterface.resi 0:4 y "range": {"start": {"line": 21, "character": 28}, "end": {"line": 21, "character": 29}}, "newText": "y" }] - } -] + }] diff --git a/analysis/dune-project b/dune-project similarity index 76% rename from analysis/dune-project rename to dune-project index 47a122217..27daa10e2 100644 --- a/analysis/dune-project +++ b/dune-project @@ -1,4 +1,4 @@ -(lang dune 2.3) +(lang dune 3.0) (generate_opam_files true) @@ -11,8 +11,8 @@ (bug_reports "https://github.com/rescript-lang/rescript-vscode/issues") (package - (name rescript-vscode) - (synopsis "ReScript vscode support") + (name analysis) + (synopsis "ReScript Analysis") (depends (ocaml (>= 4.10)) @@ -21,5 +21,4 @@ (cppo (= 1.6.9)) (reanalyze - (= 2.23.0)) - dune)) + (= 2.23.0))))