Way back in #187, I introduced a hacky tool to show the available space on a slide: it was a `mdbook` plugin which injected the necessary CSS on each slide. Crude, but it got the job done. The logic was moved from Python to a real CSS file with associated JavaScript in #1842. In #1917, the functionality was moved to a dedicated “instructor menu”, together with functionality for saving the state of the Playground on each slide. Unfortunately, the whole thing was disabled in #1935 since I found that the Playgrounds lost their code with the saving logic. I was also not 100% happy with dedicating space on each slide for a menu only used by instructors. However, I really think we need a tool to let slide editors know about the available space, so I would like to re-introduce the red box. This time via a keyboard shortcut to make it easy to toggle as needed. I’m suggesting enabling this for everyone, with the expectation that most people won’t find the shortcut and will quickly disable the box if they do (there is a dedicated button to hide it again). End-to-end tests have been added for the new functionality.
10 KiB
Project Overview
This repository contains the source code for Comprehensive Rust, a family of
courses on Rust developed by Google, starting with Rust foundations, and
including deep dives into specialized topics like Android, Chromium, bare-metal
development, and concurrency. The project is a Rust workspace that leverages
mdbook to generate a course website.
Key Technologies
- Rust: The primary programming language for the course subject, custom tools, and examples.
- mdbook: A command-line tool to create books from Markdown files, used for generating the course website.
- Custom mdbook Preprocessors:
mdbook-courseandmdbook-exerciserare Rust binaries that extendmdbook's functionality, for example, to extract exercise starter code. cargo xtask: A custom binary within the workspace used for project automation, simplifying common development tasks.
Building and Running
The project uses cargo xtask for project-specific automation, like builds,
tests, and managing translations.
Setup
- Install Rust: Follow the instructions on https://rustup.rs/.
- Clone Repository:
git clone https://github.com/google/comprehensive-rust/ cd comprehensive-rust - Install Project Tools:
This is a necessary first step for working with this repository. It will install the correct versions of all tools used by the project.
cargo xtask install-tools
Commands
All commands are run using cargo xtask. Run cargo xtask --help for a full
list of options.
-
Serve the Course Locally: Starts a web server to view the course content.
cargo xtask serve [--language <ISO_639_language_code>] [--output <output_directory>](e.g.,
cargo xtask serve -l dafor the Danish translation) -
Build the Course: Creates a static version of the course in the
book/directory.cargo xtask build [--language <ISO_639_language_code>] [--output <output_directory>] -
Run Rust Snippet Tests: Tests all Rust code snippets included in the course material.
cargo xtask rust-tests -
Run Web Driver Tests: Executes web driver tests located in the
tests/directory.cargo xtask web-tests [--dir <book_html_directory>]
Development Conventions
- Project Automation:
cargo xtaskis the primary interface for common development tasks. - Course Content: Markdown files in the
src/directory, structured according tosrc/SUMMARY.md. - Code Formatting:
dprint fmtis used to format all source files according torustfmt.tomlanddprint.json. Note that you must first install the project tools withcargo xtask install-tools. - Contributions: Refer to
CONTRIBUTING.mdfor guidelines on contributing to the project. - Style: Refer to
STYLE.mdfor style guidelines. When making changes to Markdown files insrc/, always first readSTYLE.mdand follow its conventions. - GitHub Actions: The project uses composite GitHub Actions to simplify CI
workflows. These actions should be preferred over hand-written commands.
apt-get-install: This action efficiently installs Debian packages. It configuresdpkgandaptto skip documentation and translations, and ensures thatapt-get updateis run only once per job. This significantly speeds up CI runs.install-mdbook: A composite action to installmdbookand its dependencies, includingpandocandtexlive.setup-rust-cache: A composite action that configures theSwatinem/rust-cacheaction.
Markdown Conventions
-
Headings:
- H1 (
#): Used for the main title of each page. Each slide has exactly one title. - H2 (
##): Used for major sections. Slides do not use H2 headings to save vertical space; more slides are created instead. - H3 (
###): Used for sub-sections, but not on slides.
- H1 (
-
Emphasis:
- Bold (
**...**): Used to highlight key terms, commands, and for notes (e.g.,**Note:**). The colon (:) is included inside the bold text for notes. - Italic (
_..._): Used for general emphasis, titles of external articles, and for terms being defined.
- Bold (
-
Code:
- Inline Code (
`...`): Used for code snippets, file names, commands, type names, and language keywords. Rust fragments are formatted asrustfmtwould. - Code Blocks (
```...```): Fenced code blocks are used for multi-line code examples, annotated with a language identifier (e.g.,rust,c,ignore). - Interactive Code Blocks: Rust examples are made interactive with
editable. Examples that fail to compile are marked withcompile_failorshould_panic. - Diagrams: The
boblanguage identifier is used in code blocks to generate ASCII art diagrams. - Formatting Control: The
#[rustfmt::skip]attribute is used to preventrustfmtfrom formatting specific code blocks, though it is used rarely.
- Inline Code (
-
Lists:
- Bulleted Lists: Unordered lists are the primary way to lay out key points on slides.
- Glossary Format: The glossary uses a specific format with a colon and
backslash (
:\) after each term to create a hard line break for visual formatting.
-
Other Markdown Elements:
- Block Quotes (
> ...): Used sparingly for important notes, warnings, or supplementary information to draw attention. - Links: Both standard (
[text](url)) and reference-style ([text][label]) links are used. - Tables: Markdown tables are used to present structured data.
- Horizontal Rules (
---): Not used on slides.
- Block Quotes (
-
HTML Tags:
<details>: Used for collapsible "speaker notes".<kbd>: Used to denote keyboard keys. Each key in a combination must be wrapped in its own tag, e.g.,<kbd>Ctrl</kbd> + <kbd>S</kbd>.<style>: Used rarely for targeted custom CSS.<img>: Used to embed images.
-
Project-Specific Conventions:
- mdbook Includes: The
{{#include ...}}helper is used to include snippets from other files. - mdbook Segments: The
{{%segment ...%}}and{{%session ...%}}helpers are used for course structuring. - Frontmatter: Files start with YAML frontmatter (enclosed in
---) to provide metadata. - Doc Comments: Standard Rust doc comments (
///,//!) are used./// # Safetyis used to document safety preconditions forunsafecode. - Comments: HTML comments (
<!-- ... -->) are used for editor/translator instructions and content control (e.g.,mdbook-xgettext: skip).
- mdbook Includes: The
Project-Specific Technical Context
This section contains critical, non-obvious technical details about this project's tooling and environment that an AI assistant needs to know to perform its tasks correctly.
mdbook Behavior
- Isolated Code Snippets:
mdbooktreats each fenced Rust code block (e.g.,```rust ... ```) as a separate compilation unit. When analyzing a code snippet, treat it as a self-contained program. Do not assume it shares a scope or context with other snippets in the same file unless the surrounding text explicitly states otherwise.
Interacting with the mdbook Theme
The mdbook theme has several interactive elements. Here's how to interact with
them:
-
Sidebar Toggle: The sidebar can be opened and closed by clicking the "hamburger" button in the top-left of the body text. This button has the ID
sidebar-toggle. You can use the following JavaScript to toggle the sidebar:const button = document.getElementById("sidebar-toggle"); button.click();
WebdriverIO Testing
This project uses WebdriverIO for browser-based integration tests. Here are some key findings about the test environment:
Test Environments
The tests/ directory contains two primary configurations:
npm test(runswdio.conf.ts): This is the standard for self-contained integration tests. It uses@wdio/static-server-serviceto create a temporary web server on port 8080.npm run test-mdbook(runswdio.conf-mdbook.ts): This is for testing against a livemdbook serveinstance, which typically runs on port 3000.
It is important to use the standard npm test command for most test development
to ensure the tests are self-contained.
Writing Stable Tests
Tests can be flaky if they don't correctly handle the asynchronous nature of the web browser and the test environment's state management.
-
State Leakage Between Tests: Despite what the WebdriverIO documentation might suggest,
browser.url()is not always sufficient to guarantee a clean slate between tests. Lingering state, such as inline CSS styles applied by JavaScript, can leak from one test into the next, causing unexpected failures. The most effective solution found for this project is to addawait browser.refresh();to thebeforeEachhook. This forces a full page reload that properly clears the old state. -
Race Conditions with Dynamic Elements: Many elements in this project are created dynamically by JavaScript after the initial page load. If a test tries to access an element immediately after navigation, it may fail because the script hasn't finished running and the element doesn't exist in the DOM yet. This creates a race condition. To prevent this, always use
await element.waitForExist()to ensure the element is present before trying to interact with it or assert its state (e.g.,toBeDisplayed()).
Handling Redirects
mdbook uses a redirect map defined in book.toml under the
[output.html.redirect] section. When writing tests, it is crucial to use the
final, non-redirecting URL for navigation. Navigating to a URL that is a
redirect will cause the browser to follow it, but this process can strip URL
query parameters, leading to test failures for features that depend on them.
Running and Debugging Tests
To run a single test file, use the --spec flag with the a string matching the
file name:
npm test -- --spec redbox
To check for flakiness, you can repeat a test multiple times using the
--repeat flag:
npm test -- --spec redbox --repeat 100
Use --mochaOpts.grep to run a single test within a file:
npm test -- --spec redbox --mochaOpts.grep "should be hidden by default"