Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an item-info for non-public visibility, and remove redundant pub #90242

Closed
wants to merge 2 commits into from

Conversation

jsha
Copy link
Contributor

@jsha jsha commented Oct 24, 2021

For most documentation, the pub in front of each method is redundant: you know the method is public because you are reading the documentation.

However, when running with --document-private, it's important to see which items are public and which are private. This adds an item-info tag for private items showing their visibility, and removes the pub from methods and fields.

This doesn't currently touch the summary code block at the top of the page, which will still have pub or pub(crate) or whatever is appropriate.

This refactors some code in Visibility to allow better reuse.

Part of #59829. Note: one of the pieces of feedback there was that the item-infos (experimental, deprecated, platform-specific, etc) are too prominent. That may be the case, but for this change, I think the important thing is matching the other item-infos, and we can change the style of item-infos later if we want to.

r? @GuillaumeGomez
/cc @camelid

Demo:

https://jacob.hoffman-andrews.com/rust/document-private/foo/outer_mod/inner_mod/inmost_mod/struct.Boo.html
https://jacob.hoffman-andrews.com/rust/document-private/foo/outmost_mod/outer_mod/inner_mod/inmost_mod/struct.Foo.html
https://jacob.hoffman-andrews.com/rust/document-private/foo/outmost_mod/outer_mod/inner_mod/inmost_mod/enum.Bar.html

image

Visibility::print_with_space and Visibility::to_src_with_space had some
duplicated code. This extracts the code into a shared enum, with a
Display impl that will make reuse elsewhere easier.
For most documentation, the `pub` in front of each method is redundant:
you know the method is public because you are reading the documentation.

However, when running with `--document-private`, it's important to see
which items are public and which are private. This adds an item-info tag
for private items showing their visibility, and removes the `pub` from
methods and fields.

This doesn't currently touch the summary code block at the top of the
page, which will still have `pub` or `pub(crate)` or whatever is
appropriate.
@jsha jsha added T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. A-rustdoc-ui Area: Rustdoc UI (generated HTML) labels Oct 24, 2021
@rust-highfive
Copy link
Collaborator

Some changes occurred in HTML/CSS/JS.

cc @GuillaumeGomez

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 24, 2021
@Mark-Simulacrum
Copy link
Member

FWIW, I'd personally rather avoid having rustdoc invent a new way of describing privacy -- and the lack of a visibility label does not imply public in most Rust code, so it seems surprising to take that approach here.

Perhaps we can instead only emit visibility annotations if --document-private-items is passed, but not modify their style? These feel like orthogonal changes to me.

I'd definitely be in favor of removing pub in places where it can't be written in normal Rust code, like the blanket impls section for example, and it seems OK to remove it from non---document-private-items docs, though I also don't see it as all that distracting. Perhaps I'm just used to glossing over it though :)

image

@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-llvm-12 failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
Check compiletest suite=rustdoc mode=rustdoc (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
warning: `tidy` is not installed; diffs will not be generated

running 479 tests
i........F...........F............F..............i.....F............................................ 100/479
.........F..........F.F............................................................................. 200/479
.................................................................................................... 300/479
..................iF.....................................................F..........i............... 400/479
Some tests failed in compiletest suite=rustdoc mode=rustdoc host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu
...........................................................................F...

---- [rustdoc] rustdoc/async-fn.rs stdout ----


error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/async-fn" "/checkout/src/test/rustdoc/async-fn.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
38: @matches check failed
 `XPATH PATTERN` did not match
 // @matches - '//h4[@class="code-header"]' 'pub async fn f\(\)$'
39: @matches check failed
 `XPATH PATTERN` did not match
 // @matches - '//h4[@class="code-header"]' 'pub async unsafe fn g\(\)$'
40: @matches check failed
 `XPATH PATTERN` did not match
 // @matches - '//h4[@class="code-header"]' 'pub async fn mut_self\(self, first: usize\)$'
80: @has check failed
 `XPATH PATTERN` did not match
     // @has - '//div[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
83: @has check failed
 `XPATH PATTERN` did not match
     // @has - '//div[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
85: @has check failed
 `XPATH PATTERN` did not match
     // @has - '//div[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
Encountered 6 errors

------------------------------------------



---- [rustdoc] rustdoc/const-display.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/const-display" "/checkout/src/test/rustdoc/const-display.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
52: @has check failed
 `XPATH PATTERN` did not match
     // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/h4[@class="code-header"]' 'pub fn gated() -> u32'
58: @has check failed
 `XPATH PATTERN` did not match
     // @has 'foo/struct.Foo.html' '//div[@id="method.gated_unsafe"]/h4[@class="code-header"]' 'pub unsafe fn gated_unsafe() -> u32'
64: @has check failed
 `XPATH PATTERN` did not match
     // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/h4[@class="code-header"]' 'pub const fn stable_impl() -> u32'
Encountered 3 errors

------------------------------------------



---- [rustdoc] rustdoc/const-generics/const-generics-docs.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/const-generics/const-generics-docs" "/checkout/src/test/rustdoc/const-generics/const-generics-docs.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
44: @has check failed
 `XPATH PATTERN` did not match
     // @has - '//*[@id="method.hey"]' 'pub fn hey<const N: usize>(&self) -> Bar<u8, N>'
52: @has check failed
 `XPATH PATTERN` did not match
     // @has - '//*[@id="method.hey"]' 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
Encountered 2 errors

------------------------------------------



---- [rustdoc] rustdoc/deref-typedef.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/deref-typedef" "/checkout/src/test/rustdoc/deref-typedef.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
5: @has check failed
 `XPATH PATTERN` did not match
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
6: @has check failed
 `XPATH PATTERN` did not match
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
7: @has check failed
 `XPATH PATTERN` did not match
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
8: @has check failed
 `XPATH PATTERN` did not match
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
Encountered 4 errors

------------------------------------------



---- [rustdoc] rustdoc/higher-ranked-trait-bounds.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/higher-ranked-trait-bounds" "/checkout/src/test/rustdoc/higher-ranked-trait-bounds.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
41: @has check failed
 `XPATH PATTERN` did not match
     // @has - '//h4[@class="code-header"]' "pub fn bar<T>() where T: Trait<'a>,"
Encountered 1 errors

------------------------------------------



---- [rustdoc] rustdoc/inline_cross/impl_trait.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/inline_cross/impl_trait" "/checkout/src/test/rustdoc/inline_cross/impl_trait.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
34: @has check failed
 `XPATH PATTERN` did not match
 // @has - '//*[@id="method.method"]//h4[@class="code-header"]' "pub fn method<'a>(_x: impl Clone + Into<Vec<u8, Global>> + 'a)"
39: @has check failed
 `XPATH PATTERN` did not match
 // @has - '//*[@id="method.async_foo"]' "pub async fn async_foo("
Encountered 2 errors

------------------------------------------



---- [rustdoc] rustdoc/inline_cross/assoc-items.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/inline_cross/assoc-items" "/checkout/src/test/rustdoc/inline_cross/assoc-items.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
14: @has check failed
 `XPATH PATTERN` did not match
 // @has - '//*[@id="method.public_method"]' 'pub fn public_method()'
Encountered 1 errors

------------------------------------------



---- [rustdoc] rustdoc/issue-76501.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/issue-76501" "/checkout/src/test/rustdoc/issue-76501.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
11: @has check failed
 `XPATH PATTERN` did not match
     // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' 'pub const fn blurp() -> i32'
Encountered 1 errors

------------------------------------------



---- [rustdoc] rustdoc/pub-method.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/pub-method" "/checkout/src/test/rustdoc/pub-method.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
13: @has check failed
 `XPATH PATTERN` did not match
 // @has - '//*[@class="method has-srclink"]' 'pub fn new()'
Encountered 1 errors

------------------------------------------



---- [rustdoc] rustdoc/visibility.rs stdout ----

error: htmldocck failed!
status: exit status: 1
command: "/usr/bin/python3" "/checkout/src/etc/htmldocck.py" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc/visibility" "/checkout/src/test/rustdoc/visibility.rs"
------------------------------------------

------------------------------------------
stderr:
stderr:
------------------------------------------
26: @!has check failed
 `XPATH PATTERN` did not match
     // @!has 'foo/a/struct.FooAInA.html' '//pre' 'pub'
29: @!has check failed
 `XPATH PATTERN` did not match
     // @!has 'foo/a/struct.FooAPriv.html' '//pre' 'pub'
38: @!has check failed
 `XPATH PATTERN` did not match
         // @!has 'foo/a/b/struct.FooBInAB.html' '//pre' 'pub'
41: @!has check failed
 `XPATH PATTERN` did not match
         // @!has 'foo/a/b/struct.FooBPriv.html' '//pre' 'pub'
Encountered 4 errors

------------------------------------------

---
test result: FAILED. 465 passed; 10 failed; 4 ignored; 0 measured; 0 filtered out; finished in 44.85s



command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/compiletest" "--compile-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib" "--run-lib-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/lib" "--rustc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "--rustdoc-path" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustdoc" "--src-base" "/checkout/src/test/rustdoc" "--build-base" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/rustdoc" "--stage-id" "stage2-x86_64-unknown-linux-gnu" "--suite" "rustdoc" "--mode" "rustdoc" "--target" "x86_64-unknown-linux-gnu" "--host" "x86_64-unknown-linux-gnu" "--llvm-filecheck" "/usr/lib/llvm-12/bin/FileCheck" "--nodejs" "/usr/bin/node" "--host-rustcflags" "-Crpath -O -Cdebuginfo=0  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--target-rustcflags" "-Crpath -O -Cdebuginfo=0  -Lnative=/checkout/obj/build/x86_64-unknown-linux-gnu/native/rust-test-helpers" "--docck-python" "/usr/bin/python3" "--lldb-python" "/usr/bin/python3" "--gdb" "/usr/bin/gdb" "--quiet" "--llvm-version" "12.0.0" "--llvm-components" "aarch64 aarch64asmparser aarch64codegen aarch64desc aarch64disassembler aarch64info aarch64utils aggressiveinstcombine all all-targets amdgpu amdgpuasmparser amdgpucodegen amdgpudesc amdgpudisassembler amdgpuinfo amdgpuutils analysis arm armasmparser armcodegen armdesc armdisassembler arminfo armutils asmparser asmprinter avr avrasmparser avrcodegen avrdesc avrdisassembler avrinfo binaryformat bitreader bitstreamreader bitwriter bpf bpfasmparser bpfcodegen bpfdesc bpfdisassembler bpfinfo cfguard codegen core coroutines coverage debuginfocodeview debuginfodwarf debuginfogsym debuginfomsf debuginfopdb demangle dlltooldriver dwarflinker engine executionengine extensions filecheck frontendopenacc frontendopenmp fuzzmutate globalisel hellonew hexagon hexagonasmparser hexagoncodegen hexagondesc hexagondisassembler hexagoninfo instcombine instrumentation interfacestub interpreter ipo irreader jitlink lanai lanaiasmparser lanaicodegen lanaidesc lanaidisassembler lanaiinfo libdriver lineeditor linker lto mc mca mcdisassembler mcjit mcparser mips mipsasmparser mipscodegen mipsdesc mipsdisassembler mipsinfo mirparser msp430 msp430asmparser msp430codegen msp430desc msp430disassembler msp430info native nativecodegen nvptx nvptxcodegen nvptxdesc nvptxinfo objcarcopts object objectyaml option orcjit orcshared orctargetprocess passes perfjitevents powerpc powerpcasmparser powerpccodegen powerpcdesc powerpcdisassembler powerpcinfo profiledata remarks riscv riscvasmparser riscvcodegen riscvdesc riscvdisassembler riscvinfo runtimedyld scalaropts selectiondag sparc sparcasmparser sparccodegen sparcdesc sparcdisassembler sparcinfo support symbolize systemz systemzasmparser systemzcodegen systemzdesc systemzdisassembler systemzinfo tablegen target textapi transformutils vectorize webassembly webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo windowsmanifest x86 x86asmparser x86codegen x86desc x86disassembler x86info xcore xcorecodegen xcoredesc xcoredisassembler xcoreinfo xray" "--system-llvm" "--cc" "" "--cxx" "" "--cflags" "" "--adb-path" "adb" "--adb-test-dir" "/data/tmp/work" "--android-cross-path" "" "--channel" "nightly" "--color" "always"


Build completed unsuccessfully in 0:16:46

@camelid
Copy link
Member

camelid commented Oct 24, 2021

Using item-infos to display visibility feels like a much worse way to communicate the information. It's distracting and takes up significant visual space on the page. When documenting a crate with private items, tons of items are going to have these markers, which would clutter the UI even further.

Making the visibility display dependent on whether --document-private-items is passed also doesn't feel good to me. Then, whenever I'm looking at docs, I have to remember, or even know at all, whether the crate was documented with private items; or I might get confused.

As discussed in the PR from a few months ago (#86283), I think it's good for rustdoc to be as close as possible to Rust source code. Perhaps what Mark said above in #90242 (comment) about hiding pub for places it doesn't appear in source code could be a good way to both start reducing clutter and fix a bug?

IMHO, having an extra pub for each method does not seem that significant compared to the other UI issues with rustdoc. Personally, I think it'd be best for us to focus on reducing clutter elsewhere in the UI for now.

@jsha
Copy link
Contributor Author

jsha commented Oct 24, 2021

Making the visibility display dependent on whether --document-private-items is passed also doesn't feel good to me.

This doesn't make the visibility display dependent on the --document-private-items flag. It removes pub from struct methods in all cases. The changes to --document-private-items are a followup from your comment a few months ago: if we omit pub from certain places, we need a way to distinguish things that are private.

The core problem I'm trying to solve is this: Multiple users have complained about the "scannability" of Rust docs; that's one of the core accessibility complaints in #59829. Users tend to scan web pages in an "F-Pattern", that is, after reading a summary at the top, they scan down the left side of the page. That means we should place the information they are looking for - the method name, for most structs and traits - as close to the left side of the page as possible, in the path of their scan.

There are several things that prevent the method name from being leftmost - pub, fn, const, async, etc. But pub is the most straightforward to get rid of, since fn foo() is still valid Rust syntax - and in fact we don't have any pub when looking at trait methods. Of course, trait methods don't have pub because in the source code, trait methods can't have visibility annotations - only the trait itself. But if the goal of pub is to communicate information to the user, shouldn't we have it in all the places that something is public?

One way to look at this is in terms of tasks:

Task 1: As a user reading public documentation, I need to know which methods and types are public. This is trivially achieved: everything in the documentation is public.

Task 2: As a developer working on a crate, I need to read documentation generated with --document-private and distinguish what is private from what is public.

Are we in agreement that Task 1 is as easily accomplished with this PR?

My argument is that Task 2 is actually better accomplished by marking the "private" case than the non-private case:

  • To notice that fn foo() is private, you need to notice two things: (1) the absence of the pub keyword (users notice presence, not absence, of indicators), and (2) the fact that fn foo() is part of a struct rather than part of a trait.

@Mark-Simulacrum said:

I'd personally rather avoid having rustdoc invent a new way of describing privacy -- and the lack of a visibility label does not imply public in most Rust code, so it seems surprising to take that approach here.

This is not really a new way to describe privacy: It's how privacy is described at https://doc.rust-lang.org/reference/visibility-and-privacy.html:

By default, everything in Rust is private

The difference is that privacy is expressed one way in the code, and one way in the reference documentation. I think it makes sense to align rustdoc with the reference documentation rather than the code. The code expression is geared towards one use case: privacy should be the default. The documentation expression should be geared towards another use case: public visibility is the default.

@camelid said:

IMHO, having an extra pub for each method does not seem that significant compared to the other UI issues with rustdoc.
Personally, I think it'd be best for us to focus on reducing clutter elsewhere in the UI for now.

Personally, I think the scannability of method names is the most significant clutter problem in the UI right now, and I think removing pub for struct methods is an important step towards improving it. I hope I can convince you. :-)

When documenting a crate with private items, tons of items are going to have these markers, which would clutter the UI even further.

Agreed! Would this idea improve things? If a struct is private, we would mark that struct private at the top of its page, but we would not separately annotate its fields and methods as private, since that is implied by the struct being private.

Also, I'd be really interested to hear more details about your workflow - what crates do you use --document-private on, and what tasks are you looking to accomplish when you do? Are they mostly crates that will eventually be published? Or are they crates where everything is perpetually private?

@camelid
Copy link
Member

camelid commented Oct 25, 2021

This doesn't make the visibility display dependent on the --document-private-items flag. It removes pub from struct methods in all cases. The changes to --document-private-items are a followup from your comment a few months ago: if we omit pub from certain places, we need a way to distinguish things that are private.

Sorry, I wasn't clear. I was referring to Mark's suggestion from above:

Perhaps we can instead only emit visibility annotations if --document-private-items is passed, but not modify their style? These feel like orthogonal changes to me.


@Mark-Simulacrum said:

I'd personally rather avoid having rustdoc invent a new way of describing privacy -- and the lack of a visibility label does not imply public in most Rust code, so it seems surprising to take that approach here.

This is not really a new way to describe privacy: It's how privacy is described at https://doc.rust-lang.org/reference/visibility-and-privacy.html:

By default, everything in Rust is private

The difference is that privacy is expressed one way in the code, and one way in the reference documentation. I think it makes sense to align rustdoc with the reference documentation rather than the code. The code expression is geared towards one use case: privacy should be the default. The documentation expression should be geared towards another use case: public visibility is the default.

What do you mean by the way privacy is expressed in the Reference documentation? The Rust Reference should be describing how Rust source code works. Where does the Reference say that public visibility is the default? I want to make sure we're not miscommunicating :)


Would this idea improve things? If a struct is private, we would mark that struct private at the top of its page, but we would not separately annotate its fields and methods as private, since that is implied by the struct being private.

It's hard for me to know without experiencing it first-hand. I wonder if we could consider changing the UI behind a feature flag so we could get practical experience with it before landing it for all users?

Also, I'd be really interested to hear more details about your workflow - what crates do you use --document-private on, and what tasks are you looking to accomplish when you do? Are they mostly crates that will eventually be published? Or are they crates where everything is perpetually private?

Mostly, I'm referring to the rustc and rustdoc API docs (/nightly/nightly-rustc), which I use frequently while working on Rust. I also sometimes use --document-private-items with a private side project (that's an executable, not a library), but not very frequently. I also sometimes document rust-lang/triagebot with private items when working on it.

For the most part, I use --document-private-items to be able to easily browse large and/or unfamiliar codebases and as a quick way to search for items I see in the code that I want to learn more about.


Overall, part of the issue is that I and others, like Mark, are used to the docs the way they are. Thus, it's hard for me to tell whether changing the format would be an improvement or regression, and either way, I'd have to get used to the new UI. Like I mentioned above, maybe we could figure out a way to land this behind a feature flag (or, rather, an unstable CLI flag)? Otherwise, it feels like we have to commit to the new UI before even trying it out "in the wild".

@camelid
Copy link
Member

camelid commented Oct 25, 2021

One way to look at this is in terms of tasks:

Task 1: As a user reading public documentation, I need to know which methods and types are public. This is trivially achieved: everything in the documentation is public.

Task 2: As a developer working on a crate, I need to read documentation generated with --document-private and distinguish what is private from what is public.

Are we in agreement that Task 1 is as easily accomplished with this PR?

My argument is that Task 2 is actually better accomplished by marking the "private" case than the non-private case:

  • To notice that fn foo() is private, you need to notice two things: (1) the absence of the pub keyword (users notice presence, not absence, of indicators), and (2) the fact that fn foo() is part of a struct rather than part of a trait.

I agree that it's valuable to frame the situation as two distinct ways to use rustdoc (what you call tasks): the "user" and the "developer" use case. Rustdoc is by default meant to be used in "user mode", and passing --document-private-items switches it to "developer mode". However, I think ideally the user and developer mode aren't too far apart, so consumers of the docs don't have to themselves switch between user and developer mode just to understand the docs. Displaying visibility differently between the two seems potentially helpful, though I still don't think using item-infos is the right way to do it.

cc @rust-lang/rustdoc to see what other people think

@jsha
Copy link
Contributor Author

jsha commented Oct 25, 2021

@Mark-Simulacrum said:

I'd personally rather avoid having rustdoc invent a new way of describing privacy -- and the lack of a visibility label does not imply public in most Rust code, so it seems surprising to take that approach here.

This is not really a new way to describe privacy: It's how privacy is described at https://doc.rust-lang.org/reference/visibility-and-privacy.html:

By default, everything in Rust is private

To clarify, what I meant by quoting this is that putting "Visibility: private" in Rustdoc output is not a new way to describe privacy, but that those words ("visibility" and "private") are already used to describe the semantics expressed in code by "", pub(crate), pub(self), and so on.

The difference is that privacy is expressed one way in the code, and one way in the reference documentation. I think it makes sense to align rustdoc with the reference documentation rather than the code. The code expression is geared towards one use case: privacy should be the default. The documentation expression should be geared towards another use case: public visibility is the default.

What do you mean by the way privacy is expressed in the Reference documentation? The Rust Reference should be describing how Rust source code works. Where does the Reference say that public visibility is the default? I want to make sure we're not miscommunicating :)

Ah, yes, I'm not saying that public visibility is the default when you write code. I'm saying: As a user, when I read Rust docs, 99.99% of the items I read are public. I therefore assume that most things I read are public - that's what I mean by default. And that's a property one would like from one's public documentation.

I think what I'm gathering from your use cases is: when you use --document-private, you know that you're looking at private internals, so the feeling of "default public" that other users have isn't present for you. Perhaps even the opposite - when you read private docs, do you assume most things are private? Or are you checking on a case-by-case basis?

@Mark-Simulacrum
Copy link
Member

Maybe this is an unusual mindset, but I usually don't read docs - regardless of how they were generated - with a fixation on privacy. Most or all of the code I deal with typically can, if necessary, make things public or expose a new public wrapper if necessary, so it's not a particularly meaningful attribute.

In that context, I'd prefer that the way rustdoc exposes privacy matches how I expect to see the function in source code (sort of a form of inline docs): that is, pub is rendered as pub, lack thereof is similarly rendered as nothing - just like in the code I write or source code I read.

In practice, I think that my lack of interest drives a desire to make the information (which is useful when I actually decide to use an API) as streamlined as possible. Since I'm already used to scanning Rust code in it's .rs form, pub/pub(crate) or lack thereof don't jump out at me, my eyes skim them easily, but any other indicator is "unusual" and so a distraction.

I think my "goal" for the function signatures in rustdoc is that they're as close as possible to matching what I'd see in the source, and so having different rendering then the source does not seem like a good idea. I'd rather see "pub" a bunch rather than not and need to think "oh this is not a .rs signature, so rustdoc is removing visibility markers, so pub is not necessary".

I think the signatures having the same syntax also helps as a teaching tool, since it gives a very clear mapping. But I have no actual proof for this.

@GuillaumeGomez
Copy link
Member

Just to voice my opinion here: the "scannability" issue of the rust docs came up quite a lot of time. I had quite a lot discussions about it but could never find out a way to improve it without making the output "heavier". Removing the pub in front of public items is the only thing that was always agreed upon. The big issue is that it's quite tricky to come up with a good solution on how to display the level of "privacy" of an item. I'm quite happy that @jsha is working on it now.

However, I'm not completely convinced by the current approach. It's fine, but heavier. Which seems to be the opposite of what we're trying to achieve here.

@Manishearth
Copy link
Member

Removing the pub in front of public items is the only thing that was always agreed upon.

I don't think this is true, I've been against deviating too much from how it looks in the source so that people don't have to learn a new set of conventions.


If the stated goal is scannability it might be worth having the alignment axis be the method name and have the modifiers appear before it (probably with a smaller font)

I tend to agree with Mark on my goals of using rust documentation

@camelid
Copy link
Member

camelid commented Oct 25, 2021

I think what I'm gathering from your use cases is: when you use --document-private, you know that you're looking at private internals, so the feeling of "default public" that other users have isn't present for you. Perhaps even the opposite - when you read private docs, do you assume most things are private? Or are you checking on a case-by-case basis?

My situation is essentially what Mark described:

Maybe this is an unusual mindset, but I usually don't read docs - regardless of how they were generated - with a fixation on privacy. Most or all of the code I deal with typically can, if necessary, make things public or expose a new public wrapper if necessary, so it's not a particularly meaningful attribute.

[...]

Since I'm already used to scanning Rust code in it's .rs form, pub/pub(crate) or lack thereof don't jump out at me, my eyes skim them easily, but any other indicator is "unusual" and so a distraction.

@JohnCSimon JohnCSimon added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 16, 2021
@bors
Copy link
Contributor

bors commented Nov 25, 2021

☔ The latest upstream changes (presumably #91203) made this pull request unmergeable. Please resolve the merge conflicts.

@JohnCSimon
Copy link
Member

ping from triage:
@jsha
Returning to you to address build failures and after that, please switch back to S-waiting-on-review.
thanks.

@rustbot label: +S-waiting-on-author -S-waiting-on-review

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 12, 2021
@JohnCSimon JohnCSimon added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 30, 2022
@Dylan-DPC
Copy link
Member

@jsha any updates on this?

@camelid
Copy link
Member

camelid commented Feb 19, 2022

I still prefer the current approach of trying to match source code syntax. And, if we were to switch to a less-close-to-syntax approach, I quite dislike using "item-infos" since they're very visually noisy.

@jsha
Copy link
Contributor Author

jsha commented Feb 23, 2022

Yeah, I agree item-info is not the way to go here. I hadn't really grokked how much people use rustdoc to navigate private aspects of a crate. Closing for now; I'll try again with a different approach later.

@jsha jsha closed this Feb 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-rustdoc-ui Area: Rustdoc UI (generated HTML) S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.