Skip to content
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

Fix docify embed in md #28

Merged
merged 5 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ of files or individual files.
In fact, this `README.md` file is automatically compiled whenever `cargo doc` is run on this
crate, resulting in the following codeblock to populate dynamically:

```rust
```rust,ignore
fn some_example() {
assert_eq!(2 + 2, 4);
assert_eq!(2 + 3, 5);
Expand Down
60 changes: 46 additions & 14 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use regex::Regex;
use std::{
cmp::min,
collections::HashMap,
fmt::Display,
fs::{self, OpenOptions},
io::Write,
path::{Path, PathBuf},
Expand Down Expand Up @@ -521,7 +522,10 @@ fn export_internal(
/// Output should match `rustfmt` output exactly.
#[proc_macro]
pub fn embed(tokens: TokenStream) -> TokenStream {
match embed_internal(tokens, MarkdownLanguage::Ignore) {
match embed_internal(
tokens,
vec![MarkdownLanguage::Rust, MarkdownLanguage::Ignore],
) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
Expand All @@ -534,7 +538,7 @@ pub fn embed(tokens: TokenStream) -> TokenStream {
/// [`docify::embed!(..)`](`macro@embed`) also apply to this macro.
#[proc_macro]
pub fn embed_run(tokens: TokenStream) -> TokenStream {
match embed_internal(tokens, MarkdownLanguage::Blank) {
match embed_internal(tokens, vec![MarkdownLanguage::Blank]) {
Ok(tokens) => tokens.into(),
Err(err) => err.to_compile_error().into(),
}
Expand Down Expand Up @@ -591,17 +595,36 @@ enum MarkdownLanguage {
Blank,
}

impl Display for MarkdownLanguage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MarkdownLanguage::Ignore => write!(f, "{}", "ignore"),
MarkdownLanguage::Rust => write!(f, "{}", "rust"),
MarkdownLanguage::Blank => write!(f, "{}", ""),
}
}
}

/// Converts a source string to a codeblocks wrapped example
fn into_example(st: &str, lang: MarkdownLanguage) -> String {
fn into_example(st: &str, langs: &Vec<MarkdownLanguage>) -> String {
let mut lines: Vec<String> = Vec::new();
match lang {
MarkdownLanguage::Ignore => lines.push(String::from("```ignore")),
MarkdownLanguage::Rust => lines.push(String::from("```rust")),
MarkdownLanguage::Blank => lines.push(String::from("```")),
}

// Add the markdown languages (can be more than one, or none)
let mut lang_line = String::from("```");
lang_line.push_str(
langs
.iter()
.map(|lang| lang.to_string())
.collect::<Vec<String>>()
.join(",")
.as_str(),
);
lines.push(lang_line);

for line in st.lines() {
lines.push(String::from(line));
}

lines.push(String::from("```"));
lines.join("\n")
}
Expand Down Expand Up @@ -941,7 +964,10 @@ fn source_excerpt<'a, T: ToTokens>(
}

/// Inner version of [`embed_internal`] that just returns the result as a [`String`].
fn embed_internal_str(tokens: impl Into<TokenStream2>, lang: MarkdownLanguage) -> Result<String> {
fn embed_internal_str(
tokens: impl Into<TokenStream2>,
langs: Vec<MarkdownLanguage>,
) -> Result<String> {
let args = parse2::<EmbedArgs>(tokens.into())?;
// return blank result if we can't properly resolve `caller_crate_root`
let Some(root) = caller_crate_root() else {
Expand Down Expand Up @@ -983,19 +1009,22 @@ fn embed_internal_str(tokens: impl Into<TokenStream2>, lang: MarkdownLanguage) -
for (item, style) in visitor.results {
let excerpt = source_excerpt(&source_code, &item, style)?;
let formatted = fix_indentation(excerpt);
let example = into_example(formatted.as_str(), lang);
let example = into_example(formatted.as_str(), &langs);
results.push(example);
}
results.join("\n")
} else {
into_example(source_code.as_str(), lang)
into_example(source_code.as_str(), &langs)
};
Ok(output)
}

/// Internal implementation behind [`macro@embed`].
fn embed_internal(tokens: impl Into<TokenStream2>, lang: MarkdownLanguage) -> Result<TokenStream2> {
let output = embed_internal_str(tokens, lang)?;
fn embed_internal(
tokens: impl Into<TokenStream2>,
langs: Vec<MarkdownLanguage>,
) -> Result<TokenStream2> {
let output = embed_internal_str(tokens, langs)?;
Ok(quote!(#output))
}

Expand Down Expand Up @@ -1211,7 +1240,10 @@ fn compile_markdown_source<S: AsRef<str>>(source: S) -> Result<String> {
let comment = &orig_comment[4..(orig_comment.len() - 3)].trim();
if comment.starts_with("docify") {
let args = parse2::<EmbedCommentCall>(comment.parse()?)?.args;
let compiled = embed_internal_str(args.to_token_stream(), MarkdownLanguage::Rust)?;
let compiled = embed_internal_str(
args.to_token_stream(),
vec![MarkdownLanguage::Rust, MarkdownLanguage::Ignore],
)?;
output.push(compiled);
} else {
output.push(String::from(orig_comment));
Expand Down
4 changes: 2 additions & 2 deletions macros/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn test_compile_markdown_valid() {
.to_string(),
"\"# This is a markdown file\\n\\n```rust\\nstruct \
Something;\\n```\\n<!-- this is a comment -->\\n\\n`\
``rust\\nfn some_fn() {\\n println!(\\\"foo\\\");\
``rust,ignore\\nfn some_fn() {\\n println!(\\\"foo\\\");\
\\n}\\n```\\n\\nSome text this is some text\\n\""
);
}
Expand Down Expand Up @@ -96,7 +96,7 @@ fn test_compile_markdown_source_valid() {
"this is some markdown\n\
this is some more markdown\n\
# this is a title\n\
```rust\n\
```rust,ignore\n\
fn some_fn() {\n \
println!(\"foo\");\n\
}\n\
Expand Down
Loading