owned this note
owned this note
Published
Linked with GitHub
# Rustdoc on case-insensitive filesystems
- Feature Name: (fill me in with a unique ident, `my_awesome_feature`)
- Start Date: (fill me in with today's date, YYYY-MM-DD)
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)
# Intro to rustdoc team
This is written in RFC format, but is mostly just a way for me to present an idea to the rustdoc team. Because of this, some sections are empty. Feel free to fill them in if you'd like.
An important thing to note is that at the moment this RFC has a bunch of "knobs" that we should decide on collectively. They're listed in the "unresolved questions" section, and I've marked them as such in the text.
If we were to _just_ do the "disambiguation" and "disambiguation pages" part of this document, we _probably_ do not need an RFC, but the rest of it probably does; and given that we're in this weird zone it's worth doing a hopefully quick RFC anyway. Alternatively, we can implement the disambiguation stuff and just RFC the flag and lint.
# Summary
[summary]: #summary
Changes to Rustdoc to allow it to sensibly generate files for case-sensitive file systems.
# Motivation
[motivation]: #motivation
Currently, rustdoc includes item names in the generated filenames, so `foo::Bar` will be stored at some place like `foo/struct.Bar.html`.
Rust is a case sensitive language, so it is completely legal to have `struct Foo` and `struct FOO` in the same module. This kind of thing most commonly occurs in generated bindings, where `CamelCaseFunction()` and `camelCaseFunction()` may coexist (The [brotli crate](https://docs.rs/brotli/3.3.0/brotli/enc/static_dict/index.html) has a bunch of such examples).
Currently rustdoc simply overwrites one file with the other, which means that doc generation on most Windows and Mac systems simply drops some files. This is suboptimal.
# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation
Unnecessary for team discussion
# Reference-level explanation
[reference-level-explanation]: #reference-level-explanation
By default, this proposal _only_ affects documentation when generated on case insensitive filesystems. See the `--generate-case-insensitive` section for more.
## Disambiguation
When generating documentation on case insensitive file systems, conflicting items have a number appended to them based on lexicographic sorting. So for example if you have `struct foo`, `struct Foo`, and `struct FOO`, rustdoc will generate the following files:
- `struct.foo-1.html`
- `struct.Foo-2.html`
- `struct.FOO-3.html`
The exact disambiguation scheme need not be pinned down in this RFC.
This will _only_ apply to cases where there are conflicting items. The vast majority of items will continue to be generated the same.
For modules, roughly the same scheme applies: the folders `foo-1`, `Foo-2`, and `FOO-3` will be generated.
## Disambiguation pages
Whenever such a disambiguation occurs, `struct.Foo.html` (in the case of structs) or `foo/index.html` (in the case of modules) will be populated by a "disambiguation page". This allows people to continue to visit `.../struct.Foo.html` in the URL bar and get a sensible result.
Such a page will list all the items sharing the same name: in our `struct` example, it will list `foo`, `Foo`, and `FOO` as clickable links and mention that they have been disambiguated.
(unresolved question)
An additional bit of JS that can be written is that since _HTTP_ is case sensitive, we can have JS that detects which version was used in the URL (`struct.foo.html` vs `struct.Foo.html` etc), and automatically redirect based on that.
(unresolved question)
Ideally, rustdoc will _never_ link to disambiguation pages on its own; these exist purely to make the URL scheme continue to work.
## `--generate-case-insensitive`
Sometimes one may wish to generate documentation that is intended to be shipped to a case insensitive file system, even though one may be using a case sensitive one. An example of this would be use cases where people are generating a tarball of docs that anyone can download to use locally.
For this use case, `rustdoc` (unresolved: and `cargo doc`?) will have a `--generate-case-insensitive` option that forces the disambiguation behavior regardless of the filesystem being used.
## `#[doc(filename = "..")]`
(unresolved question)
It is good to have consistency across platforms, and people may desire to disambiguate these URLs on their own. We provide a `#[doc(filename = "FooBar"]` attribute, which will generate `struct.FooBar.html` instead.
It is a hard error for `#[doc(filename)]` files to ever clash with other files when compared case insensitively, so you cannot have `#[doc(filename = "bar")] struct Foo;` and `struct Bar;` in the same module.
## `rustdoc::differing_only_by_case`
(unresolved question)
To nudge people towards disambiguating their URLs, we have a `rustdoc::differing_only_by_case` lint that detects when a module has multiple items of the same kind that differ only by case, and suggests `doc(filename)` be used.
(the name of this lint is extremely bikesheddable)
# Drawbacks
[drawbacks]: #drawbacks
Why should we *not* do this?
# Unresolved questions
[unresolved-questions]: #unresolved-questions
We should decide on:
- Should we be using JS to autoredirect?
- Should rustdoc ever link to a disambiguation page directly?
- (manish) IMO it shouldn't; we should instead maintain a defid-to-file map and use that. This makes the disambiguation pages matter much less.
- Should we have `#[doc(filename)]` to allow people to write code that behaves the same across platforms?
- Should we have `rustdoc::differing_only_by_case` as a way to nudge people towards code that behaves the same across platforms?
- Should `--generate-case-sensitive` be available via `cargo doc`? Should it be on the stabilization track?
# Rationale and alternatives
[rationale-and-alternatives]: #rationale-and-alternatives
Some other designs are:
- We can introduce a new URL scheme (see [RFC 3097](https://github.com/rust-lang/rfcs/pull/3097)), but this would break all URLs when regenerated with rustdoc
- We can apply the above scheme unconditionally on all OSes (i.e. behave as if `--generate-case-sensitive` is always set), but this degrades URLs on case sensitive file systems: where `struct.foo.html` and `struct.Foo.html` used to work they will not anymore.
# Prior art
[prior-art]: #prior-art
(feel free to fill in)
# Future possibilities
[future-possibilities]: #future-possibilities
(feel free to fill in)