From f6ab8d289eec5ea70d509a03c2e2fc184d3352d7 Mon Sep 17 00:00:00 2001 From: kenkangxgwe Date: Mon, 19 Sep 2022 02:55:42 -0700 Subject: [PATCH] Better "evaluate" positions for code lens - Show "evaluate" above outline headers. - Show "evaluate" above top-level cells which are divided by 2 empty lines mimic the behavior of a wl file opened in FrontEnd. --- src/WolframLanguageServer/Server.wl | 36 +++++++++++++--- src/WolframLanguageServer/TextDocument.wl | 50 +++++++++++++++++++++-- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/WolframLanguageServer/Server.wl b/src/WolframLanguageServer/Server.wl index 62adbc8..d4c4a65 100644 --- a/src/WolframLanguageServer/Server.wl +++ b/src/WolframLanguageServer/Server.wl @@ -1947,13 +1947,13 @@ handleRequest["textDocument/codeLens", msg_, state_] := With[ "character" -> 0 |> |>, - "data" -> <| + "command" -> Command[<| "title" -> "$(workflow) Evaluate File", "command" -> "dap-wl.evaluate-file", "arguments" -> {<| "uri" -> uri |>} - |> + |>] |>], Table[ CodeLens[<| @@ -1964,16 +1964,40 @@ handleRequest["textDocument/codeLens", msg_, state_] := With[ (* // ReplaceKey[{"end", "line"} -> codeRange["start"]["line"]] // ReplaceKey[{"end", "character"} -> 1] *) ), - "data" -> <| - "title" -> "$(play) Evaluate", + "command" -> Command[<| + "title" -> ( + {codeRange["start"]["line"] + 1, codeRange["end"]["line"] + 1} + // Apply[If[Equal, + StringTemplate["$(play) Evaluate line `1`"], + StringTemplate["$(play) Evaluate line `1`~`2`"] + ]] // Through + ), "command" -> "dap-wl.evaluate-range", "arguments" -> {<| "uri" -> uri, "range" -> codeRange |>} - |> + |>] + |>], + {codeRange, doc // FindTopLevelRanges} + ], + Table[ + CodeLens[<| + (* range can only span one line *) + "range" -> ( + heading["range"] + // ReplaceKey["end" -> heading["range"]["start"]] + ), + "command" -> Command[<| + "title" -> (heading["style"] // StringTemplate["$(play) Evaluate `1`"]), + "command" -> "dap-wl.evaluate-range", + "arguments" -> {<| + "uri" -> uri, + "range" -> heading["range"] + |>} + |>] |>], - {codeRange, doc // FindAllCodeRanges} + {heading, doc // FindHeadings} ] }, {} diff --git a/src/WolframLanguageServer/TextDocument.wl b/src/WolframLanguageServer/TextDocument.wl index 263fbaf..edba8c6 100644 --- a/src/WolframLanguageServer/TextDocument.wl +++ b/src/WolframLanguageServer/TextDocument.wl @@ -32,7 +32,9 @@ FindDocumentHighlight::usage = "FindDocumentHighlight[doc_TextDocument, pos_LspP PositionValidQ::usage = "PositionValidQ[doc_TextDocument, pos_LspPosition] returns true if the pos is valid in the doc." GetSymbolAtPosition::usage = "GetSymbolAtPosition[doc_TextDocument, pos_LspPosition] returns the symbol at the given location, otherwise Missing[\"NotFound\"]." GetSymbolRangeAtPosition::usage = "GetSymbolRangeAtPosition[doc_TextDocument, pos_LspPosition] returns the range of the symbol at the given location, otherwise Missing[\"NotFound\"]." +FindTopLevelRanges::usage = "FindTopLevelRanges[doc_TextDocument] returns a list of LspRange which locate all the code ranges (cells) in the given doc." FindAllCodeRanges::usage = "FindAllCodeRanges[doc_TextDocument] returns a list of LspRange which locate all the code ranges (cells) in the given doc." +FindHeadings::usage = "FindHeadings[doc_TextDocument] returns a list of Associations that includes range and style of all heading cells in the given doc." GetCodeActionsInRange::usage = "GetCodeActionsInRange[doc_TextDocument, range_LspRange] returns a list of CodeAction related to specified range." GetDocumentText::usage = "GetDocumentText[doc_TextDocument] returns the text of the whole doc except for the shebang line (if exists).\n\ GetDocumentText[doc_TextDocument, range_LspRange] returns the text of the doc at given range." @@ -452,6 +454,17 @@ ScriptFileQ[uri_String] := URLParse[uri, "Path"] // Last // FileExtension // Equ (*Code Range*) +getCodeCells[doc_TextDocument] := ( + If[(doc["uri"] // MissingQ) || ($CodeCells[doc["uri"]] // MissingQ), + doc + // divideCells + // Last, + $CodeCells[doc["uri"]] + // Keys + // Part[#, All, 1]& + ] +) + getCodeRanges[doc_TextDocument, _:All] := ( If[(doc["uri"] // MissingQ) || ($CodeRange[doc["uri"]] // MissingQ), doc @@ -602,17 +615,18 @@ rangeToSyntaxTree[doc_TextDocument, ranges:{{_Integer, _Integer}...}] := With[ AssociateTo[$CodeRange[uri], newRules // KeyTake[addRanges]]; $CodeRange // Lookup[uri] - // Lookup[newRules // Keys] + // KeyTake[newRules // Keys] ] ] - // Replace[err:Except[{KeyValuePattern[{"cst" -> _List, "ast" -> _List}]...}] :> ( + // Replace[err:Except[Association[({_Integer, _Integer} -> KeyValuePattern[{"cst" -> _List, "ast" -> _List}])...]] :> ( LogError[{"rangeToSyntaxTree: ", err}]; {} )] ] -rangeToAst = rangeToSyntaxTree /* Map[Lookup["ast"]] /* Catenate -rangeToCst = rangeToSyntaxTree /* Map[Lookup["cst"]] /* Catenate +rangeToAst = rangeToSyntaxTree /* Values /* Map[Lookup["ast"]] /* Catenate +rangeToCst = rangeToSyntaxTree /* Values /* Map[Lookup["cst"]] /* Catenate +rangeToTopLevelRanges = rangeToSyntaxTree /* Keys rangeToCode[doc_TextDocument, {startLine_Integer, endLine_Integer}] := ( @@ -772,6 +786,34 @@ GetSymbolRangeAtPosition[doc_TextDocument, pos_LspPosition] := With[ ] +FindTopLevelRanges[doc_TextDocument] := ( + doc + // getCodeCells + // Map[ + rangeToTopLevelRanges[doc, #]& + /* (ranges \[Function] ( + SequenceCases[ranges, {{_, prevEnd_}, {start_, _}} /; (prevEnd + 2 < start) :> start, Overlaps -> True] + // {# // Prepend[ranges // First // First], (# - 3) // Append[ranges // Last // Last]}& + // Transpose + )) + ] + // Catenate + // Map[ToLspRange[doc, #]&] +) + + +FindHeadings[doc_TextDocument] := ( + doc + // getCell + // Cases[#, CellNode[KeyValuePattern[{"style" -> style_?HeadingQ, "range" -> range_}]] :> ( + <| + "style" -> style, + "range" -> (ToLspRange[doc, range]) + |> + ), {1, -3}]& // LogDebug +) + + FindAllCodeRanges[doc_TextDocument] := ( doc // getCodeRanges