From 541f6a9d627b3fd5e31518b6f332cc9a6b8db006 Mon Sep 17 00:00:00 2001 From: Cheng Lou Date: Mon, 12 Apr 2021 03:56:42 -0700 Subject: [PATCH] Split definition into a dedicated api Just like we did for hover --- src/EditorSupportCommands.ml | 62 ++++++++++++++++++++++++++++++++++++ src/Protocol.ml | 28 ++++++++++++++++ src/RescriptEditorSupport.ml | 6 ++++ src/Utils.ml | 10 ++++++ 4 files changed, 106 insertions(+) diff --git a/src/EditorSupportCommands.ml b/src/EditorSupportCommands.ml index ade4259e..1c8cfe8b 100644 --- a/src/EditorSupportCommands.ml +++ b/src/EditorSupportCommands.ml @@ -192,3 +192,65 @@ let hover ~path ~line ~char = hover state ~file ~line ~char ~extra ~package in print_endline result + +let definition state ~file ~line ~char ~extra ~package = + let open TopTypes in + let locations = + extra.SharedTypes.locations + |> List.filter (fun (l, _) -> not l.Location.loc_ghost) + in + let locations = + let pos = (line, char) in + let pos = Utils.cmtLocFromVscode pos in + match References.locForPos ~extra:{extra with locations} pos with + | None -> [] + | Some l -> [l] + in + let locationsInfo = + locations + |> Utils.filterMap (fun (_, loc) -> + let locIsModule = + match loc with + | SharedTypes.LModule _ | TopLevelModule _ -> true + | TypeDefinition _ | Typed _ | Constant _ | Explanation _ -> false + in + let uriLocOpt = + References.definitionForLoc ~pathsForModule:package.pathsForModule + ~file ~getUri:(State.fileForUri state) + ~getModule:(State.fileForModule state ~package) + loc + in + let def, skipZero = + match uriLocOpt with + | None -> (None, false) + | Some (uri2, loc) -> + let posIsZero {Lexing.pos_lnum; pos_bol; pos_cnum} = + pos_lnum = 1 && pos_cnum - pos_bol = 0 + in + (* Skip if range is all zero, unless it's a module *) + let skipZero = + (not locIsModule) && loc.loc_start |> posIsZero + && loc.loc_end |> posIsZero + in + let open Protocol in + ( Some {uri = Uri2.toString uri2; range = Utils.cmtLocToRange loc}, + skipZero ) + in + let skip = skipZero || def = None in + match skip with true -> None | false -> def) + in + match locationsInfo with + | [] -> Protocol.null + | head :: _ -> Protocol.stringifyLocation head + +let definition ~path ~line ~char = + let state = TopTypes.empty () in + let filePath = Files.maybeConcat (Unix.getcwd ()) path in + let uri = Uri2.fromPath filePath in + let result = + match State.getFullFromCmt ~state ~uri with + | Error _message -> Protocol.null + | Ok (package, {file; extra}) -> + definition state ~file ~line ~char ~extra ~package + in + print_endline result diff --git a/src/Protocol.ml b/src/Protocol.ml index ab3c949d..79b14346 100644 --- a/src/Protocol.ml +++ b/src/Protocol.ml @@ -1,5 +1,15 @@ let array l = "[" ^ (String.concat ", " l) ^ "]" +type position = { + line: int; + character: int; +} + +type range = { + start: position; + end_: position; +} + type markupContent = { kind: string; value: string; @@ -17,6 +27,19 @@ type hover = { contents: string; } +type location = { + uri: string; + range: range; +} + +let stringifyPosition p = + Printf.sprintf {|{"line": "%i", "character": "%i"}|} p.line p.character + +let stringifyRange r = + Printf.sprintf {|{"start": "%s", "end": "%s"}|} + (stringifyPosition r.start) + (stringifyPosition r.end_) + let stringifyMarkupContent (m: markupContent) = Printf.sprintf {|{"kind": "%s", "value": "%s"}|} m.kind (String.escaped m.value) @@ -39,4 +62,9 @@ let stringifyHover h = Printf.sprintf {|{"contents": "%s"}|} (String.escaped h.contents) +let stringifyLocation h = + Printf.sprintf {|{"uri": "%s", "range": "%s"}|} + (String.escaped h.uri) + (stringifyRange h.range) + let null = "null" diff --git a/src/RescriptEditorSupport.ml b/src/RescriptEditorSupport.ml index bb4c8609..c2a8ed60 100644 --- a/src/RescriptEditorSupport.ml +++ b/src/RescriptEditorSupport.ml @@ -40,6 +40,10 @@ Options: hover: get inferred type for Foo.res at line 10 column 2: rescript-editor-support.exe hover src/Foo.res 10 2 + + definition: get inferred type for Foo.res at line 10 column 2: + + rescript-editor-support.exe definition src/Foo.res 10 2 |} let showHelp () = prerr_endline help @@ -53,6 +57,8 @@ let main () = ~char:(int_of_string char) ~currentFile | _opts, ["hover"; path; line; char] -> EditorSupportCommands.hover ~path ~line:(int_of_string line) ~char:(int_of_string char) + | _opts, ["definition"; path; line; char] -> + EditorSupportCommands.definition ~path ~line:(int_of_string line) ~char:(int_of_string char) | _ -> showHelp (); exit 1 diff --git a/src/Utils.ml b/src/Utils.ml index 7882b696..464eca9b 100644 --- a/src/Utils.ml +++ b/src/Utils.ml @@ -41,6 +41,16 @@ let endsWith s suffix = let cmtLocFromVscode (line, col) = (line + 1, col) +let cmtLocToPosition {Lexing.pos_lnum; pos_cnum; pos_bol} = Protocol.{ + line = pos_lnum - 1; + character = pos_cnum - pos_bol; +} + +let cmtLocToRange {Location.loc_start; loc_end} = Protocol.{ + start = cmtLocToPosition loc_start; + end_ = cmtLocToPosition loc_end; +} + let locWithinLoc inner outer = let open Location in inner.loc_start.pos_cnum >= outer.loc_start.pos_cnum