1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
use std::path::{Path, PathBuf};
use mdbook::book::{Book, BookItem, Chapter};
use mdbook::errors::Result;
use mdbook::preprocess::{Preprocessor, PreprocessorContext};
pub struct OpenOn;
impl Preprocessor for OpenOn {
fn name(&self) -> &str {
"open-on-gh"
}
fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book> {
let book_root = &ctx.root;
let src_root = book_root.join(&ctx.config.book.src);
let git_root = find_git(book_root).unwrap();
log::debug!("Book root: {}", book_root.display());
log::debug!("Src root: {}", src_root.display());
log::debug!("Git root: {}", git_root.display());
let repository_url = match ctx.config.get("output.html.git-repository-url") {
None => return Ok(book),
Some(url) => url,
};
let repository_url = match repository_url {
toml::Value::String(s) => s,
_ => return Ok(book),
};
log::debug!("Repository URL: {}", repository_url);
if repository_url.find("github.com").is_none() {
return Ok(book)
}
let branch = match ctx.config.get("output.html.git-branch") {
None => "master",
Some(toml::Value::String(b)) => b,
_ => return Ok(book),
};
log::debug!("Git Branch: {}", branch);
let mut res = None;
book.for_each_mut(|item: &mut BookItem| {
if let Some(Err(_)) = res {
return;
}
if let BookItem::Chapter(ref mut chapter) = *item {
res = Some(open_on(&git_root, &src_root, &repository_url, &branch, chapter).map(|md| {
chapter.content = md;
}));
}
});
res.unwrap_or(Ok(())).map(|_| book)
}
}
fn open_on(git_root: &Path, src_root: &Path, base_url: &str, branch: &str, chapter: &mut Chapter) -> Result<String> {
let content = &chapter.content;
let footer_start = "<footer id=\"open-on-gh\">";
if content.contains(footer_start) {
return Ok(content.into())
}
let path = match src_root.join(&chapter.path).canonicalize() {
Ok(path) => path,
Err(_) => return Ok(content.into()),
};
let relpath = path.strip_prefix(git_root).unwrap();
log::trace!("Chapter path: {}", path.display());
log::trace!("Relative path: {}", relpath.display());
let url = format!("{}/edit/{}/{}", base_url, branch, relpath.display());
log::trace!("URL: {}", url);
let link = format!("<a href=\"{}\">Edit this file on GitHub.</a>", url);
let content = format!("{}\n{}Found a bug? {}</footer>", content, footer_start, link);
Ok(content)
}
fn find_git(path: &Path) -> Option<PathBuf> {
let mut current_path = path;
let mut git_dir = current_path.join(".git");
let root = Path::new("/");
while !git_dir.exists() {
current_path = match current_path.parent() {
Some(p) => p,
None => return None
};
if current_path == root {
return None;
}
git_dir = current_path.join(".git");
}
git_dir.parent().map(|p| p.to_owned())
}
|