Skip to content

Commit 7220f57

Browse files
committed
clean up details and documentation output on completion items
1 parent c7114a7 commit 7220f57

26 files changed

+704
-625
lines changed

analysis/src/Commands.ml

+5-6
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ let completion ~debug ~path ~pos ~currentFile =
44
Completions.getCompletions ~debug ~path ~pos ~currentFile ~forHover:false
55
with
66
| None -> []
7-
| Some (completions, _, _) -> completions
7+
| Some (completions, full, _) ->
8+
completions
9+
|> List.map (CompletionBackEnd.completionToItem ~full)
10+
|> List.map Protocol.stringifyCompletionItem
811
in
9-
print_endline
10-
(completions
11-
|> List.map CompletionBackEnd.completionToItem
12-
|> List.map Protocol.stringifyCompletionItem
13-
|> Protocol.array)
12+
completions |> Protocol.array |> print_endline
1413

1514
let inlayhint ~path ~pos ~maxLength ~debug =
1615
let result =

analysis/src/CompletionBackEnd.ml

+105-30
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ let completionForExporteds iterExported getDeclared ~prefix ~exact ~env
7979
res :=
8080
{
8181
(Completion.create declared.name.txt ~env
82-
~kind:(transformContents declared.item))
82+
~kind:(transformContents declared))
8383
with
8484
deprecated = declared.deprecated;
8585
docstring = declared.docstring;
@@ -90,18 +90,20 @@ let completionForExporteds iterExported getDeclared ~prefix ~exact ~env
9090

9191
let completionForExportedModules ~env ~prefix ~exact ~namesUsed =
9292
completionForExporteds (Exported.iter env.QueryEnv.exported Exported.Module)
93-
(Stamps.findModule env.file.stamps) ~prefix ~exact ~env ~namesUsed (fun m ->
94-
Completion.Module m)
93+
(Stamps.findModule env.file.stamps) ~prefix ~exact ~env ~namesUsed
94+
(fun declared ->
95+
Completion.Module
96+
{docstring = declared.docstring; module_ = declared.item})
9597

9698
let completionForExportedValues ~env ~prefix ~exact ~namesUsed =
9799
completionForExporteds (Exported.iter env.QueryEnv.exported Exported.Value)
98-
(Stamps.findValue env.file.stamps) ~prefix ~exact ~env ~namesUsed (fun v ->
99-
Completion.Value v)
100+
(Stamps.findValue env.file.stamps) ~prefix ~exact ~env ~namesUsed
101+
(fun declared -> Completion.Value declared.item)
100102

101103
let completionForExportedTypes ~env ~prefix ~exact ~namesUsed =
102104
completionForExporteds (Exported.iter env.QueryEnv.exported Exported.Type)
103-
(Stamps.findType env.file.stamps) ~prefix ~exact ~env ~namesUsed (fun t ->
104-
Completion.Type t)
105+
(Stamps.findType env.file.stamps) ~prefix ~exact ~env ~namesUsed
106+
(fun declared -> Completion.Type declared.item)
105107

106108
let completionsForExportedConstructors ~(env : QueryEnv.t) ~prefix ~exact
107109
~namesUsed =
@@ -224,39 +226,104 @@ let getEnvWithOpens ~scope ~(env : QueryEnv.t) ~package
224226
| None -> None
225227
| Some env -> ResolvePath.resolvePath ~env ~package ~path))
226228

229+
let rec expandTypeExpr ~env ~package typeExpr =
230+
match typeExpr |> Shared.digConstructor with
231+
| Some path -> (
232+
match References.digConstructor ~env ~package path with
233+
| None -> None
234+
| Some (env, {item = {decl = {type_manifest = Some t}}}) ->
235+
expandTypeExpr ~env ~package t
236+
| Some (_, {docstring; item}) -> Some (docstring, item))
237+
| None -> None
238+
239+
let kindToDocumentation ~env ~full ~currentDocstring name
240+
(kind : Completion.kind) =
241+
let docsFromKind =
242+
match kind with
243+
| ObjLabel _ | Label _ | FileModule _ | Snippet _ | FollowContextPath _ ->
244+
[]
245+
| Module {docstring} -> docstring
246+
| Type {decl; name} ->
247+
[decl |> Shared.declToString name |> Markdown.codeBlock]
248+
| Value typ -> (
249+
match expandTypeExpr ~env ~package:full.package typ with
250+
| None -> []
251+
| Some (docstrings, {decl; name; kind}) ->
252+
docstrings
253+
@ [
254+
(match kind with
255+
| Record _ | Tuple _ | Variant _ ->
256+
Markdown.codeBlock (Shared.declToString name decl)
257+
| _ -> "");
258+
])
259+
| Field ({typ; optional; docstring}, s) ->
260+
(* Handle optional fields. Checking for "?" is because sometimes optional
261+
fields are prefixed with "?" when completing, and at that point we don't
262+
need to _also_ add a "?" after the field name, as that looks weird. *)
263+
docstring
264+
@ [
265+
Markdown.codeBlock
266+
(if optional && Utils.startsWith name "?" = false then
267+
name ^ "?: "
268+
^ (typ |> Utils.unwrapIfOption |> Shared.typeToString)
269+
else name ^ ": " ^ (typ |> Shared.typeToString));
270+
Markdown.codeBlock s;
271+
]
272+
| Constructor (c, s) ->
273+
[Markdown.codeBlock (showConstructor c); Markdown.codeBlock s]
274+
| PolyvariantConstructor ({displayName; args}, s) ->
275+
[
276+
Markdown.codeBlock
277+
("#" ^ displayName
278+
^
279+
match args with
280+
| [] -> ""
281+
| typeExprs ->
282+
"("
283+
^ (typeExprs
284+
|> List.map (fun typeExpr -> typeExpr |> Shared.typeToString)
285+
|> String.concat ", ")
286+
^ ")");
287+
Markdown.codeBlock s;
288+
]
289+
| ExtractedType (extractedType, _) ->
290+
[Markdown.codeBlock (TypeUtils.extractedTypeToString extractedType)]
291+
in
292+
currentDocstring @ docsFromKind
293+
|> List.filter (fun s -> s <> "")
294+
|> String.concat "\n\n"
295+
227296
let kindToDetail name (kind : Completion.kind) =
228297
match kind with
229-
| Type {decl} -> decl |> Shared.declToString name
298+
| Type {name} -> "type " ^ name
230299
| Value typ -> typ |> Shared.typeToString
231300
| ObjLabel typ -> typ |> Shared.typeToString
232301
| Label typString -> typString
233-
| Module _ -> "module"
234-
| FileModule _ -> "file module"
235-
| Field ({typ; optional}, s) ->
302+
| Module _ -> "module " ^ name
303+
| FileModule f -> "module " ^ f
304+
| Field ({typ; optional}, _) ->
236305
(* Handle optional fields. Checking for "?" is because sometimes optional
237306
fields are prefixed with "?" when completing, and at that point we don't
238307
need to _also_ add a "?" after the field name, as that looks weird. *)
239308
if optional && Utils.startsWith name "?" = false then
240-
name ^ "?: "
241-
^ (typ |> Utils.unwrapIfOption |> Shared.typeToString)
242-
^ "\n\n" ^ s
243-
else name ^ ": " ^ (typ |> Shared.typeToString) ^ "\n\n" ^ s
244-
| Constructor (c, s) -> showConstructor c ^ "\n\n" ^ s
245-
| PolyvariantConstructor ({displayName; args}, s) ->
309+
typ |> Utils.unwrapIfOption |> Shared.typeToString
310+
else typ |> Shared.typeToString
311+
| Constructor (c, _) -> showConstructor c
312+
| PolyvariantConstructor ({displayName; args}, _) -> (
246313
"#" ^ displayName
247-
^ (match args with
248-
| [] -> ""
249-
| typeExprs ->
250-
"("
251-
^ (typeExprs
252-
|> List.map (fun typeExpr -> typeExpr |> Shared.typeToString)
253-
|> String.concat ", ")
254-
^ ")")
255-
^ "\n\n" ^ s
314+
^
315+
match args with
316+
| [] -> ""
317+
| typeExprs ->
318+
"("
319+
^ (typeExprs
320+
|> List.map (fun typeExpr -> typeExpr |> Shared.typeToString)
321+
|> String.concat ", ")
322+
^ ")")
256323
| Snippet s -> s
257324
| FollowContextPath _ -> ""
258325
| ExtractedType (extractedType, _) ->
259-
TypeUtils.extractedTypeToString extractedType
326+
TypeUtils.extractedTypeToString ~nameOnly:true extractedType
260327

261328
let findAllCompletions ~(env : QueryEnv.t) ~prefix ~exact ~namesUsed
262329
~(completionContext : Completable.completionContext) =
@@ -366,7 +433,9 @@ let processLocalModule name loc ~prefix ~exact ~env
366433
localTables.resultRev <-
367434
{
368435
(Completion.create declared.name.txt ~env
369-
~kind:(Module declared.item))
436+
~kind:
437+
(Module
438+
{docstring = declared.docstring; module_ = declared.item}))
370439
with
371440
deprecated = declared.deprecated;
372441
docstring = declared.docstring;
@@ -620,7 +689,8 @@ let completionToItem
620689
insertTextFormat;
621690
filterText;
622691
detail;
623-
} =
692+
env;
693+
} ~full =
624694
let item =
625695
mkItem ~name
626696
~kind:(Completion.kindToInt kind)
@@ -629,7 +699,12 @@ let completionToItem
629699
(match detail with
630700
| None -> kindToDetail name kind
631701
| Some detail -> detail)
632-
~docstring
702+
~docstring:
703+
(match
704+
kindToDocumentation ~currentDocstring:docstring ~full ~env name kind
705+
with
706+
| "" -> []
707+
| docstring -> [docstring])
633708
in
634709
{item with sortText; insertText; insertTextFormat; filterText}
635710

analysis/src/SharedTypes.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,7 @@ end
775775

776776
module Completion = struct
777777
type kind =
778-
| Module of Module.t
778+
| Module of {docstring: string list; module_: Module.t}
779779
| Value of Types.type_expr
780780
| ObjLabel of Types.type_expr
781781
| Label of string

analysis/src/TypeUtils.ml

+16-11
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,22 @@ let printRecordFromFields ?name (fields : field list) =
2626
|> String.concat ", ")
2727
^ "}"
2828

29-
let rec extractedTypeToString ?(inner = false) = function
30-
| Tuple (_, _, typ)
31-
| Tpolyvariant {typeExpr = typ}
32-
| Tfunction {typ}
33-
| Trecord {definition = `TypeExpr typ} ->
29+
let rec extractedTypeToString ?(nameOnly = false) ?(inner = false) = function
30+
| Tuple (_, _, typ) | Tpolyvariant {typeExpr = typ} | Tfunction {typ} ->
3431
if inner then
35-
match pathFromTypeExpr typ with
36-
| None -> "record" (* Won't happen *)
37-
| Some p -> p |> SharedTypes.pathIdentToString
32+
try typ |> pathFromTypeExpr |> Option.get |> SharedTypes.pathIdentToString
33+
with _ -> ""
3834
else Shared.typeToString typ
35+
| Trecord {definition; fields} ->
36+
let name =
37+
match definition with
38+
| `TypeExpr typ -> (
39+
try
40+
typ |> pathFromTypeExpr |> Option.get |> SharedTypes.pathIdentToString
41+
with _ -> "")
42+
| `NameOnly name -> name
43+
in
44+
if inner || nameOnly then name else printRecordFromFields ~name fields
3945
| Tbool _ -> "bool"
4046
| Tstring _ -> "string"
4147
| TtypeT _ -> "type t"
@@ -53,9 +59,8 @@ let rec extractedTypeToString ?(inner = false) = function
5359
"option<" ^ extractedTypeToString ~inner:true innerTyp ^ ">"
5460
| Tpromise (_, innerTyp) -> "promise<" ^ Shared.typeToString innerTyp ^ ">"
5561
| Tvariant {variantDecl; variantName} ->
56-
if inner then variantName else Shared.declToString variantName variantDecl
57-
| Trecord {definition = `NameOnly name; fields} ->
58-
if inner then name else printRecordFromFields ~name fields
62+
if inner || nameOnly then variantName
63+
else Shared.declToString variantName variantDecl
5964
| TinlineRecord {fields} -> printRecordFromFields fields
6065
| Texn _ -> "exn"
6166

analysis/tests-incremental-typechecking/src/expected/ConstructorCompletion__Json.res.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ ContextPath CTypeAtPos()
1212
"kind": 12,
1313
"tags": [],
1414
"detail": "t",
15-
"documentation": null,
15+
"documentation": {"kind": "markdown", "value": " The JSON data structure \n\n```rescript\ntype t =\n | Boolean(bool)\n | Null\n | String(string)\n | Number(float)\n | Object(Js.Dict.t<t>)\n | Array(array<t>)\n```"},
1616
"sortText": "A",
1717
"insertText": "[$0]",
1818
"insertTextFormat": 2

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ Path ax
3131
"kind": 12,
3232
"tags": [],
3333
"detail": "Test.t",
34-
"documentation": null
34+
"documentation": {"kind": "markdown", "value": "```rescript\ntype t = {name: int}\n```"}
3535
}]
3636

0 commit comments

Comments
 (0)