From 045ddc2635d5781193faa7cb9bb725b900cbdf06 Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Sun, 18 Apr 2021 07:40:04 +0200 Subject: [PATCH] Fix hover on labels with type annotation in components. Fixes https://github.com/rescript-lang/rescript-editor-support/issues/132. --- Changes.md | 2 +- src/References.ml | 36 ++++++++++++++++++--------- src/SharedTypes.ml | 43 +++++++++++++++++++++++++-------- src/Utils.ml | 6 ++--- test/src/Hover.res | 4 +++ test/src/expected/Hover.res.txt | 3 +++ 6 files changed, 69 insertions(+), 25 deletions(-) diff --git a/Changes.md b/Changes.md index f371fcec..549dccbb 100644 --- a/Changes.md +++ b/Changes.md @@ -4,7 +4,7 @@ - Add autocomplete for props in JSX components. - Autocomplete: fix issue where `->` autocomplete was overruling `.`. See https://github.com/rescript-lang/rescript-editor-support/issues/99. - Add pipe autocomplete for builtin list, array, string, option types. And for string and array literals. -- Fix hover on labels in component functions with compiler version 9.1. +- Fix hover on labels in component functions with compiler version 9.1, and labels with type annotation. ## Release 1.0.6 of rescript-vscode This [commit](https://github.com/rescript-lang/rescript-editor-support/commit/03ee0d97b250474028d4fb08eac81ddb21ccb082) is vendored in [rescript-vscode 1.0.6](https://github.com/rescript-lang/rescript-vscode/releases/tag/1.0.6). diff --git a/src/References.ml b/src/References.ml index 8ddc54a8..0ccfa5dd 100644 --- a/src/References.ml +++ b/src/References.ml @@ -18,11 +18,12 @@ let locsForPos ~extra pos = extra.locations |> List.filter (fun (loc, _l) -> checkPos pos loc) let locForPos ~extra pos = - match locsForPos ~extra pos with + let locs = locsForPos ~extra pos in + match locs with | [(loc1, Typed (_, LocalReference _)); ((loc3, _) as l3)] when loc1 = loc3 -> - (* JSX and compiler combined: *) - (* ~x becomes Props#x *) - (* heuristic for: [Props, x], give loc of `x` *) + (* JSX and compiler combined: + ~x becomes Props#x + heuristic for: [Props, x], give loc of `x` *) Some l3 | [ (loc1, Typed (_, LocalReference _)); @@ -31,18 +32,31 @@ let locForPos ~extra pos = ] (* For older compiler 9.0 or earlier *) when loc1 = loc2 && loc2 = loc3 -> - (* JSX and compiler combined: *) - (* ~x becomes Js_OO.unsafe_downgrade(Props)#x *) - (* heuristic for: [Props, unsafe_downgrade, x], give loc of `x` *) + (* JSX and compiler combined: + ~x becomes Js_OO.unsafe_downgrade(Props)#x + heuristic for: [Props, unsafe_downgrade, x], give loc of `x` *) Some l3 + | [ + ((_, Typed (_, LocalReference (_, Value))) as _l1); + ((_, Typed (_, Definition (_, Value))) as l2); + ] -> + (* JSX on type-annotated labeled (~arg:t): + (~arg:t) becomes Props#arg + Props has the location range of arg:t + arg has the location range of arg + heuristic for: [Props, arg], give loc of `arg` *) + (* Printf.eprintf "l1 %s\nl2 %s\n" + (SharedTypes.locationToString _l1) + (SharedTypes.locationToString l2); *) + Some l2 | [(loc1, _); ((loc2, _) as l); (loc3, _)] when loc1 = loc2 && loc2 = loc3 -> - (* JSX with at most one child *) - (* heuristic for: [makeProps, make, createElement], give the loc of `make` *) + (* JSX with at most one child + heuristic for: [makeProps, make, createElement], give the loc of `make` *) Some l | [(loc1, _); (loc2, _); ((loc3, _) as l); (loc4, _)] when loc1 = loc2 && loc2 = loc3 && loc3 = loc4 -> - (* JSX variadic, e.g. {x} {y} *) - (* heuristic for: [makeProps, React.null, make, createElementVariadic], give the loc of `make` *) + (* JSX variadic, e.g. {x} {y} + heuristic for: [makeProps , React.null, make, createElementVariadic], give the loc of `make` *) Some l | l :: _ -> Some l | _ -> None diff --git a/src/SharedTypes.ml b/src/SharedTypes.ml index b7d7de45..f9c5ec08 100644 --- a/src/SharedTypes.ml +++ b/src/SharedTypes.ml @@ -24,7 +24,7 @@ let getCmt ?(interface = true) p = match p with | Impl (c, _) | Intf (c, _) -> c | IntfAndImpl (cint, _, cimpl, _) -> ( - match interface with true -> cint | false -> cimpl ) + match interface with true -> cint | false -> cimpl) type visibilityPath = | File of Uri2.t * string @@ -42,9 +42,9 @@ type 't declared = { deprecated : string option; docstring : string list; item : 't; - (* TODO: maybe add a uri? *) - (* scopeType: scope, *) - (* scopeStart: (int, int), *) + (* TODO: maybe add a uri? *) + (* scopeType: scope, *) + (* scopeStart: (int, int), *) } let emptyDeclared name = @@ -95,17 +95,16 @@ type exported = { types : namedStampMap; values : namedStampMap; modules : namedStampMap; - (* constructors: namedStampMap, *) - (* classes: namedStampMap, - classTypes: namedStampMap, *) + (* constructors: namedStampMap, *) + (* classes: namedStampMap, + classTypes: namedStampMap, *) } let initExported () = { types = Hashtbl.create 10; values = Hashtbl.create 10; - modules = Hashtbl.create 10; - (* constructors: Hashtbl.create(10), *) + modules = Hashtbl.create 10 (* constructors: Hashtbl.create(10), *); } type moduleItem = @@ -191,7 +190,6 @@ type openTracker = { mutable used : (path * tip * Location.t) list; } -(** These are the bits of info that we need to make in-app stuff awesome *) type extra = { internalReferences : (int, Location.t list) Hashtbl.t; externalReferences : (string, (path * tip * Location.t) list) Hashtbl.t; @@ -201,6 +199,7 @@ type extra = { (* OPTIMIZE: using a stack to come up with this would cut the computation time of this considerably. *) opens : (Location.t, openTracker) Hashtbl.t; } +(** These are the bits of info that we need to make in-app stuff awesome *) type full = {extra : extra; file : file} @@ -213,3 +212,27 @@ let initExtra () = } let hashList h = Hashtbl.fold (fun a b c -> (a, b) :: c) h [] + +let locKindToString = function + | LocalReference (_, tip) -> "(LocalReference " ^ tipToString tip ^ ")" + | GlobalReference _ -> "GlobalReference" + | NotFound -> "NotFound" + | Definition (_, tip) -> "(Definition " ^ tipToString tip ^ ")" + +let locToString = function + | Typed (e, locKind) -> + "Typed " ^ Shared.typeToString e ^ " " ^ locKindToString locKind + | Constant _ -> "Constant" + | LModule _ -> "LModule" + | TopLevelModule _ -> "TopLevelModule" + | TypeDefinition _ -> "TypeDefinition" + | Explanation _ -> "Explanation" + +let locationToString ({Location.loc_start; loc_end}, loc) = + let pos1 = Utils.cmtPosToPosition loc_start in + let pos2 = Utils.cmtPosToPosition loc_end in + Printf.sprintf "%d:%d-%d:%d %s" pos1.line pos1.character pos2.line + pos2.character (locToString loc) + +(* for debugging *) +let _ = locationToString \ No newline at end of file diff --git a/src/Utils.ml b/src/Utils.ml index 444b4f5c..d5663261 100644 --- a/src/Utils.ml +++ b/src/Utils.ml @@ -26,14 +26,14 @@ let endsWith s suffix = let protocolLineColToCmtLoc ~line ~col = (line + 1, col) -let cmtLocToPosition {Lexing.pos_lnum; pos_cnum; pos_bol} = Protocol.{ +let cmtPosToPosition {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; + start = cmtPosToPosition loc_start; + end_ = cmtPosToPosition loc_end; } let locWithinLoc inner outer = diff --git a/test/src/Hover.res b/test/src/Hover.res index 3f33f014..a51b13d3 100644 --- a/test/src/Hover.res +++ b/test/src/Hover.res @@ -36,4 +36,8 @@ let functionWithTypeAnnotation : unit => int = () => 1 @react.component let make = (~name) => React.string(name) +// ^hov + +@react.component +let make2 = (~name:string) => React.string(name) // ^hov \ No newline at end of file diff --git a/test/src/expected/Hover.res.txt b/test/src/expected/Hover.res.txt index 2faaa45a..11c5f326 100644 --- a/test/src/expected/Hover.res.txt +++ b/test/src/expected/Hover.res.txt @@ -22,3 +22,6 @@ Hover src/Hover.res 33:4 Hover src/Hover.res 37:13 {"contents": "```rescript\nstring\n```"} +Hover src/Hover.res 41:13 +{"contents": "```rescript\nstring\n```"} +