Skip to content

feat: add hls-document-link-plugin to support LSP document links#4898

Open
jetjinser wants to merge 5 commits intohaskell:masterfrom
jetjinser:documentLink
Open

feat: add hls-document-link-plugin to support LSP document links#4898
jetjinser wants to merge 5 commits intohaskell:masterfrom
jetjinser:documentLink

Conversation

@jetjinser
Copy link
Copy Markdown
Contributor

This PR introduces a new plugin hls-document-link-plugin that adds LSP documentLink support to Haskell Language Server.

This plugin automatically extracts documentation links for symbols in source code. These links are the same ones that power the [Documentation] link in the hover information.

Changes

  • New plugin: hls-document-link-plugin – extracts clickable links and provides them as document links. Editors can then open these links directly from the source code.
  • Configuration: Added documentLinkOn option to enable/disable the feature (default: True).

Usage

In Neovim 0.12 or later, you can place the cursor on the link and press gx to open it directly in your default browser.

The feature can be turned off by setting documentLinkOn: false in the HLS configuration.


Note. The getDocumentLinks helper for lsp-test is implemented manually here, but a same change is also pending in haskell/lsp#638. After that PR is merged and the dependency is updated, this part can be simplified.

@jetjinser jetjinser changed the title feat: ddd hls-document-link-plugin to support LSP document links feat: add hls-document-link-plugin to support LSP document links Apr 18, 2026
Copy link
Copy Markdown
Collaborator

@fendor fendor left a comment

Choose a reason for hiding this comment

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

Welcome back and happy to see you tackle this issue!

This looks pretty good to my cursory review. I have mostly nitpicks and a couple of clarification questions.
Other than that, LGTM :)

Comment on lines +28 to +32
[ (SimilarDocumentLink
(DocumentLink (Range (Position 0 10) (Position 0 13))
(Just (Uri "GHC-Types.html#t:Int"))
Nothing
Nothing)),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These could most likely benefit from some helpers. E.g.,:

Suggested change
[ (SimilarDocumentLink
(DocumentLink (Range (Position 0 10) (Position 0 13))
(Just (Uri "GHC-Types.html#t:Int"))
Nothing
Nothing)),
[ (SimilarDocumentLink (mkDocLink (mkRange 0 10 0 13) (Uri "GHC-Types.html#t:Int")),

Just a suggestion, feel free to ignore

Comment on lines +68 to +69
goldenTest :: TestName -> FilePath -> [SimilarDocumentLink] -> TestTree
goldenTest title file expected = testCase title $ runWithDocumentLink filehs $ do
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not a golden test, right?

Comment on lines +98 to +99
-- custom Eq to ignore some details, such as specific URI
-- not symmetry
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- custom Eq to ignore some details, such as specific URI
-- not symmetry
-- Custom Eq to ignore some details, such as specific URI.
-- This is not a lawful instance as it doesn't obey the `symmetry` law. Use at your own risk and only in tests.

Comment on lines +1 to +2
import Data.Maybe (fromJust, fromMaybe)
f = (fromJust, fromMaybe)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Would this also work with constructors? E.g., Just or Nothing

Comment on lines +61 to +63
pretty = \case {
LogShake shakeLog -> pretty shakeLog
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
pretty = \case {
LogShake shakeLog -> pretty shakeLog
}
pretty = \case
LogShake shakeLog -> pretty shakeLog

defineNoDiagnostics (cmapWithPrio LogShake recorder) $ \GetDocumentLinks nfp -> runMaybeT $ do
HAR {hieAst} <- useMT GetHieAst nfp
DKMap {getDocMap} <- useMT GetDocMap nfp
ast <- hoistMaybe $ getAsts hieAst Map.!? (HiePath . mkFastString . fromNormalizedFilePath) nfp
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
ast <- hoistMaybe $ getAsts hieAst Map.!? (HiePath . mkFastString . fromNormalizedFilePath) nfp
ast <- hoistMaybe $ getAsts hieAst Map.!? HiePath (mkFastString $ fromNormalizedFilePath nfp)

Just weird bracketing for my taste, feel free to ignore.

pure $ DocumentLinks (foldAst lookup ast)

foldAst :: forall a t. Monoid a => ((Identifier, Span) -> a) -> HieAST t -> a
foldAst lookup ast = case (nodeChildren ast) of
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
foldAst lookup ast = case (nodeChildren ast) of
foldAst lookup ast = case nodeChildren ast of

Comment on lines +108 to +109
foldAst :: forall a t. Monoid a => ((Identifier, Span) -> a) -> HieAST t -> a
foldAst lookup ast = case (nodeChildren ast) of
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Some docs would be nice, what is this folding over?

@fendor
Copy link
Copy Markdown
Collaborator

fendor commented Apr 18, 2026

Also, I am wondering whether this has any overlap with #4746 and the Documentation and Source links in the hover message?

@fendor
Copy link
Copy Markdown
Collaborator

fendor commented Apr 18, 2026

Screencast_20260418_150352.webm

This is the behaviour on vscode... I suppose that's not the expected behaviour?

@fendor fendor added the status: needs review This PR is ready for review label Apr 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: needs review This PR is ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants