Skip to content

Comments

[ty] Add hyperlinks to rule codes in CLI#21502

Merged
MichaReiser merged 2 commits intomainfrom
micha/error-links
Nov 18, 2025
Merged

[ty] Add hyperlinks to rule codes in CLI#21502
MichaReiser merged 2 commits intomainfrom
micha/error-links

Conversation

@MichaReiser
Copy link
Member

@MichaReiser MichaReiser commented Nov 17, 2025

Summary

This PR adds hyperlink rendering to our diagnostics so that users can jump to the rule documentation by clicking on the diagnostic id.

My first implementation added an optional url_resolver: &dyn Fn(&DiagnosticId) -> Option<String> argument to the full and concise rendering. The main idea was to avoid constructing the URLs unnecessarily when the output format doesn't need the URL.

However, I then realised that the LSP always uses the URL and we have other output formats (ruff only for now) that construct the URL too, namely the JSON and rdjson output formats. The overhead also seems negligible compared to that we always construct the full diagnostic, even when only using the concise output format. That's why I opted to store the URL as an optional field on the diagnostic instead. Not only did it simplify the implementation, it also reduced some code duplication.

The main advantage of this approach is that it requires some amount of code duplication to set the URL on the diagnostic.

It should be very easy to leverage this functionality in Ruff too (@ntBre if you're interested).

Test Plan

Screen.Recording.2025-11-18.at.09.14.16.mov

@MichaReiser MichaReiser added ty Multi-file analysis & type inference diagnostics Related to reporting of diagnostics. labels Nov 17, 2025
use std::ops::Range;

#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub(crate) struct Id<'a> {
Copy link
Member Author

Choose a reason for hiding this comment

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

This type is inspired by the new annotate snippet that also has an Id type

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 17, 2025

Diagnostic diff on typing conformance tests

No changes detected when running ty on typing conformance tests ✅

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 17, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

@astral-sh-bot
Copy link

astral-sh-bot bot commented Nov 18, 2025

ecosystem-analyzer results

No diagnostic changes detected ✅
Full report with detailed diff (timing results)

@MichaReiser MichaReiser changed the title [ty] Render links for rule codes [ty] Add hyperlinks to rule codes in CLI Nov 18, 2025
@AlexWaygood
Copy link
Member

Interesting that mypy_primer timed out but ecosystem-analyzer didn't find any changes to report (primer timeouts usually occur because it took too long trying to compute the diff between the two runs)

@MichaReiser
Copy link
Member Author

mypy primer timing out makes sense, given that it forces color output (every diagnostic has now a different output)

@MichaReiser
Copy link
Member Author

MichaReiser commented Nov 18, 2025

There's an argument that it's hard to notice that the id is clickable. We could decide to underline the id or add the URL as a note (similar to what we do with the rule status). This would have the benefit that we could render the URL as a string and it's up to the CLI to add the hyperlink. The downside of this is that it only works for the full output and not concise.

I'm also not a 100% sure if we need to restrict the hyperlink rendering to more cases, e.g. by using https://docs.rs/supports-hyperlinks/latest/src/supports_hyperlinks/lib.rs.html#12-53

Copy link
Member

@BurntSushi BurntSushi left a comment

Choose a reason for hiding this comment

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

Love it! Nice work. This all LGTM. I agree that the overhead here is likely negligible, and so preferring API simplicity is the right call.

There's an argument that it's hard to notice that the id is clickable. We could decide to underline the id or add the URL as a note (similar to what we do with the rule status). This would have the benefit that we could render the URL as a string and it's up to the CLI to add the hyperlink. The downside of this is that it only works for the full output and not concise.

I like the underline.

I'm also not a 100% sure if we need to restrict the hyperlink rendering to more cases, e.g. by using https://docs.rs/supports-hyperlinks/latest/src/supports_hyperlinks/lib.rs.html#12-53

I'd be fine with doing this reactively, i.e., in response to user feedback.

We could also choose to add a note containing the actual URL if and only if we decide not to render the hyperlink (based on supports-hyperlink).

But I'm fine shipping this as-is and iterating. :-)

@AlexWaygood
Copy link
Member

AlexWaygood commented Nov 18, 2025

CMD+clicking on the rule code works on this branch for me in a terminal inside VSCode, but not in the Terminal app on my macbook -- any idea why? (Is this just a case of "Alex, start using iTerm2 or something instead of the default Terminal app that your macbook came with"?)

Adding the full URL as a note might resolve this, since I'm definitely able to CMD+click on full URL in a terminal (I do this all the time to open local playground deploys in a browser straight from my terminal, obviously 😄)

@MichaReiser
Copy link
Member Author

CMD+clicking on the rule code works on this branch for me in a terminal inside VSCode, but not in the Terminal app on my macbook -- any idea why? (Is this just a case of "Alex, start using iTerm2 or something instead of the default Terminal app that your macbook came with"?)

I couldn't find a reference but yes, this is the behavior of terminals supporting the ANSI escape but not supporting the hyperlink feature.

@MichaReiser
Copy link
Member Author

I actually like the current behavior where Ghostty only renders the underline when I hit Cmd and hover the id. This makes it behave the same as other clickable links

@MichaReiser MichaReiser merged commit 7043d51 into main Nov 18, 2025
40 of 41 checks passed
@MichaReiser MichaReiser deleted the micha/error-links branch November 18, 2025 15:37
ntBre added a commit that referenced this pull request Nov 18, 2025
Summary
--

This PR wires up the `Diagnostic::set_documentation_url` method from #21502 to
Ruff's lint diagnostics and renders them in the grouped output format (concise
and full are already covered by #21502).

I considered also including the URLs for the pylint output format, but it
doesn't currently render any color in the CLI, so it may be a machine-readable
format too?

Test Plan
--
ntBre added a commit that referenced this pull request Nov 18, 2025
Summary
--

This PR wires up the `Diagnostic::set_documentation_url` method from
#21502 to Ruff's lint diagnostics. This enables the links for the full
and concise output formats without any other changes.

I considered also including the URLs for the grouped and pylint output
formats, but the grouped format is still in `ruff_linter` instead of
`ruff_db`, so we'd have to export some additional functionality to wire
it up with `fmt_with_hyperlink`; and the pylint format doesn't currently
render with color, so I think it might actually be machine readable
rather than human readable?

The other ouput formats (json, json-lines, junit, github, gitlab,
rdjson, azure, sarif) seem more clearly not to need the links.

Test Plan
--

I guess you can't see my cursor or the browser opening, but it works for
lint rules, which have links, and doesn't include a link for syntax
errors, which don't have valid links.


![out](https://github.com/user-attachments/assets/a520c7f9-6d7b-4e5f-a1a9-3c5e21a51d3c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

diagnostics Related to reporting of diagnostics. ecosystem-analyzer ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants