mirror of
https://github.com/tommilligan/mdbook-admonish.git
synced 2025-12-28 06:44:38 -05:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8501c812d9 | ||
|
|
933432afb2 | ||
|
|
496e8f7c6d | ||
|
|
1877fd1731 | ||
|
|
20286b3fae | ||
|
|
8e68cf919f | ||
|
|
02640dab1f | ||
|
|
771e9c9fd8 | ||
|
|
cce9343c47 | ||
|
|
20b158966b | ||
|
|
491f9cf341 | ||
|
|
6deaf1ea2b | ||
|
|
041e5a566f | ||
|
|
99b5a235cf | ||
|
|
39edc4d92a | ||
|
|
7773213093 | ||
|
|
e888fcd021 | ||
|
|
95dc7582ad | ||
|
|
b658eb6049 | ||
|
|
623291625a | ||
|
|
4dad5a86c8 | ||
|
|
7e774f4655 | ||
|
|
823cefbcbc | ||
|
|
a6a2941821 | ||
|
|
faf99a1b76 | ||
|
|
afdc2b03d0 |
30
.github/workflows/deploy.yml
vendored
30
.github/workflows/deploy.yml
vendored
@@ -16,14 +16,16 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- x86_64-unknown-linux-musl
|
||||
- x86_64-apple-darwin
|
||||
- x86_64-pc-windows-msvc
|
||||
include:
|
||||
- target: x86_64-unknown-linux-gnu
|
||||
- target: aarch64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
name: aarch64-unknown-linux-musl.tar.gz
|
||||
- target: x86_64-unknown-linux-gnu
|
||||
# Deliberately pinned to the same version `mdbook` uses to build
|
||||
# binaries, so we use the same glibc version
|
||||
#
|
||||
# ref: https://github.com/rust-lang/mdBook/pull/1955
|
||||
os: ubuntu-20.04
|
||||
name: x86_64-unknown-linux-gnu.tar.gz
|
||||
- target: x86_64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
@@ -56,17 +58,19 @@ jobs:
|
||||
profile: minimal
|
||||
target: ${{ matrix.target }}
|
||||
|
||||
- name: Setup | musl tools
|
||||
if: matrix.target == 'x86_64-unknown-linux-musl'
|
||||
run: sudo apt install -y musl-tools
|
||||
- name: Setup | cross
|
||||
if: endsWith(matrix.target, '-unknown-linux-musl')
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cross
|
||||
|
||||
- name: Build | Build
|
||||
if: matrix.target != 'x86_64-unknown-linux-musl'
|
||||
if: ${{ !endsWith(matrix.target, '-unknown-linux-musl') }}
|
||||
run: cargo build --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Build | Build (musl)
|
||||
if: matrix.target == 'x86_64-unknown-linux-musl'
|
||||
run: cargo build --release --target ${{ matrix.target }}
|
||||
if: endsWith(matrix.target, '-unknown-linux-musl')
|
||||
run: cross build --release --target ${{ matrix.target }}
|
||||
|
||||
- name: Post Setup | Extract tag name
|
||||
shell: bash
|
||||
@@ -78,7 +82,6 @@ jobs:
|
||||
run: |
|
||||
mkdir target/stage
|
||||
cd target/${{ matrix.target }}/release
|
||||
strip ${{ env.CRATE_NAME }}.exe
|
||||
7z a ../../stage/${{ env.CRATE_NAME }}-${{ steps.extract_tag.outputs.tag }}-${{ matrix.name }} ${{ env.CRATE_NAME }}.exe
|
||||
cd -
|
||||
- name: Post Setup | Prepare artifacts [-nix]
|
||||
@@ -86,7 +89,6 @@ jobs:
|
||||
run: |
|
||||
mkdir target/stage
|
||||
cd target/${{ matrix.target }}/release
|
||||
strip ${{ env.CRATE_NAME }}
|
||||
tar czvf ../../stage/${{ env.CRATE_NAME }}-${{ steps.extract_tag.outputs.tag }}-${{ matrix.name }} ${{ env.CRATE_NAME }}
|
||||
cd -
|
||||
- name: Post Setup | Upload artifacts
|
||||
|
||||
50
CHANGELOG.md
50
CHANGELOG.md
@@ -2,6 +2,50 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 1.12.1
|
||||
|
||||
### Fixed
|
||||
|
||||
- Panic when searching for an indent in non-ASCII content. Thanks to [@CoralPink](https://github.com/CoralPink) for the report! ([#128](https://github.com/tommilligan/mdbook-admonish/pull/128)
|
||||
|
||||
## 1.12.0
|
||||
|
||||
### Added
|
||||
|
||||
- Admonitions are now supported when indented inside other elements, such as a list. Thanks to [@mattburgess](https://github.com/mattburgess) for the report! ([#124](https://github.com/tommilligan/mdbook-admonish/pull/124)
|
||||
|
||||
## 1.11.1
|
||||
|
||||
### Fixed
|
||||
|
||||
- Reverted internal dependency upgrades that unintentionally increased MSRV from 1.66.0 in 1.11.0
|
||||
|
||||
## 1.11.0 (yanked)
|
||||
|
||||
**Note:** This release has been yanked.
|
||||
|
||||
It unintentionally increased the MSRV from 1.66.0
|
||||
|
||||
### Changed
|
||||
|
||||
- `gnu` prebuilt binaries are now built on `ubuntu-20.04` to match `mdbook` binaries. Thanks to [@eitsupi](https://github.com/eitsupi) for the fix! ([#118](https://github.com/tommilligan/mdbook-admonish/pull/118))
|
||||
|
||||
### Added
|
||||
|
||||
- `aarch64-unknown-linux-musl` prebuilt binary now available ([#119](https://github.com/tommilligan/mdbook-admonish/pull/119))
|
||||
|
||||
## 1.10.2
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `cargo install mdbook-admonish` failing due to an internal dependency mismatch with `mdbook` ([#115](https://github.com/tommilligan/mdbook-admonish/pull/115))
|
||||
|
||||
## 1.10.1
|
||||
|
||||
### Fixed
|
||||
|
||||
- Only restyle `summary` elements generated by `mdbook-admonish`. Thanks to [@ImUrX](https://github.com/ImUrX) for the report and fix! ([#112](https://github.com/tommilligan/mdbook-admonish/pull/112))
|
||||
|
||||
## 1.10.0
|
||||
|
||||
### Changed
|
||||
@@ -124,7 +168,11 @@ This behaviour is [documented in the readme here](https://github.com/tommilligan
|
||||
- Flattened indentation of generated HTML, otherwise it's styled as a markdown code block
|
||||
- Fixed edge cases where the info string changes length when parsed, causing title/body to be incorrectly split
|
||||
|
||||
## 1.3.0
|
||||
## 1.3.0 (yanked)
|
||||
|
||||
**Note:** This release has been yanked.
|
||||
|
||||
It unintentionally introduced a serious parsing bug.
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
488
Cargo.lock
generated
488
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
32
Cargo.toml
32
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mdbook-admonish"
|
||||
version = "1.10.0"
|
||||
version = "1.12.1"
|
||||
edition = "2021"
|
||||
|
||||
authors = ["Tom Milligan <code@tommilligan.net>"]
|
||||
@@ -17,27 +17,33 @@ name = "mdbook-admonish"
|
||||
path = "src/bin/mdbook-admonish.rs"
|
||||
required-features = ["cli"]
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
|
||||
[lib]
|
||||
name = "mdbook_admonish"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.65"
|
||||
anyhow = "1.0.75"
|
||||
clap = { version = "4", default_features = false, features = ["std", "derive"], optional = true }
|
||||
env_logger = { version = "0.10", default_features = false, optional = true }
|
||||
log = "0.4.17"
|
||||
mdbook = "0.4.32"
|
||||
once_cell = "1.15.0"
|
||||
pulldown-cmark = "0.9.2"
|
||||
regex = "1.6.0"
|
||||
semver = "1.0.14"
|
||||
serde = { version = "1.0.145", features = ["derive"] }
|
||||
serde_json = "1.0.85"
|
||||
toml = "0.7.3"
|
||||
toml_edit = { version = "0.19.8", optional = true }
|
||||
log = "0.4.20"
|
||||
mdbook = "0.4.34"
|
||||
once_cell = "1.18.0"
|
||||
pulldown-cmark = "0.9.3"
|
||||
regex = "1.9.5"
|
||||
semver = "1.0.18"
|
||||
serde = { version = "1.0.188", features = ["derive"] }
|
||||
serde_json = "1.0.107"
|
||||
# The version of toml that mdbook uses internally (and uses in it's public api)
|
||||
# Only used for compatilibilty with the mdbook public api
|
||||
toml_mdbook = { package = "toml", version = "0.5.11" }
|
||||
toml = "0.7.8"
|
||||
toml_edit = { version = "0.19.15", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "1.3.0"
|
||||
pretty_assertions = "1.4.0"
|
||||
|
||||
[features]
|
||||
default = ["cli", "cli-install"]
|
||||
|
||||
@@ -174,8 +174,6 @@ You must make the next `mdbook-admonish` crate version at least a **minor** vers
|
||||
|
||||
Github workflows are setup such that pushing a `vX.Y.Z` tag will trigger a release to be cut.
|
||||
|
||||
Once the release is created, copy and paste the relevant section of `CHANGELOG.md` manually to update the description.
|
||||
|
||||
## Thanks
|
||||
|
||||
This utility is heavily drawn from and inspired by other projects, namely:
|
||||
|
||||
@@ -9,7 +9,7 @@ title = "The mdbook-admonish book"
|
||||
|
||||
[preprocessor.admonish]
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
|
||||
assets_version = "2.0.2" # do not edit: managed by `mdbook-admonish install`
|
||||
|
||||
[preprocessor.toc]
|
||||
command = "mdbook-toc"
|
||||
|
||||
@@ -5,5 +5,5 @@ set -exuo pipefail
|
||||
cd "$(dirname "$0")"/../..
|
||||
|
||||
if ! mdbook-toc --version; then
|
||||
cargo install mdbook-toc --version 0.13.0 --force
|
||||
cargo install mdbook-toc --version 0.14.1 --force
|
||||
fi
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[](https://crates.io/crates/mdbook-admonish)
|
||||
[](https://docs.rs/mdbook-admonish)
|
||||
|
||||
A preprocessor for [mdbook](https://github.com/rust-lang-nursery/mdBook) to add [Material Design](https://material.io/design) admonishments, based on the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/reference/admonitions/) implementation.
|
||||
A preprocessor for [mdbook](https://github.com/rust-lang/mdBook) to add [Material Design](https://material.io/design) admonishments, based on the [mkdocs-material](https://squidfunk.github.io/mkdocs-material/reference/admonitions/) implementation.
|
||||
|
||||
It turns this:
|
||||
|
||||
@@ -39,7 +39,7 @@ My example is the best!
|
||||
My example is the best!
|
||||
```
|
||||
|
||||
See the [list of directives](./reference.md) for a full list of supported admonitions. You'll find:
|
||||
See the [list of directives](./reference.md#directives) for a full list of supported admonitions. You'll find:
|
||||
|
||||
- `info`
|
||||
- `warning`
|
||||
@@ -74,13 +74,13 @@ This block will error
|
||||
This block will error
|
||||
```
|
||||
|
||||
You can also configure the build to fail loudly, by setting `on_failure = "bail"` in `book.toml`. See the [configuration reference](./reference.md) for more details.
|
||||
You can also configure the build to fail loudly, by setting `on_failure = "bail"` in `book.toml`. See the [configuration reference](./reference.md#booktoml-configuration) for more details.
|
||||
|
||||
### Additional Options
|
||||
|
||||
You can pass additional options to each block. The options are structured as TOML key-value pairs.
|
||||
|
||||
Note that some options can be passed globally, through the `default` section in `book.toml`. See the [configuration reference](./reference.md) for more details.
|
||||
Note that some options can be passed globally, through the `default` section in `book.toml`. See the [configuration reference](./reference.md#booktoml-configuration) for more details.
|
||||
|
||||
#### Custom title
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ a.admonition-anchor-link {
|
||||
}
|
||||
|
||||
// Admonition title
|
||||
:is(.admonition-title, summary) {
|
||||
:is(.admonition-title, summary.admonition-title) {
|
||||
position: relative;
|
||||
min-height: 4rem;
|
||||
margin-block: 0;
|
||||
@@ -233,7 +233,7 @@ summary.admonition-title {
|
||||
}
|
||||
|
||||
// Admonition flavour title
|
||||
:is(#{$flavours}) > :is(.admonition-title, summary) {
|
||||
:is(#{$flavours}) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: color.adjust($tint, $alpha: -0.9);
|
||||
|
||||
// Admonition icon
|
||||
|
||||
@@ -9,7 +9,7 @@ title = "mdbook-admonish-integration"
|
||||
|
||||
[preprocessor.admonish]
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "2.0.1" # do not edit: managed by `mdbook-admonish install`
|
||||
assets_version = "2.0.2" # do not edit: managed by `mdbook-admonish install`
|
||||
after = ["links"]
|
||||
|
||||
[preprocessor.admonish.renderer.test]
|
||||
|
||||
@@ -9,7 +9,7 @@ title = "mdbook-admonish-integration"
|
||||
|
||||
[preprocessor.admonish]
|
||||
command = "mdbook-admonish"
|
||||
assets_version = "2.0.1" # do not edit: managed by `mdbook-admonish install`
|
||||
assets_version = "2.0.2" # do not edit: managed by `mdbook-admonish install`
|
||||
after = ["links"]
|
||||
|
||||
[preprocessor.admonish.renderer.test]
|
||||
|
||||
@@ -90,4 +90,29 @@ let x = 20;
|
||||
<span class="boring">}</span></code></pre></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>In a list:</p>
|
||||
<ol>
|
||||
<li>
|
||||
<p>Thing one</p>
|
||||
<pre><code class="language-sh">Thing one
|
||||
</code></pre>
|
||||
</li>
|
||||
<li>
|
||||
<p>Thing two</p>
|
||||
<div id="admonition-note-4" class="admonition note">
|
||||
<div class="admonition-title">
|
||||
<p>Note</p>
|
||||
<p><a class="admonition-anchor-link" href="#admonition-note-4"></a></p>
|
||||
</div>
|
||||
<div>
|
||||
<p>Thing two</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<p>Thing three</p>
|
||||
<pre><code class="language-sh">Thing three
|
||||
</code></pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
|
||||
@@ -41,3 +41,23 @@ let x = 10;
|
||||
let x = 20;
|
||||
```
|
||||
````
|
||||
|
||||
In a list:
|
||||
|
||||
1. Thing one
|
||||
|
||||
```sh
|
||||
Thing one
|
||||
```
|
||||
|
||||
1. Thing two
|
||||
|
||||
```admonish
|
||||
Thing two
|
||||
```
|
||||
|
||||
1. Thing three
|
||||
|
||||
```sh
|
||||
Thing three
|
||||
```
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.0.1
|
||||
2.0.2
|
||||
|
||||
@@ -75,7 +75,7 @@ a.admonition-anchor-link::before {
|
||||
content: "§";
|
||||
}
|
||||
|
||||
:is(.admonition-title, summary) {
|
||||
:is(.admonition-title, summary.admonition-title) {
|
||||
position: relative;
|
||||
min-height: 4rem;
|
||||
margin-block: 0;
|
||||
@@ -86,13 +86,13 @@ a.admonition-anchor-link::before {
|
||||
background-color: rgba(68, 138, 255, 0.1);
|
||||
display: flex;
|
||||
}
|
||||
:is(.admonition-title, summary) p {
|
||||
:is(.admonition-title, summary.admonition-title) p {
|
||||
margin: 0;
|
||||
}
|
||||
html :is(.admonition-title, summary):last-child {
|
||||
html :is(.admonition-title, summary.admonition-title):last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
:is(.admonition-title, summary)::before {
|
||||
:is(.admonition-title, summary.admonition-title)::before {
|
||||
position: absolute;
|
||||
top: 0.625em;
|
||||
inset-inline-start: 1.6rem;
|
||||
@@ -107,7 +107,7 @@ html :is(.admonition-title, summary):last-child {
|
||||
-webkit-mask-size: contain;
|
||||
content: "";
|
||||
}
|
||||
:is(.admonition-title, summary):hover a.admonition-anchor-link {
|
||||
:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
@@ -136,10 +136,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #448aff;
|
||||
}
|
||||
|
||||
:is(.note) > :is(.admonition-title, summary) {
|
||||
:is(.note) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(68, 138, 255, 0.1);
|
||||
}
|
||||
:is(.note) > :is(.admonition-title, summary)::before {
|
||||
:is(.note) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #448aff;
|
||||
mask-image: var(--md-admonition-icon--note);
|
||||
-webkit-mask-image: var(--md-admonition-icon--note);
|
||||
@@ -153,10 +153,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #00b0ff;
|
||||
}
|
||||
|
||||
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) {
|
||||
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(0, 176, 255, 0.1);
|
||||
}
|
||||
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before {
|
||||
:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #00b0ff;
|
||||
mask-image: var(--md-admonition-icon--abstract);
|
||||
-webkit-mask-image: var(--md-admonition-icon--abstract);
|
||||
@@ -170,10 +170,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #00b8d4;
|
||||
}
|
||||
|
||||
:is(.info, .todo) > :is(.admonition-title, summary) {
|
||||
:is(.info, .todo) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(0, 184, 212, 0.1);
|
||||
}
|
||||
:is(.info, .todo) > :is(.admonition-title, summary)::before {
|
||||
:is(.info, .todo) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #00b8d4;
|
||||
mask-image: var(--md-admonition-icon--info);
|
||||
-webkit-mask-image: var(--md-admonition-icon--info);
|
||||
@@ -187,10 +187,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #00bfa5;
|
||||
}
|
||||
|
||||
:is(.tip, .hint, .important) > :is(.admonition-title, summary) {
|
||||
:is(.tip, .hint, .important) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(0, 191, 165, 0.1);
|
||||
}
|
||||
:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before {
|
||||
:is(.tip, .hint, .important) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #00bfa5;
|
||||
mask-image: var(--md-admonition-icon--tip);
|
||||
-webkit-mask-image: var(--md-admonition-icon--tip);
|
||||
@@ -204,10 +204,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #00c853;
|
||||
}
|
||||
|
||||
:is(.success, .check, .done) > :is(.admonition-title, summary) {
|
||||
:is(.success, .check, .done) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(0, 200, 83, 0.1);
|
||||
}
|
||||
:is(.success, .check, .done) > :is(.admonition-title, summary)::before {
|
||||
:is(.success, .check, .done) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #00c853;
|
||||
mask-image: var(--md-admonition-icon--success);
|
||||
-webkit-mask-image: var(--md-admonition-icon--success);
|
||||
@@ -221,10 +221,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #64dd17;
|
||||
}
|
||||
|
||||
:is(.question, .help, .faq) > :is(.admonition-title, summary) {
|
||||
:is(.question, .help, .faq) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(100, 221, 23, 0.1);
|
||||
}
|
||||
:is(.question, .help, .faq) > :is(.admonition-title, summary)::before {
|
||||
:is(.question, .help, .faq) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #64dd17;
|
||||
mask-image: var(--md-admonition-icon--question);
|
||||
-webkit-mask-image: var(--md-admonition-icon--question);
|
||||
@@ -238,10 +238,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #ff9100;
|
||||
}
|
||||
|
||||
:is(.warning, .caution, .attention) > :is(.admonition-title, summary) {
|
||||
:is(.warning, .caution, .attention) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(255, 145, 0, 0.1);
|
||||
}
|
||||
:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before {
|
||||
:is(.warning, .caution, .attention) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #ff9100;
|
||||
mask-image: var(--md-admonition-icon--warning);
|
||||
-webkit-mask-image: var(--md-admonition-icon--warning);
|
||||
@@ -255,10 +255,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #ff5252;
|
||||
}
|
||||
|
||||
:is(.failure, .fail, .missing) > :is(.admonition-title, summary) {
|
||||
:is(.failure, .fail, .missing) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(255, 82, 82, 0.1);
|
||||
}
|
||||
:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before {
|
||||
:is(.failure, .fail, .missing) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #ff5252;
|
||||
mask-image: var(--md-admonition-icon--failure);
|
||||
-webkit-mask-image: var(--md-admonition-icon--failure);
|
||||
@@ -272,10 +272,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #ff1744;
|
||||
}
|
||||
|
||||
:is(.danger, .error) > :is(.admonition-title, summary) {
|
||||
:is(.danger, .error) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(255, 23, 68, 0.1);
|
||||
}
|
||||
:is(.danger, .error) > :is(.admonition-title, summary)::before {
|
||||
:is(.danger, .error) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #ff1744;
|
||||
mask-image: var(--md-admonition-icon--danger);
|
||||
-webkit-mask-image: var(--md-admonition-icon--danger);
|
||||
@@ -289,10 +289,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #f50057;
|
||||
}
|
||||
|
||||
:is(.bug) > :is(.admonition-title, summary) {
|
||||
:is(.bug) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(245, 0, 87, 0.1);
|
||||
}
|
||||
:is(.bug) > :is(.admonition-title, summary)::before {
|
||||
:is(.bug) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #f50057;
|
||||
mask-image: var(--md-admonition-icon--bug);
|
||||
-webkit-mask-image: var(--md-admonition-icon--bug);
|
||||
@@ -306,10 +306,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #7c4dff;
|
||||
}
|
||||
|
||||
:is(.example) > :is(.admonition-title, summary) {
|
||||
:is(.example) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(124, 77, 255, 0.1);
|
||||
}
|
||||
:is(.example) > :is(.admonition-title, summary)::before {
|
||||
:is(.example) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #7c4dff;
|
||||
mask-image: var(--md-admonition-icon--example);
|
||||
-webkit-mask-image: var(--md-admonition-icon--example);
|
||||
@@ -323,10 +323,10 @@ details[open].admonition > summary.admonition-title::after {
|
||||
border-color: #9e9e9e;
|
||||
}
|
||||
|
||||
:is(.quote, .cite) > :is(.admonition-title, summary) {
|
||||
:is(.quote, .cite) > :is(.admonition-title, summary.admonition-title) {
|
||||
background-color: rgba(158, 158, 158, 0.1);
|
||||
}
|
||||
:is(.quote, .cite) > :is(.admonition-title, summary)::before {
|
||||
:is(.quote, .cite) > :is(.admonition-title, summary.admonition-title)::before {
|
||||
background-color: #9e9e9e;
|
||||
mask-image: var(--md-admonition-icon--quote);
|
||||
-webkit-mask-image: var(--md-admonition-icon--quote);
|
||||
|
||||
@@ -5,15 +5,17 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::types::AdmonitionDefaults;
|
||||
|
||||
/// Loads the plugin configuration from mdbook internals.
|
||||
///
|
||||
/// Roundtrips config to string, to avoid linking the plugin's internal version of toml
|
||||
/// to the one publically exposed by the mdbook library.
|
||||
pub(crate) fn admonish_config_from_context(ctx: &PreprocessorContext) -> Result<Config> {
|
||||
let table: toml::Table = ctx
|
||||
.config
|
||||
.get_preprocessor("admonish")
|
||||
.context("No configuration for mdbook-admonish in book.toml")?
|
||||
.to_owned();
|
||||
table
|
||||
.try_into()
|
||||
.context("Invalid mdbook-admonish configuration in book.toml")
|
||||
let table: String = toml_mdbook::to_string(
|
||||
ctx.config
|
||||
.get_preprocessor("admonish")
|
||||
.context("No configuration for mdbook-admonish in book.toml")?,
|
||||
)?;
|
||||
toml::from_str(&table).context("Invalid mdbook-admonish configuration in book.toml")
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
|
||||
133
src/markdown.rs
133
src/markdown.rs
@@ -28,12 +28,15 @@ pub(crate) fn preprocess(
|
||||
for (event, span) in events.into_offset_iter() {
|
||||
if let Event::Start(Tag::CodeBlock(Fenced(info_string))) = event.clone() {
|
||||
let span_content = &content[span.start..span.end];
|
||||
const INDENT_SCAN_MAX: usize = 1024;
|
||||
let indent = indent_of(content, span.start, INDENT_SCAN_MAX);
|
||||
|
||||
let admonition = match parse_admonition(
|
||||
info_string.as_ref(),
|
||||
admonition_defaults,
|
||||
span_content,
|
||||
on_failure,
|
||||
indent,
|
||||
) {
|
||||
Some(admonition) => admonition,
|
||||
None => continue,
|
||||
@@ -62,11 +65,73 @@ pub(crate) fn preprocess(
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
/// Returns the indent of the given position.
|
||||
///
|
||||
/// Defined as the number of characters between the given `position` (where
|
||||
/// position is a valid char boundary byte-index in `content`),
|
||||
/// and the previous newline character `\n`.
|
||||
///
|
||||
/// `max` is the maximum number of characters to scan before assuming there is
|
||||
/// no indent (will return zero if exceeded).
|
||||
///
|
||||
/// ## Panics
|
||||
///
|
||||
/// Will panic if `position` is not a valid utf-8 char boundary index of `content`.
|
||||
fn indent_of(content: &str, position: usize, max: usize) -> usize {
|
||||
// Scan for a line start before this span.
|
||||
content[..position]
|
||||
.chars()
|
||||
.rev()
|
||||
// For safety, only scan up to a fixed limit of the text
|
||||
.take(max)
|
||||
.position(|c| c == '\n')
|
||||
// If we can't find a newline, assume no indent
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn indent_of_samples() {
|
||||
for (content, position, max, expected) in [
|
||||
// Empty case
|
||||
("", 0, 10, 0),
|
||||
("no newline", 4, 10, 0),
|
||||
// Newline at position 5, difference from 8 is 3
|
||||
("with\nnewline", 8, 10, 3),
|
||||
// If no newline in safety limit, return 0
|
||||
("with\nnewline", 8, 2, 0),
|
||||
// Safety limit is characters, not bytes
|
||||
// Regression test for FIXME LINK
|
||||
(
|
||||
"例えばこれは",
|
||||
// Position is generated by mdbook internals, should be valid char limit
|
||||
// This mimics the second character starting the span
|
||||
"例".len(),
|
||||
// Any arbitrary safetly limit should be valid
|
||||
1,
|
||||
// Should not panic
|
||||
0,
|
||||
),
|
||||
(
|
||||
"例え\n れは",
|
||||
// Position is generated by mdbook internals, should be valid char limit
|
||||
// This mimics the second character starting the span
|
||||
"例え\n ".len(),
|
||||
// Any arbitrary safetly limit should be valid
|
||||
4,
|
||||
// Should not panic
|
||||
2,
|
||||
),
|
||||
] {
|
||||
let actual = indent_of(content, position, max);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
fn prep(content: &str) -> String {
|
||||
preprocess(
|
||||
content,
|
||||
@@ -418,7 +483,7 @@ Will have bonus classnames
|
||||
```
|
||||
"#;
|
||||
|
||||
let expected = r##"
|
||||
let expected = r#"
|
||||
|
||||
<div id="admonition-default" class="admonition note">
|
||||
<div>
|
||||
@@ -427,7 +492,7 @@ Will have bonus classnames
|
||||
|
||||
</div>
|
||||
</div>
|
||||
"##;
|
||||
"#;
|
||||
|
||||
assert_eq!(expected, prep(content));
|
||||
}
|
||||
@@ -684,7 +749,7 @@ A simple admonition.
|
||||
Text
|
||||
"#;
|
||||
|
||||
let expected = r##"# Chapter
|
||||
let expected = r#"# Chapter
|
||||
|
||||
<div id="admonition-default" class="admonition note">
|
||||
<div>
|
||||
@@ -694,7 +759,7 @@ A simple admonition.
|
||||
</div>
|
||||
</div>
|
||||
Text
|
||||
"##;
|
||||
"#;
|
||||
|
||||
let preprocess_result = preprocess(
|
||||
content,
|
||||
@@ -718,7 +783,7 @@ A simple admonition.
|
||||
Text
|
||||
"#;
|
||||
|
||||
let expected = r##"# Chapter
|
||||
let expected = r#"# Chapter
|
||||
|
||||
<div id="admonition-default" class="admonition note">
|
||||
<div>
|
||||
@@ -728,6 +793,64 @@ A simple admonition.
|
||||
</div>
|
||||
</div>
|
||||
Text
|
||||
"#;
|
||||
|
||||
assert_eq!(expected, prep(content));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_embed() {
|
||||
let content = r#"# Chapter
|
||||
|
||||
1. Thing one
|
||||
|
||||
```sh
|
||||
Thing one
|
||||
```
|
||||
|
||||
1. Thing two
|
||||
|
||||
```admonish
|
||||
Thing two
|
||||
```
|
||||
|
||||
1. Thing three
|
||||
|
||||
```sh
|
||||
Thing three
|
||||
```
|
||||
"#;
|
||||
|
||||
let expected = r##"# Chapter
|
||||
|
||||
1. Thing one
|
||||
|
||||
```sh
|
||||
Thing one
|
||||
```
|
||||
|
||||
1. Thing two
|
||||
|
||||
|
||||
<div id="admonition-note" class="admonition note">
|
||||
<div class="admonition-title">
|
||||
|
||||
Note
|
||||
|
||||
<a class="admonition-anchor-link" href="#admonition-note"></a>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
Thing two
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
1. Thing three
|
||||
|
||||
```sh
|
||||
Thing three
|
||||
```
|
||||
"##;
|
||||
|
||||
assert_eq!(expected, prep(content));
|
||||
|
||||
23
src/parse.rs
23
src/parse.rs
@@ -23,6 +23,7 @@ pub(crate) fn parse_admonition<'a>(
|
||||
admonition_defaults: &'a AdmonitionDefaults,
|
||||
content: &'a str,
|
||||
on_failure: OnFailure,
|
||||
indent: usize,
|
||||
) -> Option<Result<Admonition<'a>>> {
|
||||
// We need to know fence details anyway for error messages
|
||||
let extracted = extract_admonish_body(content);
|
||||
@@ -30,8 +31,6 @@ pub(crate) fn parse_admonition<'a>(
|
||||
let info = AdmonitionMeta::from_info_string(info_string, admonition_defaults)?;
|
||||
let info = match info {
|
||||
Ok(info) => info,
|
||||
// FIXME return error messages to break build if configured
|
||||
// Err(message) => return Some(Err(content)),
|
||||
Err(message) => {
|
||||
// Construct a fence capable of enclosing whatever we wrote for the
|
||||
// actual input block
|
||||
@@ -63,6 +62,7 @@ Original markdown input:
|
||||
{enclosing_fence}
|
||||
"#
|
||||
)),
|
||||
indent,
|
||||
})
|
||||
}
|
||||
OnFailure::Bail => Err(anyhow!("Error processing admonition, bailing:\n{content}")),
|
||||
@@ -70,7 +70,24 @@ Original markdown input:
|
||||
}
|
||||
};
|
||||
|
||||
Some(Ok(Admonition::new(info, extracted.body)))
|
||||
Some(Ok(Admonition::new(
|
||||
info,
|
||||
extracted.body,
|
||||
// Note that this is a bit hacky - the fence information comes from the start
|
||||
// of the block, and includes the whole line.
|
||||
//
|
||||
// This is more likely to be what we want, as ending indentation is unrelated
|
||||
// according to the commonmark spec (ref https://spec.commonmark.org/0.12/#example-85)
|
||||
//
|
||||
// The main case we're worried about here is indenting enough to be inside list items,
|
||||
// and in this case the starting code fence must be indented enough to be considered
|
||||
// part of the list item.
|
||||
//
|
||||
// The hacky thing is that we're considering line indent in the document as a whole,
|
||||
// not relative to the context of some containing item. But I think that's what we
|
||||
// want for now, anyway.
|
||||
indent,
|
||||
)))
|
||||
}
|
||||
|
||||
/// We can't trust the info string length to find the start of the body
|
||||
|
||||
@@ -31,10 +31,11 @@ pub(crate) struct Admonition<'a> {
|
||||
pub(crate) content: Cow<'a, str>,
|
||||
pub(crate) additional_classnames: Vec<String>,
|
||||
pub(crate) collapsible: bool,
|
||||
pub(crate) indent: usize,
|
||||
}
|
||||
|
||||
impl<'a> Admonition<'a> {
|
||||
pub(crate) fn new(info: AdmonitionMeta, content: &'a str) -> Self {
|
||||
pub(crate) fn new(info: AdmonitionMeta, content: &'a str, indent: usize) -> Self {
|
||||
let AdmonitionMeta {
|
||||
directive,
|
||||
title,
|
||||
@@ -47,6 +48,7 @@ impl<'a> Admonition<'a> {
|
||||
content: Cow::Borrowed(content),
|
||||
additional_classnames,
|
||||
collapsible,
|
||||
indent,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,17 +68,18 @@ impl<'a> Admonition<'a> {
|
||||
let mut additional_class = Cow::Borrowed(self.directive.classname());
|
||||
let title = &self.title;
|
||||
let content = &self.content;
|
||||
let indent = " ".repeat(self.indent);
|
||||
|
||||
let title_block = if self.collapsible { "summary" } else { "div" };
|
||||
|
||||
let title_html = if !title.is_empty() {
|
||||
Cow::Owned(format!(
|
||||
r##"<{title_block} class="admonition-title">
|
||||
|
||||
{title}
|
||||
|
||||
<a class="admonition-anchor-link" href="#{ANCHOR_ID_PREFIX}-{anchor_id}"></a>
|
||||
</{title_block}>
|
||||
r##"{indent}<{title_block} class="admonition-title">
|
||||
{indent}
|
||||
{indent}{title}
|
||||
{indent}
|
||||
{indent}<a class="admonition-anchor-link" href="#{ANCHOR_ID_PREFIX}-{anchor_id}"></a>
|
||||
{indent}</{title_block}>
|
||||
"##
|
||||
))
|
||||
} else {
|
||||
@@ -100,13 +103,13 @@ impl<'a> Admonition<'a> {
|
||||
// rendered as markdown paragraphs.
|
||||
format!(
|
||||
r#"
|
||||
<{admonition_block} id="{ANCHOR_ID_PREFIX}-{anchor_id}" class="admonition {additional_class}">
|
||||
{title_html}<div>
|
||||
|
||||
{content}
|
||||
|
||||
</div>
|
||||
</{admonition_block}>"#,
|
||||
{indent}<{admonition_block} id="{ANCHOR_ID_PREFIX}-{anchor_id}" class="admonition {additional_class}">
|
||||
{title_html}{indent}<div>
|
||||
{indent}
|
||||
{indent}{content}
|
||||
{indent}
|
||||
{indent}</div>
|
||||
{indent}</{admonition_block}>"#,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user