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

Accept additional user-defined syntax classes in fenced code blocks #110800

Merged
merged 13 commits into from Sep 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Expand Up @@ -88,7 +88,7 @@
//!
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
//!
//! ```{.text}
//! ```text
//! Struct(vec![FieldInfo {
//! span: <span of x>
//! name: Some(<ident of x>),
Expand All @@ -99,7 +99,7 @@
//!
//! For the `B` impl, called with `B(a)` and `B(b)`,
//!
//! ```{.text}
//! ```text
//! Struct(vec![FieldInfo {
//! span: <span of `i32`>,
//! name: None,
Expand All @@ -113,7 +113,7 @@
//! When generating the `expr` for a call with `self == C0(a)` and `other
//! == C0(b)`, the SubstructureFields is
//!
//! ```{.text}
//! ```text
//! EnumMatching(0, <ast::Variant for C0>,
//! vec![FieldInfo {
//! span: <span of i32>
Expand All @@ -125,7 +125,7 @@
//!
//! For `C1 {x}` and `C1 {x}`,
//!
//! ```{.text}
//! ```text
//! EnumMatching(1, <ast::Variant for C1>,
//! vec![FieldInfo {
//! span: <span of x>
Expand All @@ -137,7 +137,7 @@
//!
//! For the tags,
//!
//! ```{.text}
//! ```text
//! EnumTag(
//! &[<ident of self tag>, <ident of other tag>], <expr to combine with>)
//! ```
Expand All @@ -149,7 +149,7 @@
//!
//! A static method on the types above would result in,
//!
//! ```{.text}
//! ```text
//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
//!
//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/active.rs
Expand Up @@ -401,6 +401,8 @@ declare_features! (
/// Allows function attribute `#[coverage(on/off)]`, to control coverage
/// instrumentation of that function.
(active, coverage_attribute, "CURRENT_RUSTC_VERSION", Some(84605), None),
/// Allows users to provide classes for fenced code block using `class:classname`.
(active, custom_code_classes_in_docs, "CURRENT_RUSTC_VERSION", Some(79483), None),
/// Allows non-builtin attributes in inner attribute position.
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/typeck_results.rs
Expand Up @@ -165,15 +165,15 @@ pub struct TypeckResults<'tcx> {
/// reading places that are mentioned in a closure (because of _ patterns). However,
/// to ensure the places are initialized, we introduce fake reads.
/// Consider these two examples:
/// ``` (discriminant matching with only wildcard arm)
/// ```ignore (discriminant matching with only wildcard arm)
/// let x: u8;
/// let c = || match x { _ => () };
/// ```
/// In this example, we don't need to actually read/borrow `x` in `c`, and so we don't
/// want to capture it. However, we do still want an error here, because `x` should have
/// to be initialized at the point where c is created. Therefore, we add a "fake read"
/// instead.
/// ``` (destructured assignments)
/// ```ignore (destructured assignments)
/// let c = || {
/// let (t1, t2) = t;
/// }
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Expand Up @@ -592,6 +592,7 @@ symbols! {
cttz,
cttz_nonzero,
custom_attribute,
custom_code_classes_in_docs,
custom_derive,
custom_inner_attributes,
custom_mir,
Expand Down
44 changes: 44 additions & 0 deletions src/doc/rustdoc/src/unstable-features.md
Expand Up @@ -625,3 +625,47 @@ and check the values of `feature`: `foo` and `bar`.

This flag enables the generation of links in the source code pages which allow the reader
to jump to a type definition.

### Custom CSS classes for code blocks

```rust
#![feature(custom_code_classes_in_docs)]

/// ```custom,{class=language-c}
/// int main(void) { return 0; }
/// ```
pub struct Bar;
```

The text `int main(void) { return 0; }` is rendered without highlighting in a code block
with the class `language-c`. This can be used to highlight other languages through JavaScript
libraries for example.

Without the `custom` attribute, it would be generated as a Rust code example with an additional
`language-C` CSS class. Therefore, if you specifically don't want it to be a Rust code example,
don't forget to add the `custom` attribute.

To be noted that you can replace `class=` with `.` to achieve the same result:

```rust
#![feature(custom_code_classes_in_docs)]

/// ```custom,{.language-c}
/// int main(void) { return 0; }
/// ```
pub struct Bar;
```
notriddle marked this conversation as resolved.
Show resolved Hide resolved

To be noted, `rust` and `.rust`/`class=rust` have different effects: `rust` indicates that this is
a Rust code block whereas the two others add a "rust" CSS class on the code block.

You can also use double quotes:

```rust
#![feature(custom_code_classes_in_docs)]

/// ```"not rust" {."hello everyone"}
/// int main(void) { return 0; }
/// ```
pub struct Bar;
```
25 changes: 21 additions & 4 deletions src/librustdoc/html/highlight.rs
Expand Up @@ -52,8 +52,9 @@ pub(crate) fn render_example_with_highlighting(
out: &mut Buffer,
tooltip: Tooltip,
playground_button: Option<&str>,
extra_classes: &[String],
) {
write_header(out, "rust-example-rendered", None, tooltip);
write_header(out, "rust-example-rendered", None, tooltip, extra_classes);
write_code(out, src, None, None);
write_footer(out, playground_button);
}
Expand All @@ -65,7 +66,13 @@ pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
write!(out, "</pre>");
}

fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) {
fn write_header(
out: &mut Buffer,
class: &str,
extra_content: Option<Buffer>,
tooltip: Tooltip,
extra_classes: &[String],
) {
write!(
out,
"<div class=\"example-wrap{}\">",
Expand Down Expand Up @@ -100,9 +107,19 @@ fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, to
out.push_buffer(extra);
}
if class.is_empty() {
write!(out, "<pre class=\"rust\">");
write!(
out,
"<pre class=\"rust{}{}\">",
if extra_classes.is_empty() { "" } else { " " },
extra_classes.join(" "),
);
} else {
write!(out, "<pre class=\"rust {class}\">");
write!(
out,
"<pre class=\"rust {class}{}{}\">",
if extra_classes.is_empty() { "" } else { " " },
extra_classes.join(" "),
);
}
write!(out, "<code>");
}
Expand Down