Skip to content

Commit

Permalink
RFC for rustdoc jump to definition
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed May 12, 2022
1 parent 69833de commit 9907e9f
Showing 1 changed file with 144 additions and 0 deletions.
144 changes: 144 additions & 0 deletions text/000-rustdoc-jump-to-definition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
Rustdoc: jump to definition

- Feature Name: `jump_to_definition`
- Start Date: 2021-12-09
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
- Rust Issue: [rust-lang/rust#89095](https://github.com/rust-lang/rust/issues/89095)

# Summary
[summary]: #summary

Generate links on idents in the rustdoc source code pages which links to the item's definition and documentation (if available).

# Motivation
[motivation]: #motivation

Since a video is worth a thousand words:

https://user-images.githubusercontent.com/3050060/114622354-21307b00-9cae-11eb-834d-f6d8178a37bd.mp4

And now with words:

We take as given that "source view" is a valuable part of rustdoc. Sometimes, it's necessary to go beyond the documentation and look at the implementation. That's why source view is a common feature in documentation tooling for a variety of languages (like Go for example, you can access this [source code](https://cs.opensource.google/go/go/+/go1.16.5:src/database/sql/sql.go;l=44) from [here](https://pkg.go.dev/database/sql#Register), or python docs or [hexdocs.pm](https://preview.hex.pm/preview/k6/0.0.1/show/lib/k6/template/web_socket.ex) for Elixir and Erlang languages). This is not a rare feature.

Rustdoc's source view often runs into a particular problem: to properly understand the implementation, you need to make reference to identifiers defined elsewhere. For instance, consider the common newtype pattern:

```
pub MyStruct(OtherStruct)
```

If you clicked through on `MyStruct`'s src link, expecting to see the private implementation details, you'd be disappointed: you actually need to see the contents of `OtherStruct`. However, `OtherStruct` might be in another file entirely. Tracking it down can be a tedious process:

- Use Ctrl-F to search the page for either a definition of `OtherStruct` or a `use` statement that imports it.
- If you found a `use` statement, figure out which file it maps to.
- Open the sidebar and navigate to that file.
- Ctrl-F again to find the actual definition of `OtherStruct`.

If `OtherStruct` itself is defined in terms of additional structs, you may need to repeat this process many times to get even a cursory understanding of the implementation of `MyStruct`. It can also be error prone. If we implement "go to definition", we can turn this whole process into a single click, and make the result reliable.

The same applies when reading a source code when type annotations are not available:

```
let var = some_other_var.do_something();
let var2 = a_function();
```

It'd require to look for each method in the various files, etc.

So overall, this would greatly improve the source code browsing experince.

The other goal is to allow to go back from the source code pages directly to the item documentation to be able to read the rendered content and not the "raw" doc comments.

So in short, this feature is split in two parts:

* Jump to definition an ident definition.
* Jump to an item documentation.

<!-- I tried to explain why I think having jump to def links and "back to doc" links is important, but I feel like I'm explaining it in some weird and unclear ways... Any suggestion is very welcome. -->

Adding this information directly into the documentation allows it to improve the documentation value: if you want to go a bit further what is written in the documentation (to see some implementation details for example), you can currently go to the source code. However, you're quickly limited to the current file if it's using private items not from this file.

Once you found what you're looking for, having a link to an item's documentation from the source code allows to add the missing connection between the source code viewer and the doc pages.

Another important note is that if documentation is split in multiple places or requires an external tool for the source code navigation, it's actually slowing down our users quite a lot.

<!-- This is the "story" part. Is it ok to put it here or should it be somewhere else? Also: is it clear enough? -->

A good example where this would be very helpful is for the [rust compiler source code](https://doc.rust-lang.org/1.57.0/nightly-rustc/src/rustc_middle/hir/map/mod.rs.html#872-877): even if a fully set up IDE or github, it's very hard to go around without previous knowledge or help from someone else. It's also very common to have undocumented items or to just want to see how something is implemented. With the "jump to definition", it already improved quite a lot the browsing experience by allowing to jump super quickly by simply clicking on a item. The missing part is now to go back from the source code into the item documentation to make it complete.

# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation

When going to the source code pages (as you can see already in the [compiler documentation](https://doc.rust-lang.org/1.57.0/nightly-rustc/src/rustc_middle/hir/map/mod.rs.html#872-877)), you will be able to click on idents to go to their definition.

Once at their definition, if you click on the item name, you'll arrive on its documentation page (if it has one, otherwise nothing will happen).

# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation

It doesn't require javascript since it's only generating links, making it work on both desktop and mobile, with or without javascript enabled.

So on the technical side, there isn't big issues. You can see the first part of this RFC implemented [here](https://github.com/rust-lang/rust/pull/84176).

For the UI, we have the following constraints:

* Must work on mobile and desktop: we cannot rely on mouse hover events.
* It's better if it works without javascript (for accessibility, it's very important but also for maintenance reasons too).

With this in mind, the suggested UI would be like this:

* Links generated on idents in source code will jump to the ident definition.
* Links generated on items' definition will jump to their documentation page (if any, private items don't have one by default).
* On mobile, these links will have dotted underline (because you don't have a cursor which change when hovering them).

Basically, the source code pages' UI doesn't change.

# Drawbacks
[drawbacks]: #drawbacks

**The biggest concern is actually about "scope expansion"**. If we add this feature, why not adding others like a "commit source code viewer", or a "git blame source code viewer", or "go to this line in github/gitlab"?

Unfortunately, on this part, the best answer I can provide is that we will need to put clear limits to what we don't want. I think we need to keep rustdoc focused on its target: documentation. We provide source code pages, so this feature allows to browse them more efficiently by using information we already have. Anything more advanced would be very likely out-of-scope.

**Another concern is**: "why should we implement this in rustdoc? Aren't there already existing tools doing it?"

A good answer to this is actually the following scenario: you are on <docs.rs> and you're looking at a crate documentation. You want to see how something is implemented and click on the `[src]` link. At this point, you encounter an item used in this page but not defined in this page. Do you want to clone the crate locally to check it out or go to github/gitlab to check it there or do you prefer having the links directly available?

**Last concern is about the maintenance**.

Any feature has a maintenance cost, this one included. It was suggested to put this feature in its own crate. The only part that can be extracted is the span map builder. But it would very likely be more of a problem than a solution considering that rustdoc API doesn't allow it easily.

One more argument about this is that the feature actually requires not that much code. It is split in two parts:

* https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/span_map.rs (which is basically a visitor gathering `span`)
* https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/highlight.rs#L725-L753 (for generating links)

# Rationale and alternatives
[rationale-and-alternatives]: #rationale-and-alternatives

[Github Code navigation feature](https://docs.github.com/en/repositories/working-with-files/using-files/navigating-code-on-github): Relying on external (and private) tools doesn't seem like a good idea. If they decide to shut it down, we can't do anything about it. In addition to that, not all projects are on github, so it excludes them. It also requires an internet connection.

rust-analyzer: This is a public opensource project. However, the setup isn't super easy (but it's a minor issue) and when using it on the rust compiler source code, it's quite resource-heavy. Also, if you want to look at a crate source code on <docs.rs>, you'd need to clone it locally to be able to use rust-analyzer on it.

# Prior art
[prior-art]: #prior-art

As mentionned above, it is actually quite common for documentation tools to have a source viewer. Implementations vary a bit between them:

| ------------- | ------------------ | ------------------ | ------------------------ |
| tool/language | source code viewer | jump to definition | go back to documentation |
| ------------- | ------------------ | ------------------ | ------------------------ |
| [doxygen](https://eigen.tuxfamily.org/dox/Matrix_8h_source.html) | yes | no | yes |
| [Go](https://cs.opensource.google/go/go/+/go1.16.5:src/database/sql/sql.go;l=44) | yes | yes | no |
| [hexdocs](https://preview.hex.pm/preview/k6/0.0.1/show/lib/k6/template/web_socket.ex) | yes | no | no |
| java | no | no | no |
| python (sphynx/pydoc) | no (links to github) | no | no |
| ruby | yes (directly on the page) | no | no |
| ------------- | ------------------ | ------------------ | ------------------------ |

# Unresolved questions
[unresolved-questions]: #unresolved-questions

Is it the best way to make the links to go to an item documentation like this? Maybe something adding a small icon to click right besides it should be better?

Should we add links to documentation to all items (impl blocks, methods, trait/impl associated items) or not?

0 comments on commit 9907e9f

Please sign in to comment.