Skip to content

Website #2247

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

Merged
merged 36 commits into from
May 23, 2025
Merged

Website #2247

Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5927a78
Remove Oranda
mo8it May 16, 2025
08548ab
Remove .editorconfig
mo8it May 16, 2025
a28000a
Remove markdown lint
mo8it May 16, 2025
74ab992
Start with Zola
mo8it May 16, 2025
7ec6986
Add templates
mo8it May 16, 2025
fda18e8
Add Ferris SVGs
mo8it May 17, 2025
61c17cb
Change syntax highlighting theme
mo8it May 17, 2025
7e26418
Remove the third-party exercises file
mo8it May 17, 2025
b9d1e63
Reduce the README to the website link
mo8it May 17, 2025
6d5369d
Add more menu and footer items
mo8it May 17, 2025
2673177
Update header and footer
mo8it May 17, 2025
3d8bef4
Remove landscape mode recommendation
mo8it May 17, 2025
b30973a
Compress the intro
mo8it May 17, 2025
f387f4c
Add setup and usage pages
mo8it May 17, 2025
69fe962
Update base URL
mo8it May 17, 2025
23b9aa3
Move Q/A menu item
mo8it May 17, 2025
8339007
Update setup and usage
mo8it May 17, 2025
984e9fe
Merge branch 'main'
mo8it May 17, 2025
b4a6b87
Less padding
mo8it May 17, 2025
2f70099
Remove macros
mo8it May 17, 2025
8fa598a
Add details shortcode
mo8it May 17, 2025
5fc787f
Style details body
mo8it May 17, 2025
dc46888
Highlight platform
mo8it May 17, 2025
8c24763
Q/A -> Q&A
mo8it May 17, 2025
f6a657a
Finish the usage page
mo8it May 17, 2025
a51d6f1
third-party/custom -> community
mo8it May 17, 2025
54a74fd
Use internal links for validation
mo8it May 17, 2025
69a9e9c
Less top margin for blockquotes
mo8it May 17, 2025
512ded8
Done community exercises page
mo8it May 17, 2025
596e7f3
Add website CI
mo8it May 17, 2025
47e490a
Run rustywind
mo8it May 17, 2025
edc8528
Improve CI
mo8it May 19, 2025
04520ae
Use the website link as header
mo8it May 19, 2025
f80c2ed
Remove fnm
mo8it May 23, 2025
adf3ddd
Remove rustywind from dev deps
mo8it May 23, 2025
bf74a3d
Update the README with more context before the website link
mo8it May 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions .editorconfig

This file was deleted.

16 changes: 10 additions & 6 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
name: Rustlings Tests
name: Check

on:
push:
branches: [main]
paths-ignore:
- website
- '*.md'
pull_request:
branches: [main]
paths-ignore:
- website
- '*.md'

env:
CARGO_TERM_COLOR: always
@@ -14,14 +20,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: cargo clippy -- --deny warnings
- name: Clippy
run: cargo clippy -- --deny warnings
fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DavidAnson/markdownlint-cli2-action@v16
with:
globs: "exercises/**/*.md"
- name: rustfmt
run: cargo fmt --all --check
test:
@@ -40,4 +44,4 @@ jobs:
- uses: actions/checkout@v4
- uses: swatinem/rust-cache@v2
- name: rustlings dev check
run: cargo run -- dev check --require-solutions
run: cargo dev check --require-solutions
87 changes: 0 additions & 87 deletions .github/workflows/web.yml

This file was deleted.

42 changes: 42 additions & 0 deletions .github/workflows/website.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Website

on:
push:
branches: [main]
paths: [website]

jobs:
build:
defaults:
run:
working-directory: website
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install TailwindCSS
run: npm install
- name: Build CSS
run: npx @tailwindcss/cli -m -i input.css -o static/main.css
- name: Download Zola
run: curl -fsSL https://github.com/getzola/zola/releases/download/v0.20.0/zola-v0.20.0-x86_64-unknown-linux-gnu.tar.gz | tar xz
- name: Build site
run: ./zola build
- name: Upload static files as artifact
uses: actions/upload-pages-artifact@v3
with:
path: public/

deploy:
needs: build
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
# Deploy to the github-pages environment
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v4
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -6,10 +6,6 @@ Cargo.lock
# State file
.rustlings-state.txt

# oranda
public/
.netlify

# OS
.DS_Store
.direnv/
2 changes: 0 additions & 2 deletions .markdownlint.yml

This file was deleted.

100 changes: 5 additions & 95 deletions CHANGELOG.md

Large diffs are not rendered by default.

166 changes: 4 additions & 162 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,165 +1,7 @@
<div class="oranda-hide">
# [Rustlings](https://rustlings.rust-lang.org) 🦀

# Rustlings 🦀❤️
Small exercises to get you used to reading and writing [Rust](https://www.rust-lang.org) code - _Recommended in parallel to reading [the official Rust book](https://doc.rust-lang.org/book) 📚️_

</div>
Visit the **website** for a demo, info about setup and more:

Greetings and welcome to Rustlings.
This project contains small exercises to get you used to reading and writing Rust code.
This includes reading and responding to compiler messages!

It is recommended to do the Rustlings exercises in parallel to reading [the official Rust book](https://doc.rust-lang.org/book/), the most comprehensive resource for learning Rust 📚️

[Rust By Example](https://doc.rust-lang.org/rust-by-example/) is another recommended resource that you might find helpful.
It contains code examples and exercises similar to Rustlings, but online.

## Getting Started

### Installing Rust

Before installing Rustlings, you need to have the **latest version of Rust** installed.
Visit [www.rust-lang.org/tools/install](https://www.rust-lang.org/tools/install) for further instructions on installing Rust.
This will also install _Cargo_, Rust's package/project manager.

> 🐧 If you are on Linux, make sure you have installed `gcc` (for a linker).
>
> Deb: `sudo apt install gcc`
>
> Dnf: `sudo dnf install gcc`
> 🍎 If you are on MacOS, make sure you have installed Xcode and its developer tools by running `xcode-select --install`.
### Installing Rustlings

The following command will download and compile Rustlings:

```bash
cargo install rustlings
```

<details>
<summary><strong>If the installation fails…</strong> (<em>click to expand</em>)</summary>

- Make sure you have the latest Rust version by running `rustup update`
- Try adding the `--locked` flag: `cargo install rustlings --locked`
- Otherwise, please [report the issue](https://github.com/rust-lang/rustlings/issues/new)

</details>

### Initialization

After installing Rustlings, run the following command to initialize the `rustlings/` directory:

```bash
rustlings init
```

<details>
<summary><strong>If the command <code>rustlings</code> can't be found…</strong> (<em>click to expand</em>)</summary>

You are probably using Linux and installed Rust using your package manager.

Cargo installs binaries to the directory `~/.cargo/bin`.
Sadly, package managers often don't add `~/.cargo/bin` to your `PATH` environment variable.

The solution is to …

- either add `~/.cargo/bin` manually to `PATH`
- or to uninstall Rust from the package manager and install it using the official way with `rustup`: https://www.rust-lang.org/tools/install

</details>

Now, go into the newly initialized directory and launch Rustlings for further instructions on getting started with the exercises:

```bash
cd rustlings/
rustlings
```

## Working environment

### Editor

Our general recommendation is [VS Code](https://code.visualstudio.com/) with the [rust-analyzer plugin](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
But any editor that supports [rust-analyzer](https://rust-analyzer.github.io/) should be enough for working on the exercises.

### Terminal

While working with Rustlings, please use a modern terminal for the best user experience.
The default terminal on Linux and Mac should be sufficient.
On Windows, we recommend the [Windows Terminal](https://aka.ms/terminal).

## Doing exercises

The exercises are sorted by topic and can be found in the subdirectory `exercises/<topic>`.
For every topic, there is an additional `README.md` file with some resources to get you started on the topic.
We highly recommend that you have a look at them before you start 📚️

Most exercises contain an error that keeps them from compiling, and it's up to you to fix it!
Some exercises contain tests that need to pass for the exercise to be done ✅

Search for `TODO` and `todo!()` to find out what you need to change.
Ask for hints by entering `h` in the _watch mode_ 💡

### Watch Mode

After the [initialization](#initialization), Rustlings can be launched by simply running the command `rustlings`.

This will start the _watch mode_ which walks you through the exercises in a predefined order (what we think is best for newcomers).
It will rerun the current exercise automatically every time you change the exercise's file in the `exercises/` directory.

<details>
<summary><strong>If detecting file changes in the <code>exercises/</code> directory fails…</strong> (<em>click to expand</em>)</summary>

> You can add the **`--manual-run`** flag (`rustlings --manual-run`) to manually rerun the current exercise by entering `r` in the watch mode.
>
> Please [report the issue](https://github.com/rust-lang/rustlings/issues/new) with some information about your operating system and whether you run Rustlings in a container or virtual machine (e.g. WSL).
</details>

### Exercise List

In the [watch mode](#watch-mode) (after launching `rustlings`), you can enter `l` to open the interactive exercise list.

The list allows you to…

- See the status of all exercises (done or pending)
- `c`: Continue at another exercise (temporarily skip some exercises or go back to a previous one)
- `r`: Reset status and file of the selected exercise (you need to _reload/reopen_ its file in your editor afterwards)

See the footer of the list for all possible keys.

## Questions?

If you need any help while doing the exercises and the builtin-hints aren't helpful, feel free to ask in the [_Q&A_ category of the discussions](https://github.com/rust-lang/rustlings/discussions/categories/q-a?discussions_q=) if your question wasn't asked yet 💡

## Third-Party Exercises

Third-party exercises are a set of exercises maintained by the community.
You can use the same `rustlings` program that you installed with `cargo install rustlings` to run them:

- 🇯🇵 [Japanese Rustlings](https://github.com/sotanengel/rustlings-jp):A Japanese translation of the Rustlings exercises.
- 🇨🇳 [Simplified Chinese Rustlings](https://github.com/SandmeyerX/rustlings-zh-cn): A simplified Chinese translation of the Rustlings exercises.

Do you want to create your own set of Rustlings exercises to focus on some specific topic?
Or do you want to translate the original Rustlings exercises?
Then follow the the guide about [third-party exercises](https://github.com/rust-lang/rustlings/blob/main/THIRD_PARTY_EXERCISES.md)!

## Continuing On

Once you've completed Rustlings, put your new knowledge to good use!
Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to.

## Uninstalling Rustlings

If you want to remove Rustlings from your system, run the following command:

```bash
cargo uninstall rustlings
```

## Contributing

See [CONTRIBUTING.md](https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md) 🔗

Thanks to [all the wonderful contributors](https://github.com/rust-lang/rustlings/graphs/contributors)
## ➡️ [rustlings.rust-lang.org](https://rustlings.rust-lang.org) ⬅️
53 changes: 0 additions & 53 deletions THIRD_PARTY_EXERCISES.md

This file was deleted.

13 changes: 0 additions & 13 deletions oranda.json

This file was deleted.

4 changes: 2 additions & 2 deletions src/app_state.rs
Original file line number Diff line number Diff line change
@@ -315,7 +315,7 @@ impl AppState {
}

// Official exercises: Dump the original file from the binary.
// Third-party exercises: Reset the exercise file with `git stash`.
// Community exercises: Reset the exercise file with `git stash`.
fn reset(&self, exercise_ind: usize, path: &str) -> Result<()> {
if self.official_exercises {
return EMBEDDED_FILES
@@ -385,7 +385,7 @@ impl AppState {
}

/// Official exercises: Dump the solution file from the binary and return its path.
/// Third-party exercises: Check if a solution file exists and return its path in that case.
/// Community exercises: Check if a solution file exists and return its path in that case.
pub fn current_solution_path(&self) -> Result<Option<String>> {
if cfg!(debug_assertions) {
return Ok(None);
2 changes: 1 addition & 1 deletion src/dev.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ mod update;

#[derive(Subcommand)]
pub enum DevCommands {
/// Create a new project for third-party Rustlings exercises
/// Create a new project for community exercises
New {
/// The path to create the project in
path: PathBuf,
8 changes: 4 additions & 4 deletions src/dev/new.rs
Original file line number Diff line number Diff line change
@@ -86,18 +86,18 @@ target/
";

const INFO_FILE_BEFORE_FORMAT_VERSION: &str =
"# The format version is an indicator of the compatibility of third-party exercises with the
"# The format version is an indicator of the compatibility of community exercises with the
# Rustlings program.
# The format version is not the same as the version of the Rustlings program.
# In case Rustlings makes an unavoidable breaking change to the expected format of third-party
# In case Rustlings makes an unavoidable breaking change to the expected format of community
# exercises, you would need to raise this version and adapt to the new format.
# Otherwise, the newest version of the Rustlings program won't be able to run these exercises.
format_version = ";

const INFO_FILE_AFTER_FORMAT_VERSION: &str = r#"
# Optional multi-line message to be shown to users when just starting with the exercises.
welcome_message = """Welcome to these third-party Rustlings exercises."""
welcome_message = """Welcome to these community Rustlings exercises."""
# Optional multi-line message to be shown to users after finishing all exercises.
final_message = """We hope that you found the exercises helpful :D"""
@@ -141,7 +141,7 @@ publish = false

const README: &str = "# Rustlings 🦀
Welcome to these third-party Rustlings exercises 😃
Welcome to these community Rustlings exercises 😃
First, [install Rustlings using the official instructions](https://github.com/rust-lang/rustlings) ✅
4 changes: 2 additions & 2 deletions src/info_file.rs
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ impl RunnableExercise for ExerciseInfo {
/// The deserialized `info.toml` file.
#[derive(Deserialize)]
pub struct InfoFile {
/// For possible breaking changes in the future for third-party exercises.
/// For possible breaking changes in the future for community exercises.
pub format_version: u8,
/// Shown to users when starting with the exercises.
pub welcome_message: Option<String>,
@@ -91,7 +91,7 @@ pub struct InfoFile {

impl InfoFile {
/// Official exercises: Parse the embedded `info.toml` file.
/// Third-party exercises: Parse the `info.toml` file in the current directory.
/// Community exercises: Parse the `info.toml` file in the current directory.
pub fn parse() -> Result<Self> {
// Read a local `info.toml` if it exists.
let slf = match fs::read_to_string("info.toml") {
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ enum Subcommands {
/// The name of the exercise
name: Option<String>,
},
/// Commands for developing (third-party) Rustlings exercises
/// Commands for developing (community) Rustlings exercises
#[command(subcommand)]
Dev(DevCommands),
}
7 changes: 7 additions & 0 deletions website/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/node_modules/
/package-lock.json

/public/

/static/main.css
/static/processed_images/
41 changes: 41 additions & 0 deletions website/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
base_url = "https://rustlings.rust-lang.org"
title = "Rustlings"
description = "Small exercises to get you used to reading and writing Rust code!"

compile_sass = false
build_search_index = false

[markdown]
highlight_code = true
highlight_theme = "dracula"

insert_anchor_links = "heading"

[extra]
logo_path = "images/happy_ferris.svg"

[[extra.menu_items]]
name = "Rustlings"
url = "@/_index.md"
[[extra.menu_items]]
name = "Setup"
url = "@/setup/index.md"
[[extra.menu_items]]
name = "Usage"
url = "@/usage/index.md"
[[extra.menu_items]]
name = "Community Exercises"
url = "@/community-exercises/index.md"
[[extra.menu_items]]
name = "Q&A"
url = "https://github.com/rust-lang/rustlings/discussions/categories/q-a?discussions_q="

[[extra.footer_items]]
name = "Repository"
url = "https://github.com/rust-lang/rustlings"
[[extra.footer_items]]
name = "Changelog"
url = "https://github.com/rust-lang/rustlings/blob/main/CHANGELOG.md"
[[extra.footer_items]]
name = "MIT License"
url = "https://github.com/rust-lang/rustlings/blob/main/LICENSE"
21 changes: 21 additions & 0 deletions website/content/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
+++
+++

Small exercises to get you used to reading and writing [Rust](https://www.rust-lang.org) code - _Recommended in parallel to reading [the official Rust book](https://doc.rust-lang.org/book) 📚️_

<script src="https://asciinema.org/a/719805.js" id="asciicast-719805" async="true"></script>

## Quick start

```bash
# Installation
cargo install rustlings
# Initialization
rustlings init
# Moving into new directory
cd rustlings
# Starting Rustlings
rustlings
```

Visit the [**setup**](@/setup/index.md) page for more details 🧰
73 changes: 73 additions & 0 deletions website/content/community-exercises/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
+++
title = "Community Exercises"
+++

## List of Community Exercises

- 🇯🇵 [Japanese Rustlings](https://github.com/sotanengel/rustlings-jp):A Japanese translation of the Rustlings exercises.
- 🇨🇳 [Simplified Chinese Rustlings](https://github.com/SandmeyerX/rustlings-zh-cn): A simplified Chinese translation of the Rustlings exercises.

> You can use the same `rustlings` program that you installed with `cargo install rustlings` to run community exercises.
## Creating Community Exercises

Rustling's support for community exercises allows you to create your own exercises to focus on some specific topic.
You could also offer a translation of the original Rustlings exercises as community exercises.

### Getting Started

To create community exercises, install Rustlings and run `rustlings dev new PROJECT_NAME`.
This command will, similar to `cargo new PROJECT_NAME`, create the template directory `PROJECT_NAME` with all what you need to get started.

_Read the comments_ in the generated `info.toml` file to understand its format.
It allows you to set a custom welcome and final message and specify the metadata of every exercise.

### Creating an Exercise

Here is an example of the metadata of one exercise:

```toml
[[exercises]]
name = "intro1"
hint = """
To finish this exercise, you need to …
These links might help you …"""
```

After entering this in `info.toml`, create the file `intro1.rs` in the `exercises/` directory.
The exercise needs to contain a `main` function, but it can be empty.
Adding tests is recommended.
Look at the official Rustlings exercises for inspiration.

You can optionally add a solution file `intro1.rs` to the `solutions/` directory.

Now, run `rustlings dev check`.
It will tell you about any issues with your exercises.
For example, it will tell you to run `rustlings dev update` to update the `Cargo.toml` file to include the new exercise `intro1`.

`rustlings dev check` will also run your solutions (if you have any) to make sure that they run successfully.

That's it!
You finished your first exercise 🎉

### Cargo.toml

Except of the `bin` list, you can modify the `Cargo.toml` file as you want.

> The `bin` list is automatically updated by running `rustlings dev update`
- You can add dependencies in the `[dependencies]` table.
- You might want to [configure some lints](https://doc.rust-lang.org/cargo/reference/manifest.html#the-lints-section) for all exercises. You can do so in the `[lints.rust]` and `[lints.clippy]` tables.

### Publishing

Now, add more exercises and publish them as a Git repository.

Users just have to clone that repository and run `rustlings` in it to start working on your exercises (just like the official ones).

One difference to the official exercises is that the solution files will not be hidden until the user finishes an exercise.
But you can trust your users to not open the solution too early 😉

### Sharing

After publishing your community exercises, open an issue or a pull request in the [official Rustlings repository](https://github.com/rust-lang/rustlings) to add your project to the [list of community exercises](#list-of-community-exercises) 😃
78 changes: 78 additions & 0 deletions website/content/setup/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
+++
title = "Setup"
+++

<!-- toc -->

## Installing Rust

Before installing Rustlings, you must have the **latest version of Rust** installed.
Visit [www.rust-lang.org/tools/install](https://www.rust-lang.org/tools/install) for further instructions.
This will also install _Cargo_, Rust's package/project manager.

> 🐧 If you are on **Linux**, make sure you have `gcc` installed (_for a linker_).
>
> Debian: `sudo apt install gcc`\
> Fedora: `sudo dnf install gcc`
> 🍎 If you are on **MacOS**, make sure you have _Xcode and its developer tools_ installed: `xcode-select --install`
## Installing Rustlings

The following command will download and compile Rustlings:

```bash
cargo install rustlings
```

{% details(summary="If the installation fails…") %}

- Make sure you have the latest Rust version by running `rustup update`
- Try adding the `--locked` flag: `cargo install rustlings --locked`
- Otherwise, please [report the issue](https://github.com/rust-lang/rustlings/issues/new)

{% end %}

## Initialization

After installing Rustlings, run the following command to initialize the `rustlings/` directory:

```bash
rustlings init
```

{% details(summary="If the command <code>rustlings</code> can't be found…") %}

You are probably using Linux and installed Rust using your package manager.

Cargo installs binaries to the directory `~/.cargo/bin`.
Sadly, package managers often don't add `~/.cargo/bin` to your `PATH` environment variable.

- Either add `~/.cargo/bin` manually to `PATH`
- Or uninstall Rust from the package manager and [install it using the official way with `rustup`](https://www.rust-lang.org/tools/install)

{% end %}

Now, go into the newly initialized directory and launch Rustlings for further instructions on getting started with the exercises:

```bash
cd rustlings/
rustlings
```

## Working environment

### Editor

Our general recommendation is [VS Code](https://code.visualstudio.com/) with the [rust-analyzer plugin](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
But any editor that supports [rust-analyzer](https://rust-analyzer.github.io/) should be enough for working on the exercises.

### Terminal

While working with Rustlings, please use a modern terminal for the best user experience.
The default terminal on Linux and Mac should be sufficient.
On Windows, we recommend the [Windows Terminal](https://aka.ms/terminal).

## Usage

After being done with the setup, visit the [**usage**](@/usage/index.md) page for some info about using Rustlings 🚀
55 changes: 55 additions & 0 deletions website/content/usage/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
+++
title = "Usage"
+++

<!-- toc -->

## Doing exercises

The exercises are sorted by topic and can be found in the subdirectory `exercises/<topic>`.
For every topic, there is an additional `README.md` file with some resources to get you started on the topic.
We highly recommend that you have a look at them before you start 📚️

Most exercises contain an error that keeps them from compiling, and it's up to you to fix it!
Some exercises contain tests that need to pass for the exercise to be done ✅

Search for `TODO` and `todo!()` to find out what you need to change.
Ask for hints by entering `h` in the _watch mode_ 💡

## Watch Mode

After the [initialization](@/setup/index.md#initialization), Rustlings can be launched by simply running the command `rustlings`.

This will start the _watch mode_ which walks you through the exercises in a predefined order (what we think is best for newcomers).
It will rerun the current exercise automatically every time you change the exercise's file in the `exercises/` directory.

{% details(summary="If detecting file changes in the <code>exercises/</code> directory fails…") %}

You can add the **`--manual-run`** flag (`rustlings --manual-run`) to manually rerun the current exercise by entering `r` in the watch mode.

Please [report the issue](https://github.com/rust-lang/rustlings/issues/new) with some information about your operating system and whether you run Rustlings in a container or a virtual machine (e.g. WSL).

{% end %}

## Exercise List

In the [watch mode](#watch-mode) (after launching `rustlings`), you can enter `l` to open the interactive exercise list.

The list allows you to…

- See the status of all exercises (done or pending)
- `c`: Continue at another exercise (temporarily skip some exercises or go back to a previous one)
- `r`: Reset status and file of the selected exercise (you need to _reload/reopen_ its file in your editor afterwards)

See the footer of the list for all possible keys.

## Questions?

If you need any help while doing the exercises and the builtin hints aren't helpful, feel free to ask in the [_Q&A_ discussions](https://github.com/rust-lang/rustlings/discussions/categories/q-a?discussions_q=) if your question isn't answered there 💡

## Continuing On

Once you've completed Rustlings, put your new knowledge to good use!
Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to.

> If you want to create your own Rustlings exercises, visit the [**community exercises**](@/community-exercises/index.md) page 🏗️
54 changes: 54 additions & 0 deletions website/input.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@import 'tailwindcss';

@layer base {
h1 {
@apply text-4xl mt-3 mb-3 font-bold;
}
h2 {
@apply text-3xl mt-4 mb-1.5 font-bold;
}
h3 {
@apply text-2xl mt-5 mb-1.5 font-bold;
}
h4 {
@apply text-xl mt-6 mb-1.5 font-bold;
}
p {
@apply mb-2;
}
a {
@apply text-[#FFC832] underline hover:decoration-orange-400 transition duration-300;
}
ul {
@apply mt-2 mb-3 ml-1 list-disc list-inside marker:text-sky-600;
}
ol {
@apply mt-2 mb-3 ml-1 list-decimal list-inside marker:text-sky-500;
}
li {
@apply my-0.5;
}
code {
@apply bg-white/10 px-1 pb-px pt-1 rounded-md;
}
pre code {
@apply bg-inherit p-0 text-inherit;
}
hr {
@apply my-5 rounded-full;
}
img {
@apply md:w-3/4 lg:w-3/5;
}
blockquote {
@apply px-3 pt-2 pb-0.5 mb-4 mt-2 border-s-4 border-white/80 bg-white/7 rounded-sm;
}

pre {
@apply px-2 pt-2 pb-px overflow-x-auto text-sm sm:text-base rounded-sm mt-2 mb-4 after:content-[attr(data-lang)] after:text-[8px] after:opacity-40 selection:bg-white/15;
}
pre code mark {
@apply pb-0.5 pt-1 pr-px text-inherit rounded-xs;
}
}

5 changes: 5 additions & 0 deletions website/justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
zola:
zola serve --open

tailwind:
npx @tailwindcss/cli -w -i input.css -o static/main.css
5 changes: 5 additions & 0 deletions website/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"@tailwindcss/cli": "^4.1"
}
}
33 changes: 33 additions & 0 deletions website/static/images/happy_ferris.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 70 additions & 0 deletions website/static/images/panic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions website/static/images/rust_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions website/templates/404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% extends "base.html" %}

{% block content %}
<div class="flex flex-col mx-auto text-center">
<h1>DON'T PANIC!</h1>
<h2>404: Page not found!</h2>

<img class="mx-auto max-h-[50vh]"
src="{{ get_url(path='images/panic.svg') | safe }}"
alt="">

<a class="text-2xl font-bold" href="{{ get_url(path='@/_index.md') }}">Back to homepage</a>
</div>
{% endblock %}
2 changes: 2 additions & 0 deletions website/templates/anchor-link.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<a class="text-white no-underline transition-none hover:underline"
href="#{{ id }}"></a>
92 changes: 92 additions & 0 deletions website/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

{%- set timestamp = now(timestamp=true) -%}

{%- if page.title -%}
{% set_global title = page.title %}
{%- elif section.title -%}
{% set_global title = section.title %}
{%- else -%}
{% set_global title = config.title %}
{%- endif -%}

{%- if page.description -%}
{% set_global description = page.description %}
{%- elif section.description -%}
{% set_global description = section.description %}
{%- else -%}
{% set_global description = config.description %}
{%- endif -%}

{%- if page.permalink -%}
{% set_global permalink = page.permalink %}
{%- elif section.permalink -%}
{% set_global permalink = section.permalink %}
{%- endif %}

<title>{%- block title -%}{{- title -}}{%- endblock -%}</title>

<meta name="description"
content="{%- block description -%}{{- description -}}{%- endblock -%}">

<link rel="icon"
type="image/x-icon"
href="{{ get_url(path=config.extra.logo_path) | safe }}?v={{ timestamp }}">

<link href="{{ get_url(path='main.css') | safe }}?v={{ timestamp }}"
rel="stylesheet">

<meta property="og:title" content="{{ title }}">
<meta property="og:description" content="{{ description }}">
<meta property="og:image"
content="{{ get_url(path=config.extra.logo_path) | safe }}?v={{ timestamp }}">
{% if permalink %}<meta property="og:url" content="{{ permalink | safe }}">{% endif %}
</head>

<body class="flex flex-col p-2 mx-auto min-h-screen text-lg text-white break-words lg:px-5 2xl:container bg-[#2A3439]">
<header class="flex flex-col gap-x-4 items-center py-2 px-4 mb-1 rounded-sm sm:flex-row sm:rounded-full bg-black/30">
<a class="transition duration-500 hover:scale-110"
href="{{ get_url(path='@/_index.md') | safe }}"
aria-hidden="true">
<img class="w-12 h-12"
src="{{ get_url(path=config.extra.logo_path) | safe }}"
alt="">
</a>

<nav class="flex flex-col gap-x-6 items-center font-bold sm:flex-row">
{% for menu_item in config.extra.menu_items %}
{%- if menu_item.url is starting_with("@") -%}
{% set_global menu_item_url = get_url(path=menu_item.url) %}
{%- else -%}
{% set_global menu_item_url = menu_item.url %}
{%- endif %}

<a class="p-1 no-underline" href="{{ menu_item_url | safe }}">{{ menu_item.name }}</a>
{% endfor %}
</nav>
</header>

<main class="leading-relaxed">
{% block content %}{% endblock %}
</main>

<footer class="pt-2 pb-1 mt-auto text-sm text-center">
<div class="inline-flex gap-x-1.5 items-center mx-auto mt-2">
<img class="w-8 h-8"
src="{{ get_url(path='images/rust_logo.svg') | safe }}"
alt="">
<div class="italic">Rustlings is an official Rust project</div>
</div>

<nav class="flex flex-col gap-y-3 justify-around py-3 mt-3 rounded-sm sm:flex-row sm:rounded-full bg-black/30">
{% for footer_item in config.extra.footer_items %}
<a class="no-underline" href="{{ footer_item.url | safe }}">{{ footer_item.name }}</a>
{% endfor %}
</nav>
</footer>
</body>
</html>
9 changes: 9 additions & 0 deletions website/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% extends "base.html" %}

{% block content %}
<div class="m-3">
<h1>Rustlings</h1>

{{ section.content | safe }}
</div>
{% endblock %}
39 changes: 39 additions & 0 deletions website/templates/page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{% extends "base.html" %}

{% block content %}
<article>
<h1>{{ page.title }}</h1>

<div class="py-0.5 px-4 my-3 rounded-xl border-double border-s-4">
<nav>
<ul class="ml-0 list-none">
{% for parent in page.toc %}
{% if parent.level == 2 %}
<li>
{#- -#}
<a href="{{ parent.permalink | safe }}">{{ parent.title }}</a>
{#- -#}
{% if parent.children %}
<ul class="my-0 ml-5 list-none">
{% for child in parent.children %}
{% if child.level == 3 %}
<li>
{#- -#}
<a class="text-base" href="{{ child.permalink | safe }}">{{ child.title }}</a>
{#- -#}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{#- -#}
</li>
{% endif %}
{% endfor %}
</ul>
</nav>
</div>

{{ page.content | safe }}
</article>
{% endblock %}
9 changes: 9 additions & 0 deletions website/templates/shortcodes/details.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<details>
<summary>
<strong>{{ summary | safe }}</strong> (<em>click to expand</em>)
</summary>

<blockquote class="pt-1 mx-0.5 mt-1 rounded-none border-dashed border-x-3 border-b-3">
{{ body | markdown | safe }}
</blockquote>
</details>