Skip to content

Commit 3200404

Browse files
committed
Expand one level of type definition on hover.
Fixes #557
1 parent 8ee93d1 commit 3200404

File tree

7 files changed

+77
-30
lines changed

7 files changed

+77
-30
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
- Add support for prop completion for JSX V4 https://github.com/rescript-lang/rescript-vscode/pull/579
1818
- Add support for create interface file for JSX V4 https://github.com/rescript-lang/rescript-vscode/pull/580
19+
- Expand one level of type definition on hover. Dig into record/variant body.
1920

2021
## v1.6.0
2122

analysis/src/Hover.ml

+43-15
Original file line numberDiff line numberDiff line change
@@ -98,25 +98,53 @@ let newHover ~full:{file; package} locItem =
9898
| Const_int64 _ -> "int64"
9999
| Const_nativeint _ -> "int"))
100100
| Typed (_, t, locKind) ->
101+
let fromConstructorPath ~env path =
102+
match References.digConstructor ~env ~package path with
103+
| None -> None
104+
| Some (_env, {name = {txt}; item = {decl}}) ->
105+
if Utils.isUncurriedInternal path then None
106+
else Some (decl |> Shared.declToString txt |> codeBlock)
107+
in
101108
let fromType ~docstring typ =
102109
let typeString = codeBlock (typ |> Shared.typeToString) in
103-
let extraTypeInfo =
110+
let typeDefinitions =
111+
(* Expand definitions of types mentioned in typ.
112+
If typ itself is a record or variant, search its body *)
104113
let env = QueryEnv.fromFile file in
105-
match typ |> Shared.digConstructor with
106-
| None -> None
107-
| Some path -> (
108-
match References.digConstructor ~env ~package path with
109-
| None -> None
110-
| Some (_env, {docstring; name = {txt}; item = {decl}}) ->
111-
if Utils.isUncurriedInternal path then None
112-
else Some (decl |> Shared.declToString txt, docstring))
113-
in
114-
let typeString, docstring =
115-
match extraTypeInfo with
116-
| None -> (typeString, docstring)
117-
| Some (extra, extraDocstring) ->
118-
(typeString ^ "\n\n" ^ codeBlock extra, extraDocstring)
114+
let envToSearch, typesToSearch =
115+
match typ |> Shared.digConstructor with
116+
| Some path -> (
117+
let labelDeclarationsTypes lds =
118+
lds |> List.map (fun (ld : Types.label_declaration) -> ld.ld_type)
119+
in
120+
match References.digConstructor ~env ~package path with
121+
| None -> (env, [typ])
122+
| Some (env1, {item = {decl}}) -> (
123+
match decl.type_kind with
124+
| Type_record (lds, _) ->
125+
(env1, typ :: (lds |> labelDeclarationsTypes))
126+
| Type_variant cds ->
127+
( env1,
128+
cds
129+
|> List.map (fun (cd : Types.constructor_declaration) ->
130+
let fromArgs =
131+
match cd.cd_args with
132+
| Cstr_tuple ts -> ts
133+
| Cstr_record lds -> lds |> labelDeclarationsTypes
134+
in
135+
typ
136+
::
137+
(match cd.cd_res with
138+
| None -> fromArgs
139+
| Some t -> t :: fromArgs))
140+
|> List.flatten )
141+
| _ -> (env, [typ])))
142+
| None -> (env, [typ])
143+
in
144+
let constructors = Shared.findTypeConstructors typesToSearch in
145+
constructors |> List.filter_map (fromConstructorPath ~env:envToSearch)
119146
in
147+
let typeString = typeString :: typeDefinitions |> String.concat "\n\n" in
120148
(typeString, docstring)
121149
in
122150
let parts =

analysis/src/Shared.ml

+28-10
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,38 @@ let tryReadCmi cmi =
2929
None
3030
| x -> Some x
3131

32-
(** TODO move to the Process_ stuff *)
33-
let rec dig typ =
34-
match typ.Types.desc with
35-
| Types.Tlink inner -> dig inner
36-
| Types.Tsubst inner -> dig inner
37-
| Types.Tpoly (inner, _) -> dig inner
38-
| _ -> typ
32+
let rec dig (te : Types.type_expr) =
33+
match te.desc with
34+
| Tlink inner -> dig inner
35+
| Tsubst inner -> dig inner
36+
| Tpoly (inner, _) -> dig inner
37+
| _ -> te
3938

40-
let digConstructor expr =
41-
let expr = dig expr in
42-
match expr.desc with
39+
let digConstructor te =
40+
match (dig te).desc with
4341
| Tconstr (path, _args, _memo) -> Some path
4442
| _ -> None
4543

44+
let findTypeConstructors (tel : Types.type_expr list) =
45+
let paths = ref [] in
46+
let addPath path =
47+
if not (List.exists (Path.same path) !paths) then paths := path :: !paths
48+
in
49+
let rec loop (te : Types.type_expr) =
50+
match te.desc with
51+
| Tlink te1 | Tsubst te1 | Tpoly (te1, _) -> loop te1
52+
| Tconstr (path, _, _) -> addPath path
53+
| Tarrow (_, te1, te2, _) ->
54+
loop te1;
55+
loop te2
56+
| Ttuple tel -> tel |> List.iter loop
57+
| Tnil | Tvar _ | Tobject _ | Tfield _ | Tvariant _ | Tunivar _ | Tpackage _
58+
->
59+
()
60+
in
61+
tel |> List.iter loop;
62+
!paths |> List.rev
63+
4664
let declToString ?(recStatus = Types.Trec_not) name t =
4765
PrintType.printDecl ~recStatus name t
4866

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Hover src/Auto.res 2:13
2-
{"contents": "```rescript\n(Belt.List.t<'a>, 'a => 'b) => Belt.List.t<'b>\n```\n\n\n Returns a new list with `f` applied to each element of `someList`.\n\n ```res example\n list{1, 2}->Belt.List.map(x => x + 1) // list{3, 4}\n ```\n"}
2+
{"contents": "```rescript\n(Belt.List.t<'a>, 'a => 'b) => Belt.List.t<'b>\n```\n\n```rescript\ntype t<'a> = list<'a>\n```\n\n\n Returns a new list with `f` applied to each element of `someList`.\n\n ```res example\n list{1, 2}->Belt.List.map(x => x + 1) // list{3, 4}\n ```\n"}
33

analysis/tests/src/expected/Definition.res.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Hover src/Definition.res 14:14
88
{"contents": "```rescript\n('a => 'b, list<'a>) => list<'b>\n```\n\n [List.map f [a1; ...; an]] applies function [f] to [a1, ..., an],\n and builds the list [[f a1; ...; f an]]\n with the results returned by [f]. Not tail-recursive. "}
99

1010
Hover src/Definition.res 18:14
11-
{"contents": "```rescript\n(Belt.List.t<'a>, 'a => 'b) => Belt.List.t<'b>\n```\n\n\n Returns a new list with `f` applied to each element of `someList`.\n\n ```res example\n list{1, 2}->Belt.List.map(x => x + 1) // list{3, 4}\n ```\n"}
11+
{"contents": "```rescript\n(Belt.List.t<'a>, 'a => 'b) => Belt.List.t<'b>\n```\n\n```rescript\ntype t<'a> = list<'a>\n```\n\n\n Returns a new list with `f` applied to each element of `someList`.\n\n ```res example\n list{1, 2}->Belt.List.map(x => x + 1) // list{3, 4}\n ```\n"}
1212

1313
Hover src/Definition.res 23:3
1414
{"contents": "```rescript\n(. int, int) => int\n```"}

analysis/tests/src/expected/Div.res.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Hover src/Div.res 0:10
22
getLocItem #3: heuristic for <div>
3-
{"contents": "```rescript\n(\n string,\n ~props: ReactDOMRe.domProps=?,\n array<React.element>,\n) => React.element\n```"}
3+
{"contents": "```rescript\n(\n string,\n ~props: ReactDOMRe.domProps=?,\n array<React.element>,\n) => React.element\n```\n\n```rescript\ntype element\n```"}
44

55
Complete src/Div.res 3:17
66
posCursor:[3:17] posNoWhite:[3:16] Found expr:[3:4->3:17]

analysis/tests/src/expected/Hover.res.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ Hover src/Hover.res 106:21
7575
{"contents": "```rescript\nint\n```"}
7676

7777
Hover src/Hover.res 116:16
78-
{"contents": "```rescript\nAA.cond<[< #str(string)]> => AA.cond<[< #str(string)]>\n```"}
78+
{"contents": "```rescript\nAA.cond<[< #str(string)]> => AA.cond<[< #str(string)]>\n```\n\n```rescript\ntype cond<'a> = 'a\n constraint 'a = [< #str(string)]\n```"}
7979

8080
Hover src/Hover.res 119:25
81-
{"contents": "```rescript\nAA.cond<[< #str(string)]> => AA.cond<[< #str(string)]>\n```"}
81+
{"contents": "```rescript\nAA.cond<[< #str(string)]> => AA.cond<[< #str(string)]>\n```\n\n```rescript\ntype cond<'a> = 'a\n constraint 'a = [< #str(string)]\n```"}
8282

8383
Hover src/Hover.res 122:3
8484
Nothing at that position. Now trying to use completion.

0 commit comments

Comments
 (0)