Skip to content
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
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ repository = "https://github.com/VectorInstitute/mdbook-github-authors"

[dependencies]
anyhow = "1.0.95"
handlebars = "6.3.0"
mdbook = "0.4.44"
once_cell = "1.20.2"
regex = "1.11.1"
serde = "1.0.217"
serde_json = "1.0.138"
86 changes: 86 additions & 0 deletions src/github_authors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use mdbook::book::Book;
use mdbook::preprocess::{Preprocessor, PreprocessorContext};
use once_cell::sync::Lazy;
use regex::{CaptureMatches, Captures, Regex};

#[derive(Default)]
pub struct GithubAuthorsPreprocessor;

/// A preprocess for expanding "authors" helper.
///
/// {{#author <github-username>}}
impl GithubAuthorsPreprocessor {
pub(crate) const NAME: &'static str = "github-author";

pub fn new() -> Self {
GithubAuthorsPreprocessor
}
}

impl Preprocessor for GithubAuthorsPreprocessor {
fn name(&self) -> &str {
Self::NAME
}

#[allow(unused_variables)]
fn run(&self, ctx: &PreprocessorContext, book: Book) -> anyhow::Result<Book> {
// Gameplan:
// 1. Find all authors helper using reg-ex in chapter content, using `find_authors`
// 2. Sequentially erase all authors helpers from the content
// 3. Use handlebar template `authors.hbs` and render the found authors
// 4. Take the rendered html string and add it to the end of the chapter content
// 5. Figure out if need to make a cli for this and use CmdPreprocessor
todo!()
}
}

#[allow(dead_code)]
#[derive(PartialEq, Debug, Clone)]
struct Author<'a> {
start_index: usize,
end_index: usize,
github_username: &'a str,
}

impl<'a> Author<'a> {
#[allow(dead_code, unused_variables)]
fn from_capture(cap: Captures<'a>) -> Option<Author<'a>> {
todo!()
}
}

#[allow(dead_code)]
struct AuthorIter<'a>(CaptureMatches<'a, 'a>);

impl<'a> Iterator for AuthorIter<'a> {
type Item = Author<'a>;
fn next(&mut self) -> Option<Author<'a>> {
for cap in &mut self.0 {
if let Some(inc) = Author::from_capture(cap) {
return Some(inc);
}
}
None
}
}

#[allow(dead_code)]
fn find_authors(contents: &str) -> AuthorIter<'_> {
// lazily compute following regex
// r"\\\{\{#.*\}\}|\{\{#([a-zA-Z0-9]+)\s*([^}]+)\}\}")?;
static RE: Lazy<Regex> = Lazy::new(|| {
Regex::new(
r"(?x) # insignificant whitespace mode
\\\{\{\#.*\}\} # match escaped link
| # or
\{\{\s* # link opening parens and whitespace
\#([a-zA-Z0-9_]+) # link type
\s+ # separating whitespace
([^}]+) # link target path and space separated properties
\}\} # link closing parens",
)
.unwrap()
});

AuthorIter(RE.captures_iter(contents))
}
15 changes: 2 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
pub mod github_authors;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
pub use github_authors::GithubAuthorsPreprocessor;
12 changes: 12 additions & 0 deletions src/template/authors.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<hr style="border: none; border-top: 1px solid #ddd; margin: 20px 0;">
<div class="contributor-footnotes">
<small>
<strong>Contributors:</strong>
{{#authors}}
<a href="https://github.com/{{username}}">
<img src="https://github.com/{{username}}.png"
width="32px" alt="Contributor {{username}}" style="border-radius: 50%">
</a>
</small>
{{/authors}}
</div>