trim leading whitespace from code snippets

This commit is contained in:
Jesse de Wit
2023-11-03 22:51:11 +01:00
parent 101be32da2
commit e7ad51e682
6 changed files with 2132 additions and 0 deletions

View File

@@ -13,6 +13,7 @@ To locally serve the docs run:
```bash
cargo install mdbook
cargo install --path ./snippets-processor
mdbook build
mdbook serve --open
```

View File

@@ -13,3 +13,6 @@ edit-url-template = "https://github.com/breez/breez-sdk-docs/edit/main/{path}"
[output.html.print]
enable = false
[preprocessor.snippets]
after = ["links"]

1
snippets-processor/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
target

1993
snippets-processor/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
[package]
name = "mdbook-snippets"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = "4.4.7"
mdbook = "0.4.35"
serde_json = "1.0.108"

View File

@@ -0,0 +1,123 @@
use clap::{crate_version, Arg, ArgMatches, Command};
use mdbook::book::Book;
use mdbook::errors::{Error, Result};
use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext};
use mdbook::BookItem;
use std::io;
fn main() -> Result<()> {
// set up app
let matches = make_app().get_matches();
let pre = SnippetsProcessor;
// determine what behaviour has been requested
if let Some(sub_args) = matches.subcommand_matches("supports") {
// handle cmdline supports
handle_supports(&pre, sub_args)
} else {
// handle preprocessing
handle_preprocessing(&pre)
}
}
/// Parse CLI options.
pub fn make_app() -> Command {
Command::new("mdbook-snippets")
.version(crate_version!())
.about("A preprocessor that removes leading whitespace from code snippets.")
.subcommand(
Command::new("supports")
.arg(Arg::new("renderer").required(true))
.about("Check whether a renderer is supported by this preprocessor"),
)
}
/// Tell mdBook if we support what it asks for.
fn handle_supports(pre: &dyn Preprocessor, sub_args: &ArgMatches) -> Result<()> {
let renderer = sub_args
.get_one::<String>("renderer")
.expect("Required argument");
let supported = pre.supports_renderer(renderer);
if supported {
Ok(())
} else {
Err(Error::msg(format!(
"The snippets preprocessor does not support the '{renderer}' renderer",
)))
}
}
/// Preprocess `book` using `pre` and print it out.
fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<()> {
let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?;
check_mdbook_version(&ctx.mdbook_version);
let processed_book = pre.run(&ctx, book)?;
serde_json::to_writer(io::stdout(), &processed_book)?;
Ok(())
}
/// Produce a warning on mdBook version mismatch.
fn check_mdbook_version(version: &str) {
if version != mdbook::MDBOOK_VERSION {
eprintln!(
"This mdbook-snippets was built against mdbook v{}, \
but we are being called from mdbook v{version}. \
If you have any issue, this might be a reason.",
mdbook::MDBOOK_VERSION,
)
}
}
struct SnippetsProcessor;
impl Preprocessor for SnippetsProcessor {
fn name(&self) -> &str {
"snippets"
}
fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
book.for_each_mut(|item| {
if let BookItem::Chapter(chapter) = item {
let mut resulting_lines: Vec<&str> = vec![];
let mut in_block = false;
let mut block_lines: Vec<&str> = vec![];
let mut min_indentation: usize = 0;
for line in chapter.content.lines() {
if line.starts_with("```") {
if in_block {
// This is end of block
// Replace previous lines
for block_line in block_lines.iter() {
let indent = std::cmp::min(min_indentation, block_line.len());
resulting_lines.push(&block_line[indent..])
}
in_block = false;
} else {
// Start of block
in_block = true;
block_lines = vec![];
min_indentation = usize::MAX;
}
resulting_lines.push(line);
continue;
}
if in_block {
block_lines.push(line);
let trimmed = line.trim_start_matches(' ');
if !trimmed.is_empty() {
min_indentation =
std::cmp::min(min_indentation, line.len() - trimmed.len())
}
} else {
resulting_lines.push(line);
}
}
chapter.content = resulting_lines.join("\n");
}
});
Ok(book)
}
}