Skip to content

feat: make scaladoc/javadoc wiki links navigable in hover and go-to-definition - #8658

Open
jozanek wants to merge 2 commits into
scalameta:mainfrom
jozanek:fix/scaladoc-hover-wiki-links
Open

feat: make scaladoc/javadoc wiki links navigable in hover and go-to-definition#8658
jozanek wants to merge 2 commits into
scalameta:mainfrom
jozanek:fix/scaladoc-hover-wiki-links

Conversation

@jozanek

@jozanek jozanek commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Closes #3383.

Scaladoc and Javadoc entity (wiki) links such as [[scala.Foo]] and {@link Bar} are now navigable instead of rendering as broken links.

Before / After

For /** Returns a [[scala.Predef.String]]. */, hover used to render [String](scala.Predef.String), whose target is a bare fully-qualified name that opens an invalid location, and the link did nothing in the source comment. Now hover renders String as a goto-definition command link (or plain text on clients without command-link support), and clicking it in the source comment navigates to the definition.

Solution

Links are resolved to their definitions, and fall back to plain text when a link is ambiguous or unresolvable or the client lacks command-link support, so a broken link is never shown. Because mtags has no symbol resolver or client config, the work spans two layers. mtags marks each link with a versioned sentinel scheme that carries a structured DocScope (the owner symbol, per-scope import scope, language, source file, and dialect) into the rendered markdown. The server decodes the marker and rewrites each link to a goto command or plain text, and source go-to-definition rebuilds the same context from the syntax tree, so hover and source navigate identically.

What's covered

  • Both Scala [[...]] and Java {@link}, {@linkplain}, and @see (inline and multi-line block) links are supported.
  • Resolution is import-scope-aware and follows Scala's precedence and ambiguity rules, covering explicit, wildcard, renamed, _root_, chained, and backticked-keyword aliases as well as the per-scope enclosing package.
  • Scala 3 specifics are handled, including source-order companions, enum cases, named and anonymous givens, and top-level def/val/type members that live in the synthetic <file>$package owner.
  • Link parsing handles member-owner capping, type-argument stripping (Map[K, V]), and backtick and signature aware target/title splitting.

Known limitations

  • Inherited members are not resolved because the resolver does not walk the type hierarchy, so links like [[List.apply]] or [[Child#inheritedMember]] fall back to plain text.
  • Anonymous Scala 3 givens resolve on hover but not from source, because the synthetic given_<type> symbol cannot be rebuilt from syntax alone.
  • Enclosing-package members are not searched, since they would rank below the implicit scala and java.lang scope, which the flat fallback tiers do not model.

Summary by CodeRabbit

  • New Features

    • Hover and documentation now render symbol links as clickable navigation targets.
    • Added support for resolving links from both Scala and Java doc comments.
    • New “go to doc link” command lets you jump from linked documentation to its definition.
  • Bug Fixes

    • Prevented broken marker text from appearing in hover, signature help, and completion docs.
    • Improved link handling for tricky cases like escaped names, imports, enums, constructors, and ambiguous targets.
    • Documentation links now resolve more reliably across Scala 2, Scala 3, and Java sources.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a marker-based protocol for scaladoc/javadoc entity links so that hover and completion responses no longer leak broken raw links. It adds import-scope-aware link resolution for both Scala and Java, a new goto-scaladoc-link LSP command for navigation, and rewrites hover/completion content to render markers as command links or plain text.

Changes

Scaladoc link resolution and navigation

Layer / File(s) Summary
Wiki-link marker protocol and parsing
mtags/.../docstrings/WikiLink.scala, mtags/.../docstrings/MetalsSymbolLink.scala, mtags/.../docstrings/DocScope.scala, mtags/.../docstrings/ScaladocParser.scala, mtags/.../docstrings/printers/MarkdownGenerator.scala
Adds shared parsing (WikiLink), a URL-safe marker/payload encoding scheme (MetalsSymbolLink), typed DocScope/ImportScope/ImportLevel contracts, and updates markdown link rendering/parsing to use these utilities.
Import scope computation and indexer wiring
mtags/.../ScaladocImportScope.scala, mtags/.../mtags/JavacMtags.scala, mtags/.../JavadocIndexer.scala, mtags/.../ScaladocIndexer.scala, mtags/.../Docstrings.scala
Computes lexical import scopes for Scala and Java, adds onCompilationUnit/onDeclaration hooks to JavacMtags, wires DocScope into rendered Java/Scala docstrings, and updates parent-docstring caching/expiration.
Scaladoc/Javadoc link resolution engine
metals/.../ScaladocDefinitionProvider.scala, metals/.../DefinitionProvider.scala
Reworks link-target resolution with a binding ladder, scope-aware fallback tiers, Java/Scala precedence, and adjusts overall definition strategy ordering including Java-specific ordering and package-symbol fallback handling.
Goto-scaladoc-link command wiring
metals/.../ServerCommands.scala, metals/.../MetalsLspService.scala, metals/.../WorkspaceLspService.scala
Adds GotoScaladocLink command and ScaladocLinkParams, implements resolveScaladocLink, and wires command execution to navigate to a resolved location or show a message.
Hover and completion marker rewriting
metals/.../Compilers.scala
Strips wiki-link markers from completion and signature help documentation, and rewrites hover wiki-links into clickable command links or plain titles via a new RewrittenHover wrapper.
Test decode helpers and test group registration
tests/mtest/.../DocstringMarkers.scala, PCSuite.scala, TestHovers.scala, TestInlayHints.scala, project/TestGroups.scala
Adds a test-only marker decoder used across hover/completion/inlay-hint test rendering, and registers new test suites.
Definition and hover navigation tests
tests/unit/.../DefinitionLspSuite.scala, HoverLspSuite.scala
Adds extensive tests for scaladoc/javadoc link navigation across imports, scopes, Scala 3 ordering/enums, Java interop, and hover command-link rewriting/navigation.
Wiki-link parsing and symbol resolution unit tests
tests/unit/.../JavadocSuite.scala, MarkdownGeneratorSuite.scala, MetalsSymbolLinkSuite.scala, ScaladocSymbolsSuite.scala, WikiLinkSuite.scala
Adds/expands unit tests for marker round-tripping, URL vs symbol classification, and scaladoc symbol candidate generation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Editor
  participant WorkspaceLspService
  participant MetalsLspService
  participant ScaladocDefinitionProvider
  participant DefinitionProvider

  Editor->>WorkspaceLspService: executeCommand(GotoScaladocLink, payload)
  WorkspaceLspService->>MetalsLspService: resolveScaladocLink(params)
  MetalsLspService->>MetalsLspService: parsePayload / build DocScope context
  MetalsLspService->>ScaladocDefinitionProvider: resolveLinkLocations(isJava, knownDocstringFile)
  ScaladocDefinitionProvider->>DefinitionProvider: resolveSymbol / fromSymbol
  DefinitionProvider-->>ScaladocDefinitionProvider: candidate locations
  ScaladocDefinitionProvider-->>MetalsLspService: Resolved / NotUnique / Failed
  MetalsLspService-->>WorkspaceLspService: ScaladocLinkResolution
  alt Resolved
    WorkspaceLspService->>Editor: GotoLocation
  else NotUnique or Failed
    WorkspaceLspService->>Editor: show message
  end
Loading
sequenceDiagram
  participant Editor
  participant Compilers
  participant PresentationCompiler
  participant MetalsSymbolLink

  Editor->>Compilers: textDocument/hover
  Compilers->>PresentationCompiler: hover(params)
  PresentationCompiler-->>Compilers: raw hover markup with markers
  Compilers->>MetalsSymbolLink: parsePayload for each marker
  Compilers->>Compilers: rewriteHoverWikiLinks(commandInHtmlFormat?)
  alt command links enabled
    Compilers-->>Editor: hover with command:metals.goto-scaladoc-link links
  else plaintext fallback
    Compilers-->>Editor: hover with plain titles
  end
Loading

Possibly related PRs

  • scalameta/metals#7751: Both PRs modify the LSP definition-resolution flow, notably DefinitionProvider.definition, overlapping in the strategy-ordering logic.
  • scalameta/metals#8357: The javac-based Java indexing/Javadoc parsing refactor (JavacMtags, JavadocIndexer) underlies the updated Javadoc rendering pipeline this PR depends on.

Suggested reviewers: tgodzik

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: making Scaladoc/Javadoc wiki links navigable in hover and go-to-definition.
Linked Issues check ✅ Passed The PR addresses #3383 by rewriting broken hover wiki links into navigable editor commands and adds matching source-definition resolution.
Out of Scope Changes check ✅ Passed The changes stay focused on wiki-link rendering, resolution, and related tests; no unrelated code areas appear to be modified.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
metals/src/main/scala/scala/meta/internal/metals/Compilers.scala (1)

1235-1266: 🚀 Performance & Scalability | 🔵 Trivial

Hover markup is rendered twice per request (toLsp() called in both the detection path and RewrittenHover.toLsp()).

rewriteHoverWikiLinks's non-ScalaHover branch calls hover.toLsp() just to peek at the contents, then wraps the result in RewrittenHover, whose own toLsp() calls underlying.toLsp() again when the client later renders the hover. If toLsp() does non-trivial markdown generation, that's a redundant computation on every out-of-process hover. Not incorrect, just wasteful; consider caching the first Hover result inside RewrittenHover instead of recomputing.

Also applies to: 2034-2056

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@metals/src/main/scala/scala/meta/internal/metals/Compilers.scala` around
lines 1235 - 1266, The non-ScalaHover path in rewriteHoverWikiLinks is
recomputing hover markup by calling hover.toLsp() for detection and then again
later through RewrittenHover.toLsp(). Update Compilers.RewrittenHover (and its
use in rewriteHoverWikiLinks) to cache the first LSP Hover/contents result so
the rewritten hover can reuse it instead of regenerating markdown on every
render.
tests/unit/src/test/scala/tests/HoverLspSuite.scala (3)

860-866: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Misplaced/orphaned comment.

This comment block ("A Java wildcard import... resolves to a.b.Helper") describes wiki-link-navigate-java-wildcard-import (line 979), not the wiki-link-scheme-in-label test it actually precedes. Looks like it was left behind when the tests were reordered. Move it above the correct test to avoid confusing future readers.

✏️ Suggested fix
-  // A Java wildcard import (`import a.b.*;`) qualifies a relative Javadoc link
-  // via its prefix, so `{`@link` Helper}` resolves to `a.b.Helper`
-  // (scalameta/metals#3383).
   // A docstring whose link label itself contains the marker scheme (an escaped
   // `](metals-wiki-link2:…)`) must not crash hover/completion rendering — it
   // degrades gracefully instead (scalameta/metals#3383).
   test("wiki-link-scheme-in-label".tag(FlakyWindows)) {

and then, before test("wiki-link-navigate-java-wildcard-import"...):

+  // A Java wildcard import (`import a.b.*;`) qualifies a relative Javadoc link
+  // via its prefix, so `{`@link` Helper}` resolves to `a.b.Helper`
+  // (scalameta/metals#3383).
   test("wiki-link-navigate-java-wildcard-import".tag(FlakyWindows)) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/src/test/scala/tests/HoverLspSuite.scala` around lines 860 - 866,
The wildcard-import comment is attached to the wrong test and should be moved to
the matching `wiki-link-navigate-java-wildcard-import` case instead of
`wiki-link-scheme-in-label`. Relocate the comment block so it sits directly
above the `test("wiki-link-navigate-java-wildcard-import"...` in
`HoverLspSuite`, keeping the existing `wiki-link-scheme-in-label` test only with
its own relevant comment.

1085-1120: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Ambiguity tests don't consistently verify the "Could not uniquely resolve" message.

clickFirstLink returns None both when the rendered hover has no command link at all and when the command executes but resolution is genuinely ambiguous — these tests only assert uri.isEmpty, so they can't distinguish the two. Other tests in this same suite covering the same category of scenario (e.g. wiki-link-java-duplicate-static-import, wiki-link-overload-no-navigation, wiki-link-no-companion-navigation, wiki-link-ambiguous-no-navigation) do additionally assert on client.showMessages containing "Could not uniquely resolve". Applying the same assertion here would make these tests actually validate that ambiguity was detected and reported, rather than merely that navigation didn't happen.

Also applies to: 1350-1387, 2118-2146, 2810-2847, 2896-2940

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/src/test/scala/tests/HoverLspSuite.scala` around lines 1085 -
1120, The ambiguity hover/navigation test only checks that clickFirstLink
returns no URI, so it does not verify that the failure was actually reported as
an ambiguous resolution. Update the affected HoverLspSuite tests, including
wiki-link-ambiguous-wildcard-no-navigation and the other similar ambiguous
cases, to also assert that client.showMessages contains the “Could not uniquely
resolve” message after the hover link interaction, matching the pattern already
used by wiki-link-java-duplicate-static-import,
wiki-link-overload-no-navigation, and related tests.

3055-3081: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Same weak-assertion gap as DefinitionLspSuite's enum-case-param test.

The comment states this verifies [[r]] resolves to the case parameter rather than falling through to the enum's companion, but the assertion only checks the file suffix (/a/Color.scala), not the resolved line — both the case and any companion fallback would live in files ending the same way in this setup. Consider asserting the specific line/range to actually catch a regression toward the enum companion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/src/test/scala/tests/HoverLspSuite.scala` around lines 3055 -
3081, The test in HoverLspSuite for wiki-link-navigate-enum-case-param is too
weak because it only checks that clickFirstLink returns a URI ending in
Color.scala, which would also pass if the link incorrectly resolved to the enum
companion. Strengthen the assertion by checking the exact target location or
range returned by clickFirstLink, using the existing test setup around
Color.scala and Main.scala to verify the wiki link resolves to the case
parameter r rather than just any symbol in the same file.
tests/unit/src/test/scala/tests/DefinitionLspSuite.scala (1)

813-842: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test doesn't verify the claimed CASE-vs-ENUM distinction.

The comment states this test confirms [[r]] resolves against the case Mix, not the enclosing enum E, but both live in the same file (E.scala), and the assertion only checks the URI suffix, not the resolved line/range. A regression that resolves to the enum itself instead of the case parameter would still pass this test. Consider asserting locations.head.getRange().getStart().getLine() (or similar), the way the sibling scaladoc-definition-scala3-source-order and scaladoc-definition-scala3-toplevel-member tests already do.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/src/test/scala/tests/DefinitionLspSuite.scala` around lines 813 -
842, The scaladoc definition test only checks that the result is in the same
file, so it does not actually verify that `[[r]]` resolves to the enum case
parameter rather than the enclosing enum. Update the
`scaladoc-definition-enum-case-param` test in `DefinitionLspSuite` to assert the
returned location’s range/line matches the `case Mix(r: Int)` parameter target,
using the same pattern as the nearby `scaladoc-definition-scala3-source-order`
and `scaladoc-definition-scala3-toplevel-member` tests.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mtags/src/main/scala/scala/meta/internal/metals/docstrings/WikiLink.scala`:
- Around line 41-53: The Scaladoc for the bracket-link offset behavior is
attached to the wrong helper: the comment above javadocAtOffset describes the
atOffset behavior instead. Move that documentation block so it sits with
atOffset, and keep javadocAtOffset’s own inline-link doc in place; use the
atOffset and javadocAtOffset symbols to relocate the orphaned comment cleanly.

---

Nitpick comments:
In `@metals/src/main/scala/scala/meta/internal/metals/Compilers.scala`:
- Around line 1235-1266: The non-ScalaHover path in rewriteHoverWikiLinks is
recomputing hover markup by calling hover.toLsp() for detection and then again
later through RewrittenHover.toLsp(). Update Compilers.RewrittenHover (and its
use in rewriteHoverWikiLinks) to cache the first LSP Hover/contents result so
the rewritten hover can reuse it instead of regenerating markdown on every
render.

In `@tests/unit/src/test/scala/tests/DefinitionLspSuite.scala`:
- Around line 813-842: The scaladoc definition test only checks that the result
is in the same file, so it does not actually verify that `[[r]]` resolves to the
enum case parameter rather than the enclosing enum. Update the
`scaladoc-definition-enum-case-param` test in `DefinitionLspSuite` to assert the
returned location’s range/line matches the `case Mix(r: Int)` parameter target,
using the same pattern as the nearby `scaladoc-definition-scala3-source-order`
and `scaladoc-definition-scala3-toplevel-member` tests.

In `@tests/unit/src/test/scala/tests/HoverLspSuite.scala`:
- Around line 860-866: The wildcard-import comment is attached to the wrong test
and should be moved to the matching `wiki-link-navigate-java-wildcard-import`
case instead of `wiki-link-scheme-in-label`. Relocate the comment block so it
sits directly above the `test("wiki-link-navigate-java-wildcard-import"...` in
`HoverLspSuite`, keeping the existing `wiki-link-scheme-in-label` test only with
its own relevant comment.
- Around line 1085-1120: The ambiguity hover/navigation test only checks that
clickFirstLink returns no URI, so it does not verify that the failure was
actually reported as an ambiguous resolution. Update the affected HoverLspSuite
tests, including wiki-link-ambiguous-wildcard-no-navigation and the other
similar ambiguous cases, to also assert that client.showMessages contains the
“Could not uniquely resolve” message after the hover link interaction, matching
the pattern already used by wiki-link-java-duplicate-static-import,
wiki-link-overload-no-navigation, and related tests.
- Around line 3055-3081: The test in HoverLspSuite for
wiki-link-navigate-enum-case-param is too weak because it only checks that
clickFirstLink returns a URI ending in Color.scala, which would also pass if the
link incorrectly resolved to the enum companion. Strengthen the assertion by
checking the exact target location or range returned by clickFirstLink, using
the existing test setup around Color.scala and Main.scala to verify the wiki
link resolves to the case parameter r rather than just any symbol in the same
file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0c941f7c-7aad-4c09-90c8-e0145ebd2389

📥 Commits

Reviewing files that changed from the base of the PR and between 96f539c and 1ab96b0.

📒 Files selected for processing (28)
  • metals/src/main/scala/scala/meta/internal/metals/Compilers.scala
  • metals/src/main/scala/scala/meta/internal/metals/DefinitionProvider.scala
  • metals/src/main/scala/scala/meta/internal/metals/MetalsLspService.scala
  • metals/src/main/scala/scala/meta/internal/metals/ScaladocDefinitionProvider.scala
  • metals/src/main/scala/scala/meta/internal/metals/ServerCommands.scala
  • metals/src/main/scala/scala/meta/internal/metals/WorkspaceLspService.scala
  • mtags/src/main/scala/scala/meta/internal/metals/Docstrings.scala
  • mtags/src/main/scala/scala/meta/internal/metals/JavadocIndexer.scala
  • mtags/src/main/scala/scala/meta/internal/metals/ScaladocImportScope.scala
  • mtags/src/main/scala/scala/meta/internal/metals/ScaladocIndexer.scala
  • mtags/src/main/scala/scala/meta/internal/metals/docstrings/DocScope.scala
  • mtags/src/main/scala/scala/meta/internal/metals/docstrings/MetalsSymbolLink.scala
  • mtags/src/main/scala/scala/meta/internal/metals/docstrings/ScaladocParser.scala
  • mtags/src/main/scala/scala/meta/internal/metals/docstrings/WikiLink.scala
  • mtags/src/main/scala/scala/meta/internal/metals/docstrings/printers/MarkdownGenerator.scala
  • mtags/src/main/scala/scala/meta/internal/mtags/JavacMtags.scala
  • project/TestGroups.scala
  • tests/mtest/src/main/scala/tests/DocstringMarkers.scala
  • tests/mtest/src/main/scala/tests/PCSuite.scala
  • tests/mtest/src/main/scala/tests/TestHovers.scala
  • tests/mtest/src/main/scala/tests/TestInlayHints.scala
  • tests/unit/src/test/scala/tests/DefinitionLspSuite.scala
  • tests/unit/src/test/scala/tests/HoverLspSuite.scala
  • tests/unit/src/test/scala/tests/JavadocSuite.scala
  • tests/unit/src/test/scala/tests/MarkdownGeneratorSuite.scala
  • tests/unit/src/test/scala/tests/MetalsSymbolLinkSuite.scala
  • tests/unit/src/test/scala/tests/ScaladocSymbolsSuite.scala
  • tests/unit/src/test/scala/tests/WikiLinkSuite.scala

Comment on lines +41 to +53
/**
* The target of the entity link whose brackets (`[[ ... ]]`, or any `n >= 2`
* matching brackets, mirroring the renderer) enclose `offset`, so source
* go-to-definition navigates exactly the links the renderer makes clickable
* (scalameta/metals#3383).
*/
/**
* The target of the Javadoc inline link (`{@link ... }` / `{@linkplain ... }`)
* whose braces enclose `offset`, matching what the renderer extracts so source
* clicks navigate the same links. The first token is the target; the rest is
* the label (scalameta/metals#3383).
*/
def javadocAtOffset(text: String, offset: Int): Option[String] = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Orphaned Scaladoc comment — belongs to atOffset.

The block at Lines 41-46 documents the [[ ... ]] bracket-link-at-offset behavior, which is atOffset (Line 157), but it sits above javadocAtOffset (which already has its own doc at Lines 47-52). Meanwhile atOffset at Line 157 has no documentation. This reads as a copy/move artifact and misleads readers of this public helper.

Move the Lines 41-46 block above atOffset.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mtags/src/main/scala/scala/meta/internal/metals/docstrings/WikiLink.scala`
around lines 41 - 53, The Scaladoc for the bracket-link offset behavior is
attached to the wrong helper: the comment above javadocAtOffset describes the
atOffset behavior instead. Move that documentation block so it sits with
atOffset, and keep javadocAtOffset’s own inline-link doc in place; use the
atOffset and javadocAtOffset symbols to relocate the orphaned comment cleanly.

@jozanek

jozanek commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Hey @tgodzik 👋 If you were wondering where I vanished to for the last three weeks, this was it. 😄

Sorry about the size of the diff. It started as a small "make the broken hover wiki links clickable" change. Then it turned into a never-ending story of fixes. Every edge case I closed uncovered a couple more (renamed / _root_ / chained / backticked-keyword aliases, per-scope packages, Scala 3 source order, enum cases, named and anonymous givens, top-level defs in <file>$package, type-argument links, @see block tags). It did stop eventually. Probably.

Happy to split it into smaller PRs or walk you through any part if that makes review easier. 🙏

@tgodzik

tgodzik commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Happy to split it into smaller PRs or walk you through any part if that makes review easier.

That would be quite welcome, this is a bit terrifying to review 😅 Do you have any fixes unrelated to the current PR we could split?

@tgodzik

tgodzik commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

I was thinking about this feature previously and I hoped we could just make the links become go to definition links for VS Code and handle it with the current scaladoc definitions (these might need some fixes). For anything aside from VS Code I would probably just escape them.

Sublime I think also has some link syntax we could use.

* `Resolved`; a miss or ambiguous/overloaded link is `NotUnique`; an
* unexpected (logged) error is `Failed` (scalameta/metals#3383).
*/
def resolveScaladocLink(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

tgodzik pushed a commit that referenced this pull request Jul 21, 2026
…#8676)

First part of #8658, paritally fixing #3383

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved Scaladoc and Javadoc link parsing, including links with
custom titles, nested brackets, signatures, and backticked names.
* Fixed navigation so links resolve to their actual target symbols
rather than displayed titles.
* Correctly renders quoted `@see` text as plain text instead of a link.

* **Tests**
* Added coverage for complex link formats, offset detection, and
definition navigation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
tgodzik pushed a commit to tgodzik/metals that referenced this pull request Jul 30, 2026
…scalameta#8676)

First part of scalameta#8658, paritally fixing scalameta#3383

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

* **Bug Fixes**
* Improved Scaladoc and Javadoc link parsing, including links with
custom titles, nested brackets, signatures, and backticked names.
* Fixed navigation so links resolve to their actual target symbols
rather than displayed titles.
* Correctly renders quoted `@see` text as plain text instead of a link.

* **Tests**
* Added coverage for complex link formats, offset detection, and
definition navigation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

(cherry picked from commit cb485be)
tgodzik pushed a commit to tgodzik/metals that referenced this pull request Jul 31, 2026
…scalameta#8676)

First part of scalameta#8658, paritally fixing scalameta#3383

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

* **Bug Fixes**
* Improved Scaladoc and Javadoc link parsing, including links with
custom titles, nested brackets, signatures, and backticked names.
* Fixed navigation so links resolve to their actual target symbols
rather than displayed titles.
* Correctly renders quoted `@see` text as plain text instead of a link.

* **Tests**
* Added coverage for complex link formats, offset detection, and
definition navigation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

(cherry picked from commit cb485be)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invalid scaladoc links in hover response

2 participants