Skip to content

Show doc comments before type expansions in hover information #7774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#### :rocket: New Feature

- Show docstrings before type expansions on hover. https://github.com/rescript-lang/rescript/pull/7774

#### :bug: Bug fix

#### :memo: Documentation
Expand Down
43 changes: 22 additions & 21 deletions analysis/src/Hover.ml
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ let expandTypes ~file ~package ~supportsMarkdownLinks typ =
`Default )

(* Produces a hover with relevant types expanded in the main type being hovered. *)
let hoverWithExpandedTypes ~file ~package ~supportsMarkdownLinks ?constructor
typ =
let hoverWithExpandedTypes ~file ~package ~supportsMarkdownLinks ?docstring
?constructor typ =
let expandedTypes, expansionType =
expandTypes ~file ~package ~supportsMarkdownLinks typ
in
Expand All @@ -164,7 +164,15 @@ let hoverWithExpandedTypes ~file ~package ~supportsMarkdownLinks ?constructor
typeString ^ "\n" ^ CompletionBackEnd.showConstructor constructor
| None -> typeString
in
Markdown.codeBlock typeString :: expandedTypes |> String.concat "\n"
let typeString =
match docstring with
| Some [] | None -> Markdown.codeBlock typeString
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The pattern Some [] suggests that an empty docstring list should be treated the same as no docstring. Consider using a helper function or guard clause to make this logic clearer, as the pattern matching combines two conceptually different cases.

Suggested change
| Some [] | None -> Markdown.codeBlock typeString
let is_empty_docstring = function
| None | Some [] -> true
| Some _ -> false
in
match docstring with
| d when is_empty_docstring d -> Markdown.codeBlock typeString

Copilot uses AI. Check for mistakes.

| Some docstring ->
Markdown.codeBlock typeString
^ Markdown.divider
^ (docstring |> String.concat "\n")
in
typeString :: expandedTypes |> String.concat "\n"
| `InlineType -> expandedTypes |> String.concat "\n"

(* Leverages autocomplete functionality to produce a hover for a position. This
Expand All @@ -191,10 +199,10 @@ let getHoverViaCompletions ~debug ~path ~pos ~currentFile ~forHover
with
| Some (typ, _env) ->
let typeString =
hoverWithExpandedTypes ~file ~package ~supportsMarkdownLinks typ
hoverWithExpandedTypes ~file ~package ~docstring
~supportsMarkdownLinks typ
in
let parts = docstring @ [typeString] in
Some (Protocol.stringifyHover (String.concat "\n\n" parts))
Some (Protocol.stringifyHover typeString)
| None -> None)
| {env} :: _ -> (
let opens = CompletionBackEnd.getOpens ~debug ~rawOpens ~package ~env in
Expand Down Expand Up @@ -277,22 +285,15 @@ let newHover ~full:{file; package} ~supportsMarkdownLinks locItem =
| Const_int64 _ -> "int64"
| Const_bigint _ -> "bigint"))
| Typed (_, t, locKind) ->
let fromType ?constructor typ =
hoverWithExpandedTypes ~file ~package ~supportsMarkdownLinks ?constructor
typ
let fromType ?docstring ?constructor typ =
hoverWithExpandedTypes ~file ~package ~supportsMarkdownLinks ?docstring
?constructor typ
in
let parts =
match References.definedForLoc ~file ~package locKind with
| None ->
let typeString = t |> fromType in
[typeString]
Some
(match References.definedForLoc ~file ~package locKind with
| None -> t |> fromType
| Some (docstring, res) -> (
match res with
| `Declared | `Field ->
let typeString = t |> fromType in
typeString :: docstring
| `Declared | `Field -> t |> fromType ~docstring
| `Constructor constructor ->
let typeString = t |> fromType ~constructor in
typeString :: constructor.docstring)
in
Some (String.concat Markdown.divider parts)
t |> fromType ~docstring:constructor.docstring ~constructor))
4 changes: 2 additions & 2 deletions tests/analysis_tests/tests/src/expected/Hover.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,13 @@ Path Hover.someField
Path someField
Package opens Stdlib.place holder Pervasives.JsxModules.place holder
Resolved opens 1 Stdlib
{"contents": {"kind": "markdown", "value": " Mighty fine field here. \n\n```rescript\nbool\n```"}}
{"contents": {"kind": "markdown", "value": "```rescript\nbool\n```\n---\n Mighty fine field here. "}}

Hover src/Hover.res 248:19
{"contents": {"kind": "markdown", "value": "```rescript\nbool\n```\n---\n Mighty fine field here. "}}

Hover src/Hover.res 253:20
{"contents": {"kind": "markdown", "value": "```rescript\nvariant\nCoolVariant\n```\n\n---\n\n```\n \n```\n```rescript\ntype variant = CoolVariant | OtherCoolVariant\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C251%2C0%5D)\n\n---\n Cool variant! "}}
{"contents": {"kind": "markdown", "value": "```rescript\nvariant\nCoolVariant\n```\n---\n Cool variant! \n\n---\n\n```\n \n```\n```rescript\ntype variant = CoolVariant | OtherCoolVariant\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C251%2C0%5D)\n"}}

Hover src/Hover.res 258:22
{"contents": {"kind": "markdown", "value": "```rescript\npayloadVariants\nInlineRecord({field1: int, field2: bool})\n```\n\n---\n\n```\n \n```\n```rescript\ntype payloadVariants =\n | InlineRecord({field1: int, field2: bool})\n | Args(int, bool)\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22Hover.res%22%2C256%2C0%5D)\n"}}
Expand Down
2 changes: 1 addition & 1 deletion tests/analysis_tests/tests/src/expected/JsxV4.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Path M4.make
}]

Hover src/JsxV4.res 14:9
{"contents": {"kind": "markdown", "value": "```rescript\nReact.component<M4.props<string, string, string>>\n```\n\n---\n\n```\n \n```\n```rescript\ntype React.component<'props> = Jsx.component<'props>\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C12%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype M4.props<'first, 'fun, 'second> = {\n first: 'first,\n fun?: 'fun,\n second?: 'second,\n}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxV4.res%22%2C3%2C2%5D)\n\n---\n Doc Comment For M4 "}}
{"contents": {"kind": "markdown", "value": "```rescript\nReact.component<M4.props<string, string, string>>\n```\n---\n Doc Comment For M4 \n\n---\n\n```\n \n```\n```rescript\ntype React.component<'props> = Jsx.component<'props>\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22React.res%22%2C12%2C0%5D)\n\n\n---\n\n```\n \n```\n```rescript\ntype M4.props<'first, 'fun, 'second> = {\n first: 'first,\n fun?: 'fun,\n second?: 'second,\n}\n```\nGo to: [Type definition](command:rescript-vscode.go_to_location?%5B%22JsxV4.res%22%2C3%2C2%5D)\n"}}

Create Interface src/JsxV4.res
module M4: {
Expand Down
Loading