diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index 9bdcf80fc585dd..db36a0248bcf17 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -1,4 +1,4 @@
-name: mkdocs
+name: mdbook
on:
release:
@@ -6,7 +6,7 @@ on:
workflow_dispatch:
jobs:
- mkdocs:
+ mdbook:
runs-on: ubuntu-latest
env:
CF_API_TOKEN_EXISTS: ${{ secrets.CF_API_TOKEN != '' }}
@@ -18,16 +18,16 @@ jobs:
- uses: Swatinem/rust-cache@v1
- name: "Install dependencies"
run: |
- pip install -r docs/requirements.txt
- - name: "Copy README File"
+ cargo install mdbook
+ - name: "Generate the website"
run: |
python scripts/transform_readme.py --target mkdocs
- python scripts/generate_mkdocs.py
- mkdocs build --strict
+ python scripts/generate_book.py
+ cd docs && mdbook build
- name: "Deploy to Cloudflare Pages"
if: ${{ env.CF_API_TOKEN_EXISTS == 'true' }}
uses: cloudflare/wrangler-action@2.0.0
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
accountId: ${{ secrets.CF_ACCOUNT_ID }}
- command: pages publish site --project-name=ruff-docs --branch ${GITHUB_HEAD_REF} --commit-hash ${GITHUB_SHA}
+ command: pages publish docs/book/ --project-name=ruff-docs --branch ${GITHUB_HEAD_REF} --commit-hash ${GITHUB_SHA}
diff --git a/.gitignore b/.gitignore
index e13e01999aa0c2..2a0d0255d12459 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
# Local cache
.ruff_cache
crates/ruff/resources/test/cpython
-mkdocs.yml
.overrides
###
@@ -160,9 +159,6 @@ venv.bak/
# Rope project settings
.ropeproject
-# mkdocs documentation
-/site
-
# mypy
.mypy_cache/
.dmypy.json
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 812f12b610e119..445681e340d13e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -9,7 +9,7 @@ Welcome! We're happy to have you here. Thank you in advance for your contributio
- [Example: Adding a new lint rule](#example-adding-a-new-lint-rule)
- [Rule naming convention](#rule-naming-convention)
- [Example: Adding a new configuration option](#example-adding-a-new-configuration-option)
-- [MkDocs](#mkdocs)
+- [mdBook](#mdbook)
- [Release Process](#release-process)
- [Benchmarks](#benchmarks)
@@ -181,21 +181,21 @@ lives in `crates/ruff/src/flake8_to_ruff/converter.rs`.
Finally, regenerate the documentation and generated code with `cargo dev generate-all`.
-## MkDocs
+## mdBook
To preview any changes to the documentation locally:
-1. Install MkDocs and Material for MkDocs with:
+1. Install mdBook with:
```shell
- pip install -r docs/requirements.txt
+ cargo install mdbook
```
-2. Generate the MkDocs site with:
+2. Generate the markdown files with:
```shell
- python scripts/generate_mkdocs.py
+ python scripts/generate_book.py
```
3. Run the development server with:
```shell
- mkdocs serve
+ cd docs && mdbook serve
```
The documentation should then be available locally at
diff --git a/crates/ruff_dev/src/generate_docs.rs b/crates/ruff_dev/src/generate_docs.rs
index e95c74aa7ba69c..a6ca7e1f90c110 100644
--- a/crates/ruff_dev/src/generate_docs.rs
+++ b/crates/ruff_dev/src/generate_docs.rs
@@ -19,7 +19,7 @@ pub struct Args {
}
pub fn main(args: &Args) -> Result<()> {
- let out_dir = Path::new("docs/rules");
+ let out_dir = Path::new("docs/src/rules");
if !args.dry_run {
fs::create_dir_all(out_dir)?;
}
@@ -74,7 +74,7 @@ fn process_documentation(documentation: &str, out: &mut String) {
let anchor = option.rsplit('.').next().unwrap();
out.push_str(&format!("* [`{option}`]\n"));
- after.push_str(&format!("[`{option}`]: ../../settings#{anchor}"));
+ after.push_str(&format!("[`{option}`]: ../settings.html#{anchor}"));
continue;
}
diff --git a/docs/.gitignore b/docs/.gitignore
index 8efd6c8dd091cd..5145b03f7acd93 100644
--- a/docs/.gitignore
+++ b/docs/.gitignore
@@ -1,3 +1,2 @@
-*
-!assets
-!requirements.txt
+book
+src
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
new file mode 100644
index 00000000000000..b4a5475efac411
--- /dev/null
+++ b/docs/SUMMARY.md
@@ -0,0 +1,10 @@
+# Summary
+
+- [Overview](./index.md)
+- [Installation And Usage](./installation-and-usage.md)
+- [Configuration](./configuration.md)
+- [Rules](./rules.md)
+- [Settings](./settings.md)
+- [Editor Integrations](./editor-integrations.md)
+- [FAQ](./faq.md)
+- [Contributing](./contributing.md)
diff --git a/docs/book.toml b/docs/book.toml
new file mode 100644
index 00000000000000..e25a008e6e0df1
--- /dev/null
+++ b/docs/book.toml
@@ -0,0 +1,13 @@
+[book]
+authors = ["The Ruff Developers"]
+language = "en"
+multilingual = false
+src = "src"
+title = "Ruff Documentation"
+
+[output.html]
+git-repository-url = "https://github.com/charliermarsh/ruff"
+
+[output.html.fold]
+enable = true
+level = 0
diff --git a/docs/requirements.txt b/docs/requirements.txt
deleted file mode 100644
index b5b1417243b463..00000000000000
--- a/docs/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-mkdocs~=1.4.2
-mkdocs-material~=9.0.6
-PyYAML~=6.0
diff --git a/docs/assets/ruff-favicon.png b/docs/theme/favicon.png
similarity index 100%
rename from docs/assets/ruff-favicon.png
rename to docs/theme/favicon.png
diff --git a/docs/theme/head.hbs b/docs/theme/head.hbs
new file mode 100644
index 00000000000000..340d60d8162c10
--- /dev/null
+++ b/docs/theme/head.hbs
@@ -0,0 +1 @@
+
diff --git a/mkdocs.template.yml b/mkdocs.template.yml
deleted file mode 100644
index 4ce6d30a39cefc..00000000000000
--- a/mkdocs.template.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-site_name: Ruff
-theme:
- name: material
- logo: assets/ruff.svg
- favicon: assets/ruff-favicon.png
- features:
- - navigation.instant
- - navigation.tracking
- - content.code.annotate
- - toc.integrate
- - toc.follow
- - navigation.path
- - navigation.top
- - navigation.footer
- - content.code.copy
- palette:
- - media: "(prefers-color-scheme: light)"
- scheme: default
- primary: red
- toggle:
- icon: material/weather-sunny
- name: Switch to dark mode
- - media: "(prefers-color-scheme: dark)"
- scheme: slate
- primary: red
- toggle:
- icon: material/weather-night
- name: Switch to light mode
- custom_dir: .overrides
-repo_url: https://github.com/charliermarsh/ruff
-repo_name: ruff
-site_author: charliermarsh
-site_url: https://beta.ruff.rs/docs/
-site_dir: site/docs
-markdown_extensions:
- - toc:
- permalink: "#"
- - pymdownx.snippets:
- - pymdownx.magiclink:
- - attr_list:
- - md_in_html:
- - pymdownx.highlight:
- anchor_linenums: true
- - pymdownx.inlinehilite:
- - pymdownx.superfences:
- - markdown.extensions.attr_list:
- - pymdownx.keys:
- - pymdownx.tasklist:
- custom_checkbox: true
- - pymdownx.highlight:
- anchor_linenums: true
-plugins:
- - search
diff --git a/scripts/generate_mkdocs.py b/scripts/generate_book.py
similarity index 59%
rename from scripts/generate_mkdocs.py
rename to scripts/generate_book.py
index 71f6ddc136c278..502baf41b34544 100644
--- a/scripts/generate_mkdocs.py
+++ b/scripts/generate_book.py
@@ -1,11 +1,9 @@
-"""Generate an MkDocs-compatible `docs` and `mkdocs.yml` from the README.md."""
+"""Generate the Markdown files for mdbook in `docs/src`."""
import argparse
import shutil
import subprocess
from pathlib import Path
-import yaml
-
SECTIONS: list[tuple[str, str]] = [
("Overview", "index.md"),
("Installation and Usage", "installation-and-usage.md"),
@@ -20,14 +18,9 @@
"This README is also available as [documentation](https://beta.ruff.rs/docs/)."
)
-FATHOM_SCRIPT: str = (
- '"
-)
-
def main() -> None:
- """Generate an MkDocs-compatible `docs` and `mkdocs.yml`."""
+ """Generate the Markdown files for mdbook in `docs/src`."""
subprocess.run(["cargo", "dev", "generate-docs"], check=True)
@@ -46,12 +39,24 @@ def main() -> None:
"rules/",
)
- docs_path = Path("docs")
+ docs_path = Path("docs/src")
docs_path.mkdir(parents=True, exist_ok=True)
+ with (docs_path.parent / "SUMMARY.md").open("r") as f:
+ text = f.read()
+
+ rules_item = "- [Rules](./rules.md)\n"
+ assert rules_item in text
+ rule_items = (f" - [{f.stem}](rules/{f.name})\n" for f in sorted(docs_path.joinpath("rules").iterdir()))
+ text = text.replace(rules_item, rules_item + "".join(rule_items))
+
+ with (docs_path / "SUMMARY.md").open("w") as f:
+ f.write(text)
+
# Split the README.md into sections.
for title, filename in SECTIONS:
with docs_path.joinpath(filename).open("w+") as f:
+ f.write(f"# {title}\n")
block = content.split(f"")
if len(block) != 2:
msg = f"Section {title} not found in README.md"
@@ -67,37 +72,10 @@ def main() -> None:
# Copy the CONTRIBUTING.md.
shutil.copy("CONTRIBUTING.md", docs_path / "contributing.md")
- # Add the nav section to mkdocs.yml.
- with Path("mkdocs.template.yml").open(encoding="utf8") as fp:
- config = yaml.safe_load(fp)
- config["nav"] = [
- {"Overview": "index.md"},
- {"Installation and Usage": "installation-and-usage.md"},
- {"Configuration": "configuration.md"},
- {"Rules": "rules.md"},
- {"Settings": "settings.md"},
- {"Editor Integrations": "editor-integrations.md"},
- {"FAQ": "faq.md"},
- {"Contributing": "contributing.md"},
- ]
- config["extra"] = {"analytics": {"provider": "fathom"}}
-
- Path(".overrides/partials/integrations/analytics").mkdir(
- parents=True,
- exist_ok=True,
- )
- with Path(".overrides/partials/integrations/analytics/fathom.html").open(
- "w+",
- ) as fp:
- fp.write(FATHOM_SCRIPT)
-
- with Path("mkdocs.yml").open("w+") as fp:
- yaml.safe_dump(config, fp)
-
if __name__ == "__main__":
parser = argparse.ArgumentParser(
- description="Generate an MkDocs-compatible `docs` and `mkdocs.yml`.",
+ description=__doc__,
)
args = parser.parse_args()
main()