From fcf0d8abeb1c90b31af65c33624240636e31fd5d Mon Sep 17 00:00:00 2001 From: wangb Date: Fri, 26 Mar 2021 13:38:27 +0800 Subject: [PATCH 01/13] syntax highlight in markdown code block --- grammars/rescript.markdown.json | 45 +++++++++++++++++++++++++++++++++ package.json | 12 ++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 grammars/rescript.markdown.json diff --git a/grammars/rescript.markdown.json b/grammars/rescript.markdown.json new file mode 100644 index 000000000..95cf16f96 --- /dev/null +++ b/grammars/rescript.markdown.json @@ -0,0 +1,45 @@ +{ + "fileTypes": [], + "injectionSelector": "L:text.html.markdown", + "patterns": [ + { + "include": "#rescript-code-block" + } + ], + "repository": { + "rescript-code-block": { + "name": "markup.fenced_code.block.markdown", + "begin": "(^|\\G)(\\s*)(\\`{3,}|~{3,})\\s*(?i:(res|rescript)(\\s+[^`~]*)?$)", + "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", + "beginCaptures": { + "3": { + "name": "punctuation.definition.markdown" + }, + "5": { + "name": "fenced_code.block.language" + }, + "6": { + "name": "fenced_code.block.language.attributes" + } + }, + "endCaptures": { + "3": { + "name": "punctuation.definition.markdown" + } + }, + "patterns": [ + { + "begin": "(^|\\G)(\\s*)(.*)", + "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", + "contentName": "meta.embedded.block.rescript", + "patterns": [ + { + "include": "source.rescript" + } + ] + } + ] + } + }, + "scopeName": "markdown.rescript.codeblock" +} diff --git a/package.json b/package.json index 9744337ec..753ead91e 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,16 @@ "language": "rescript", "scopeName": "source.rescript", "path": "./grammars/rescript.tmLanguage.json" + }, + { + "scopeName": "markdown.rescript.codeblock", + "path": "./grammars/rescript.markdown.json", + "injectTo": [ + "text.html.markdown" + ], + "embeddedLanguages": { + "meta.embedded.block.rescript": "rescript" + } } ], "languages": [ @@ -116,4 +126,4 @@ "dependencies": { "chokidar": "^3.4.2" } -} +} \ No newline at end of file From 5872fd754438b24de09991541b980b0c2bd52f46 Mon Sep 17 00:00:00 2001 From: Christoph Knittel Date: Wed, 20 Jul 2022 16:48:42 +0200 Subject: [PATCH 02/13] Fix commit SHA in artifact name for PR builds --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d02742392..a583e311b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -123,7 +123,9 @@ jobs: - name: Store short commit SHA for filename id: vars - run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" + env: + COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: echo "::set-output name=sha_short::${COMMIT_SHA:0:7}" - name: Package Extension run: npx vsce package -o rescript-vscode-${{ steps.vars.outputs.sha_short }}.vsix From ce3a17724e62bef5b52d7b54e892ec5c35bd2383 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 24 Jul 2022 18:43:23 +0200 Subject: [PATCH 03/13] This sets our language server up to handle the codeLens requests coming from the language client. This just ensures that the server tells the client that sending codeLens requests is fine. Next we'll implement the actual functionality that resolves the code leneses. --- server/src/server.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/server/src/server.ts b/server/src/server.ts index 542d1010b..71e4f3fcb 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -13,6 +13,7 @@ import { DidChangeConfigurationNotification, InitializeParams, InlayHintParams, + CodeLensParams, } from "vscode-languageserver-protocol"; import * as utils from "./utils"; import * as codeActions from "./codeActions"; @@ -411,6 +412,18 @@ function sendInlayHintsRefresh() { send(request); } +function codeLens(msg: p.RequestMessage) { + const params = msg.params as p.CodeLensParams; + const filePath = fileURLToPath(params.textDocument.uri); + + const response = utils.runAnalysisCommand( + filePath, + ["codeLens", filePath], + msg + ); + return response; +} + function definition(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition let params = msg.params as p.DefinitionParams; @@ -1001,6 +1014,9 @@ function onMessage(msg: p.Message) { full: true, }, inlayHintProvider: extensionConfiguration.inlayHints.enable, + codeLensProvider: { + workDoneProgress: false + }, }, }; let response: p.ResponseMessage = { @@ -1086,6 +1102,12 @@ function onMessage(msg: p.Message) { if (extName === c.resExt) { send(inlayHint(msg)); } + } else if (msg.method === p.CodeLensRequest.method) { + let params = msg.params as CodeLensParams; + let extName = path.extname(params.textDocument.uri); + if (extName === c.resExt) { + send(codeLens(msg)); + } } else { let response: p.ResponseMessage = { jsonrpc: c.jsonrpcVersion, From 13a937fd4f28670d15cdefcda1f90976b70d2cad Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 24 Jul 2022 21:39:55 +0200 Subject: [PATCH 04/13] Allow setting line width when printing types. Will use to nudge the printer towards printing function types for code lenses on one line --- analysis/src/PrintType.ml | 4 ++-- analysis/src/Shared.ml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/analysis/src/PrintType.ml b/analysis/src/PrintType.ml index b146430fb..3da8293c0 100644 --- a/analysis/src/PrintType.ml +++ b/analysis/src/PrintType.ml @@ -1,6 +1,6 @@ -let printExpr typ = +let printExpr ?(lineWidth = 60) typ = Printtyp.reset_names (); - Res_doc.toString ~width:60 + Res_doc.toString ~width:lineWidth (Res_outcome_printer.printOutTypeDoc (Printtyp.tree_of_typexp false typ)) let printDecl ~recStatus name decl = diff --git a/analysis/src/Shared.ml b/analysis/src/Shared.ml index 21b84a125..a44ca111b 100644 --- a/analysis/src/Shared.ml +++ b/analysis/src/Shared.ml @@ -49,12 +49,12 @@ let declToString ?(recStatus = Types.Trec_not) name t = let cacheTypeToString = ref false let typeTbl = Hashtbl.create 1 -let typeToString (t : Types.type_expr) = +let typeToString ?(lineWidth = 60) (t : Types.type_expr) = match if !cacheTypeToString then Hashtbl.find_opt typeTbl (t.id, t) else None with | None -> - let s = PrintType.printExpr t in + let s = PrintType.printExpr ~lineWidth t in Hashtbl.replace typeTbl (t.id, t) s; s | Some s -> s From 76a7c237056a438623ba42411ef5627903418f1c Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 24 Jul 2022 21:43:33 +0200 Subject: [PATCH 05/13] Add needed LSP protocol types for code lenses. --- analysis/src/Protocol.ml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index 6838a29ca..87dda6b05 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -1,6 +1,8 @@ type position = {line: int; character: int} type range = {start: position; end_: position} type markupContent = {kind: string; value: string} +type command = {title: string; command: string} +type codeLens = {range: range; command: command option} type inlayHint = { position: position; label: string; @@ -147,6 +149,26 @@ 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 + {|{ + "range": %s, + "command": %s + }|} + (stringifyRange codeLens.range) + (match codeLens.command with + | None -> "" + | Some command -> stringifyCommand command) + (* https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic *) let stringifyDiagnostic d = Printf.sprintf From 25bfa613d2ff538f53b860d14bc90523cdb533a3 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 24 Jul 2022 21:51:16 +0200 Subject: [PATCH 06/13] Implement emitting code lenses for functions. --- analysis/src/Cli.ml | 8 +++++- analysis/src/Commands.ml | 7 +++++ analysis/src/Hint.ml | 56 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/analysis/src/Cli.ml b/analysis/src/Cli.ml index 9acc01417..90b82b1c8 100644 --- a/analysis/src/Cli.ml +++ b/analysis/src/Cli.ml @@ -11,7 +11,8 @@ API examples: ./rescript-editor-analysis.exe references src/MyFile.res 10 2 ./rescript-editor-analysis.exe rename src/MyFile.res 10 2 foo ./rescript-editor-analysis.exe diagnosticSyntax src/MyFile.res - /rescript-editor-analysis.exe inlayHint src/MyFile.res 0 3 25 + ./rescript-editor-analysis.exe inlayHint src/MyFile.res 0 3 25 + ./rescript-editor-analysis.exe codeLens src/MyFile.res Dev-time examples: ./rescript-editor-analysis.exe dump src/MyFile.res src/MyFile2.res @@ -70,6 +71,10 @@ Options: ./rescript-editor-analysis.exe inlayHint src/MyFile.res 0 3 25 + codeLens: get all code lens entries for file src/MyFile.res + + ./rescript-editor-analysis.exe codeLens src/MyFile.res + test: run tests specified by special comments in file src/MyFile.res ./rescript-editor-analysis.exe test src/src/MyFile.res @@ -98,6 +103,7 @@ let main () = Commands.inlayhint ~path ~pos:(int_of_string line_start, int_of_string line_end) ~maxLength ~debug:false + | [_; "codeLens"; path] -> Commands.codeLens ~path ~debug:false | [_; "codeAction"; path; line; col; currentFile] -> Commands.codeAction ~path ~pos:(int_of_string line, int_of_string col) diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 3dd16c468..552cdc996 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -32,6 +32,10 @@ let inlayhint ~path ~pos ~maxLength ~debug = let result = Hint.inlay ~path ~pos ~maxLength ~debug |> Protocol.array in print_endline result +let codeLens ~path ~debug = + let result = Hint.codeLens ~path ~debug |> Protocol.array in + print_endline result + let hover ~path ~pos ~currentFile ~debug = let result = match Cmt.fullFromPath ~path with @@ -391,6 +395,9 @@ let test ~path = let line_end = 6 in print_endline ("Inlay Hint " ^ path ^ " " ^ string_of_int line_start ^ ":" ^ string_of_int line_end); inlayhint ~path ~pos:(line_start, line_end) ~maxLength:"25" ~debug:false) + | "clens" -> + print_endline ("Code Lens " ^ path); + codeLens ~path ~debug:false | _ -> ()); print_newline ()) in diff --git a/analysis/src/Hint.ml b/analysis/src/Hint.ml index c3d8a9682..788ad5005 100644 --- a/analysis/src/Hint.ml +++ b/analysis/src/Hint.ml @@ -119,4 +119,58 @@ let inlay ~path ~pos ~maxLength ~debug = | Some value -> if String.length label > value then None else Some result | None -> Some result) - | None -> None))) \ No newline at end of file + | None -> None))) + +let codeLens ~path ~debug = + let lenses = ref [] in + let push loc = + let range = Utils.cmtLocToRange loc in + lenses := range :: !lenses + in + (* Code lenses are only emitted for functions right now. So look for value bindings that are functions, + and use the loc of the value binding itself so we can look up the full function type for our code lens. *) + let value_binding (iterator : Ast_iterator.iterator) + (vb : Parsetree.value_binding) = + (match vb with + | { + pvb_pat = {ppat_desc = Ppat_var _; ppat_loc}; + pvb_expr = {pexp_desc = Pexp_fun _}; + } -> + push ppat_loc + | _ -> ()); + Ast_iterator.default_iterator.value_binding iterator vb + in + let iterator = {Ast_iterator.default_iterator with value_binding} in + (if Filename.check_suffix path ".res" then + let parser = + Res_driver.parsingEngine.parseImplementation ~forPrinter:false + in + let {Res_driver.parsetree = structure} = parser ~filename:path in + iterator.structure iterator structure |> ignore); + !lenses + |> List.filter_map (fun (range : Protocol.range) -> + match Cmt.fullFromPath ~path with + | None -> None + | Some full -> ( + match + References.getLocItem ~full + ~pos:(range.start.line, range.start.character + 1) + ~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; + }; + }) + | _ -> None)) From a43710b6ec4d260b3f84df5a3b9e758e7912601f Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 24 Jul 2022 21:59:52 +0200 Subject: [PATCH 07/13] Add tests for code lenses. --- analysis/src/Commands.ml | 2 +- analysis/src/Protocol.ml | 6 +----- analysis/tests/src/CodeLens.res | 11 +++++++++++ analysis/tests/src/expected/CodeLens.res.txt | 15 +++++++++++++++ analysis/tests/src/expected/Dce.res.txt | 2 +- analysis/tests/src/expected/Debug.res.txt | 3 ++- 6 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 analysis/tests/src/CodeLens.res create mode 100644 analysis/tests/src/expected/CodeLens.res.txt diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 552cdc996..ad9ad4a89 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -395,7 +395,7 @@ let test ~path = let line_end = 6 in print_endline ("Inlay Hint " ^ path ^ " " ^ string_of_int line_start ^ ":" ^ string_of_int line_end); inlayhint ~path ~pos:(line_start, line_end) ~maxLength:"25" ~debug:false) - | "clens" -> + | "cle" -> print_endline ("Code Lens " ^ path); codeLens ~path ~debug:false | _ -> ()); diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index 87dda6b05..5247a487d 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -150,11 +150,7 @@ let stringifyHint hint = (Json.escape hint.label) hint.kind hint.paddingLeft hint.paddingRight let stringifyCommand (command : command) = - Printf.sprintf - {|{ - "title": "%s", - "command": "%s" - }|} + Printf.sprintf {|{"title": "%s", "command": "%s"}|} (Json.escape command.title) (Json.escape command.command) diff --git a/analysis/tests/src/CodeLens.res b/analysis/tests/src/CodeLens.res new file mode 100644 index 000000000..a63bed6df --- /dev/null +++ b/analysis/tests/src/CodeLens.res @@ -0,0 +1,11 @@ +let add = (x, y) => x + y + +let foo = (~age, ~name) => name ++ string_of_int(age) + +let ff = (~opt1=0, ~a, ~b, (), ~opt2=0, (), ~c) => a + b + c + opt1 + opt2 + +let compFF = Completion.ff + +@react.component +let make = (~name) => React.string(name) +//^cle diff --git a/analysis/tests/src/expected/CodeLens.res.txt b/analysis/tests/src/expected/CodeLens.res.txt new file mode 100644 index 000000000..06472d5e4 --- /dev/null +++ b/analysis/tests/src/expected/CodeLens.res.txt @@ -0,0 +1,15 @@ +Code Lens src/CodeLens.res +[{ + "range": {"start": {"line": 9, "character": 4}, "end": {"line": 9, "character": 8}}, + "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": ""} + }, { + "range": {"start": {"line": 2, "character": 4}, "end": {"line": 2, "character": 7}}, + "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": ""} + }] + diff --git a/analysis/tests/src/expected/Dce.res.txt b/analysis/tests/src/expected/Dce.res.txt index 441bb5807..9e47ef48c 100644 --- a/analysis/tests/src/expected/Dce.res.txt +++ b/analysis/tests/src/expected/Dce.res.txt @@ -1,3 +1,3 @@ DCE src/Dce.res -issues:243 +issues:249 diff --git a/analysis/tests/src/expected/Debug.res.txt b/analysis/tests/src/expected/Debug.res.txt index ff23fe834..a95597eae 100644 --- a/analysis/tests/src/expected/Debug.res.txt +++ b/analysis/tests/src/expected/Debug.res.txt @@ -4,8 +4,9 @@ Dependencies: @rescript/react Source directories: ./node_modules/@rescript/react/src ./node_modules/@rescript/react/src/legacy Source files: ./node_modules/@rescript/react/src/React.res ./node_modules/@rescript/react/src/ReactDOM.res ./node_modules/@rescript/react/src/ReactDOMServer.res ./node_modules/@rescript/react/src/ReactDOMStyle.res ./node_modules/@rescript/react/src/ReactEvent.res ./node_modules/@rescript/react/src/ReactEvent.resi ./node_modules/@rescript/react/src/ReactTestUtils.res ./node_modules/@rescript/react/src/ReactTestUtils.resi ./node_modules/@rescript/react/src/RescriptReactErrorBoundary.res ./node_modules/@rescript/react/src/RescriptReactErrorBoundary.resi ./node_modules/@rescript/react/src/RescriptReactRouter.res ./node_modules/@rescript/react/src/RescriptReactRouter.resi ./node_modules/@rescript/react/src/legacy/ReactDOMRe.res ./node_modules/@rescript/react/src/legacy/ReasonReact.res Source directories: ./src ./src/expected -Source files: ./src/Auto.res ./src/CompletePrioritize1.res ./src/CompletePrioritize2.res ./src/Completion.res ./src/Component.res ./src/Component.resi ./src/CreateInterface.res ./src/Cross.res ./src/Dce.res ./src/Debug.res ./src/Definition.res ./src/DefinitionWithInterface.res ./src/DefinitionWithInterface.resi ./src/Div.res ./src/DocumentSymbol.res ./src/Fragment.res ./src/Highlight.res ./src/Hover.res ./src/InlayHint.res ./src/Jsx.res ./src/Jsx.resi ./src/LongIdentTest.res ./src/Object.res ./src/Patterns.res ./src/RecModules.res ./src/RecordCompletion.res ./src/RecoveryOnProp.res ./src/References.res ./src/ReferencesWithInterface.res ./src/ReferencesWithInterface.resi ./src/Rename.res ./src/RenameWithInterface.res ./src/RenameWithInterface.resi ./src/TableclothMap.ml ./src/TableclothMap.mli ./src/TypeDefinition.res ./src/Xform.res +Source files: ./src/Auto.res ./src/CodeLens.res ./src/CompletePrioritize1.res ./src/CompletePrioritize2.res ./src/Completion.res ./src/Component.res ./src/Component.resi ./src/CreateInterface.res ./src/Cross.res ./src/Dce.res ./src/Debug.res ./src/Definition.res ./src/DefinitionWithInterface.res ./src/DefinitionWithInterface.resi ./src/Div.res ./src/DocumentSymbol.res ./src/Fragment.res ./src/Highlight.res ./src/Hover.res ./src/InlayHint.res ./src/Jsx.res ./src/Jsx.resi ./src/LongIdentTest.res ./src/Object.res ./src/Patterns.res ./src/RecModules.res ./src/RecordCompletion.res ./src/RecoveryOnProp.res ./src/References.res ./src/ReferencesWithInterface.res ./src/ReferencesWithInterface.resi ./src/Rename.res ./src/RenameWithInterface.res ./src/RenameWithInterface.resi ./src/TableclothMap.ml ./src/TableclothMap.mli ./src/TypeDefinition.res ./src/Xform.res Impl cmt:./lib/bs/src/Auto.cmt res:./src/Auto.res +Impl cmt:./lib/bs/src/CodeLens.cmt res:./src/CodeLens.res Impl cmt:./lib/bs/src/CompletePrioritize1.cmt res:./src/CompletePrioritize1.res Impl cmt:./lib/bs/src/CompletePrioritize2.cmt res:./src/CompletePrioritize2.res Impl cmt:./lib/bs/src/Completion.cmt res:./src/Completion.res From c3fad00dcaf815e428df8dd2b303c177febeae3b Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 24 Jul 2022 22:06:25 +0200 Subject: [PATCH 08/13] Hide code lens functionality behind a setting. --- client/src/extension.ts | 5 ++++- package.json | 5 +++++ server/src/server.ts | 22 +++++++++++++++++++--- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/client/src/extension.ts b/client/src/extension.ts index 95d3387de..9e9cf89fd 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -240,7 +240,10 @@ export function activate(context: ExtensionContext) { // language client, and because of that requires a full restart. context.subscriptions.push( workspace.onDidChangeConfiguration(({ affectsConfiguration }) => { - if (affectsConfiguration("rescript.settings.inlayHints")) { + if ( + affectsConfiguration("rescript.settings.inlayHints") || + affectsConfiguration("rescript.settings.codeLens") + ) { commands.executeCommand("rescript-vscode.restart_language_server"); } }) diff --git a/package.json b/package.json index eb190c40b..3f99ceebd 100644 --- a/package.json +++ b/package.json @@ -146,6 +146,11 @@ ], "minimum": 0 }, + "rescript.settings.codeLens.enable": { + "type": "boolean", + "default": false, + "description": "Enable (experimental) code lens for function definitions." + }, "rescript.settings.binaryPath": { "type": ["string", "null"], "default": null, diff --git a/server/src/server.ts b/server/src/server.ts index 71e4f3fcb..316996807 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -31,6 +31,7 @@ interface extensionConfiguration { enable: boolean; maxLength: number | null; }; + codeLens: boolean; binaryPath: string | null; } let extensionConfiguration: extensionConfiguration = { @@ -39,6 +40,7 @@ let extensionConfiguration: extensionConfiguration = { enable: false, maxLength: 25 }, + codeLens: false, binaryPath: null, }; let pullConfigurationPeriodically: NodeJS.Timeout | null = null; @@ -230,6 +232,9 @@ let compilerLogsWatcher = chokidar if (extensionConfiguration.inlayHints.enable === true) { sendInlayHintsRefresh(); } + if (extensionConfiguration.codeLens === true) { + sendCodeLensRefresh(); + } }); let stopWatchingCompilerLog = () => { // TODO: cleanup of compilerLogs? @@ -424,6 +429,15 @@ function codeLens(msg: p.RequestMessage) { return response; } +function sendCodeLensRefresh() { + let request: p.RequestMessage = { + jsonrpc: c.jsonrpcVersion, + method: p.CodeLensRefreshRequest.method, + id: serverSentRequestIdCounter++, + }; + send(request); +} + function definition(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_definition let params = msg.params as p.DefinitionParams; @@ -1014,9 +1028,11 @@ function onMessage(msg: p.Message) { full: true, }, inlayHintProvider: extensionConfiguration.inlayHints.enable, - codeLensProvider: { - workDoneProgress: false - }, + codeLensProvider: extensionConfiguration.codeLens + ? { + workDoneProgress: false, + } + : undefined, }, }; let response: p.ResponseMessage = { From 122b4a312eafbc67216b8ed4cac6f1078a311d86 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Sun, 24 Jul 2022 22:07:16 +0200 Subject: [PATCH 09/13] Readme + changelog for code lenses. --- CHANGELOG.md | 2 ++ README.md | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bb7cd495..33c350334 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ #### :rocket: New Feature - Inlay Hints (experimetal). `rescript.settings.inlayHints.enable: true` +- Code Lenses for functions (experimetal). `rescript.settings.codeLens: true` + ## v1.4.2 #### :bug: Bug Fix diff --git a/README.md b/README.md index ed047c0d0..c432d7d2f 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,15 @@ rescript.settings.inlayHints.enable: true rescript.settings.inlayHints.maxLength: 25 ``` +### Code Lens (experimental) + +This tells the editor to add code lenses to function definitions, showing its full type as an annotation above the definition. + +```jsonc +// Enable (experimental) code lens. +rescript.settings.codeLens: true +``` + ### Hide generated files You can configure VSCode to collapse the JavaScript files ReScript generates under its source ReScript file. This will "hide" the generated files in the VSCode file explorer, but still leaving them accessible by expanding the source ReScript file they belong to. From b7e2d463aa9fec8a34e061d99f2a9e0001f5d675 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 25 Jul 2022 09:22:05 +0200 Subject: [PATCH 10/13] Clarify readme and changelog. --- CHANGELOG.md | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33c350334..f227d4717 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,8 @@ #### :rocket: New Feature -- Inlay Hints (experimetal). `rescript.settings.inlayHints.enable: true` -- Code Lenses for functions (experimetal). `rescript.settings.codeLens: true` +- Inlay Hints (experimetal). `rescript.settings.inlayHints.enable: true`. Turned off by default. +- Code Lenses for functions (experimetal). `rescript.settings.codeLens: true`. Turned off by default. ## v1.4.2 diff --git a/README.md b/README.md index c432d7d2f..d51428d8a 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ rescript.settings.inlayHints.maxLength: 25 ### Code Lens (experimental) -This tells the editor to add code lenses to function definitions, showing its full type as an annotation above the definition. +This tells the editor to add code lenses to function definitions, showing its full type above the definition. ```jsonc // Enable (experimental) code lens. From 0d5cbe0593f777bc3ba9ede7e35879c2bf9aef67 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 25 Jul 2022 09:22:36 +0200 Subject: [PATCH 11/13] Remove redundant default value. --- analysis/src/Shared.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/Shared.ml b/analysis/src/Shared.ml index a44ca111b..467238629 100644 --- a/analysis/src/Shared.ml +++ b/analysis/src/Shared.ml @@ -49,12 +49,12 @@ let declToString ?(recStatus = Types.Trec_not) name t = let cacheTypeToString = ref false let typeTbl = Hashtbl.create 1 -let typeToString ?(lineWidth = 60) (t : Types.type_expr) = +let typeToString ?lineWidth (t : Types.type_expr) = match if !cacheTypeToString then Hashtbl.find_opt typeTbl (t.id, t) else None with | None -> - let s = PrintType.printExpr ~lineWidth t in + let s = PrintType.printExpr ?lineWidth t in Hashtbl.replace typeTbl (t.id, t) s; s | Some s -> s From 775bd9cc7c8ec3d84a31090ec03f01ecd33fd485 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 25 Jul 2022 09:22:57 +0200 Subject: [PATCH 12/13] Add clarifying comments. --- analysis/src/Hint.ml | 2 ++ analysis/src/Protocol.ml | 5 +++++ client/src/extension.ts | 5 +++++ server/src/server.ts | 3 +++ 4 files changed, 15 insertions(+) diff --git a/analysis/src/Hint.ml b/analysis/src/Hint.ml index 788ad5005..0f90ff8ea 100644 --- a/analysis/src/Hint.ml +++ b/analysis/src/Hint.ml @@ -141,6 +141,8 @@ let codeLens ~path ~debug = Ast_iterator.default_iterator.value_binding iterator vb in let iterator = {Ast_iterator.default_iterator with value_binding} in + (* We only print code lenses in implementation files. This is because they'd be redundant in interface files, + where the definition itself will be the same thing as what would've been printed in the code lens. *) (if Filename.check_suffix path ".res" then let parser = Res_driver.parsingEngine.parseImplementation ~forPrinter:false diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index 5247a487d..a1440aa85 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -1,8 +1,13 @@ type position = {line: int; character: int} 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} + +(* https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#codeLens *) type codeLens = {range: range; command: command option} + type inlayHint = { position: position; label: string; diff --git a/client/src/extension.ts b/client/src/extension.ts index 9e9cf89fd..7bd85b918 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -240,6 +240,11 @@ export function activate(context: ExtensionContext) { // language client, and because of that requires a full restart. context.subscriptions.push( workspace.onDidChangeConfiguration(({ affectsConfiguration }) => { + // Put any configuration that, when changed, requires a full restart of + // the server here. That will typically be any configuration that affects + // the capabilities declared by the server, since those cannot be updated + // on the fly, and require a full restart with new capabilities set when + // initializing. if ( affectsConfiguration("rescript.settings.inlayHints") || affectsConfiguration("rescript.settings.codeLens") diff --git a/server/src/server.ts b/server/src/server.ts index 316996807..072195bf4 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -34,6 +34,9 @@ interface extensionConfiguration { codeLens: boolean; binaryPath: string | null; } + +// All values here are temporary, and will be overridden as the server is +// initialized, and the current config is received from the client. let extensionConfiguration: extensionConfiguration = { askToStartBuild: true, inlayHints: { From f430618ea93085f4e1931a4c8882409a30099abb Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 25 Jul 2022 13:24:22 +0200 Subject: [PATCH 13/13] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f227d4717..91e63f573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Inlay Hints (experimetal). `rescript.settings.inlayHints.enable: true`. Turned off by default. - Code Lenses for functions (experimetal). `rescript.settings.codeLens: true`. Turned off by default. +- Markdown code blocks tagged as `rescript` now get basic syntax highlighting. ## v1.4.2