This feature is about adding links on idents in the source code pages in rustdoc. There have been a lot of concerns about this feature, the point here is to go through all of it, and plan exactly what we want and what we don't want.
I insist on this: I don't want this feature to do anything else than creating links at "compile time". Anything more would very likely be out-of-scope.
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. And some of them also provide this feature (like Go for example, you can access this source code from here, or python docs or hexdocs.pm 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 ause
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.
An example of an extension of this feature would be to have a "go to definition" when clicking on variable names (like var
or some_other_var
). This sounds like a natural and somewhat "in scope" extension. Or we could go even further and add a "go to type definition". I personally think it's a bit "too much" but not sure what others might think... For now, none of them are handled and I don't plan to add them if this feature is merged.
Similarly, we could also add something to tell us what the type of the variable is. But same answer as previously.
Now let's start with how it works:
It uses a HIR visitor going through all files to collect spans where the ident
appear as key and put its definition span as definition. The goal being to then use this "span map" to generate links when we generate the source code pages.
As easy as it may seem, it actually has one issue: on methods' call, we need to call typeck_body
which generates error messages (even though it doesn't prevent rustdoc to run perfectly normally). It happens when it's being used on blocks which are normally opted-out from the compilation because of a cfg
. So sometimes, we ask information about a method which simply doesn't exist in the current cfg
. In case it cannot find one, we simply don't generate the span, but the error messages remain. The solution to this problem would be to simply disable error output in this given context.
It doesn't require JS since it's only generating links.
The code for the feature is already well documented.
So on the technical side, there isn't big issues. There is an implementation of this proposal available there: rust-lang/rust#84176
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 it more efficiently by using information we already have. Anything more advanced would be very likely out-of-scope.
The big problem being to be able to determine more precisely where is the "conceptual limit": if a contributor in the future comes to you and says "I really want additional source browsing feature X," what is the basis on which you would tell them yes or no?
Another concern is: "why should we implement this in rustdoc? Aren't there already existing tools doing it?".
Github doesn't provide this feature for Rust and cargo-src
is old and unmainted and has been for years now. So there aren't many alternatives there unfortunately.
Last concern was 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. It's also very likely that it's the only part which will need "evolutions" because it's using rustc's API. Not sure if it'll make anything simpler or not, to be debated I guess?
I would start by making the positive case for (a) why this feature is important and (b) why it belongs in rustdoc. For instance it might go something like this:
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.
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:
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
statement that imports it.use
statement, figure out which file it maps to.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.
Also in terms of addressing the concerns about scope creep: I think what we need is a description of the conceptual line between this feature and other, related features. Think of it this way: If a contributor in the future comes to you and says "I really want additional source browsing feature X," what is the basis on which you would tell them yes or no?