Skip to content

Commit 0593682

Browse files
committed
feat(cli.yml): Can provide a custom template for html documentation
BREAKING CHANGE: - --html => --location - --template added - Improved error handling on invalid paths
1 parent 6ce68ec commit 0593682

File tree

4 files changed

+147
-34
lines changed

4 files changed

+147
-34
lines changed

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bashdoc"
3-
version = "0.4.5"
3+
version = "0.4.6"
44
authors = ["Dustin Knopoff <dustinknopoff@gmail.com>"]
55
description = """
66
A tool for generating documentation/help menu for user defined bash functions.
@@ -23,10 +23,10 @@ dirs = "1.0.4"
2323
clap = {version = "2.32", features = ["yaml"]}
2424
glob = "0.2"
2525
rayon = "1.0.3"
26-
serde_derive = "1.0.80"
27-
serde = "1.0.80"
26+
serde_derive = "1.0.82"
27+
serde = "1.0.82"
2828
serde_json = "1.0.33"
29-
toml = "0.4.8"
29+
toml = "0.4.10"
3030
nom = "4.1.1"
3131
handlebars = "1.1.0"
3232
notify = "4.0.6"

cli.yml

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
about: 'Creates a "javadoc" like structure for bash. See github repo github.com/dustinknopoff/bashdoc for information on formatting.'
22
author: "Dustin Knopoff <dustinknopoff@gmail.com>"
33
name: bashdoc
4-
version: "0.4.0"
4+
version: "0.4.6"
55
args:
66
- color:
77
help: "toggles color"
@@ -21,15 +21,22 @@ args:
2121
short: j
2222
takes_value: true
2323
value_name: FILE
24-
- html:
25-
help: output html documentation
26-
short: h
27-
long: html
28-
takes_value: true
2924
- watch:
3025
help: continuously update on change
3126
short: w
3227
long: watch
28+
- location:
29+
short: l
30+
long: location
31+
help: location to save HTML
32+
takes_value: true
33+
required: true
34+
- template:
35+
short: t
36+
long: template
37+
help: .hbs template to use for generation of documentation
38+
takes_value: true
39+
requires: location
3340
subcommands:
3441
- override:
3542
about: override the delimiters

src/docs.rs

Lines changed: 116 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,7 @@ use nom::*;
88
use nom_locate::{position, LocatedSpan};
99
use rayon::prelude::*;
1010
use serde_derive::*;
11-
use std::collections::HashMap;
12-
use std::env;
13-
use std::fs;
14-
use std::fs::File;
15-
use std::io::prelude::*;
16-
use std::path::Path;
17-
11+
use std::{collections::HashMap, env, fs, fs::File, io::prelude::*, path::Path, process::exit};
1812
type Span<'a> = LocatedSpan<CompleteStr<'a>>;
1913

2014
/// Represents a simple Key, Value pair
@@ -198,7 +192,13 @@ fn get_strings_from_file<'a>(p: &Path, delims: Delimiters) -> Vec<Extracted<'a>>
198192
// println!("{:#?}", used);
199193
let result = parse_strings_from_file(Span::new(CompleteStr(used)), delims);
200194
// println!("{:#?}", result);
201-
result.unwrap().1
195+
match result {
196+
Ok(r) => r.1,
197+
Err(e) => {
198+
println!("Error parsing {}", p.display());
199+
exit(1);
200+
},
201+
}
202202
}
203203

204204
/// Given a `Vec<str>` make a `DocFile`
@@ -345,21 +345,41 @@ pub fn write_json(docstrings: &[DocFile], file_name: &str) {
345345
.expect("Could not write to file.");
346346
}
347347

348-
pub fn to_html(docstrings: &[DocFile], dir: &str) {
348+
pub fn to_html(docstrings: &[DocFile], dir: Option<&str>, template_loc: Option<&str>) {
349349
for dfile in docstrings {
350350
let json = to_json(dfile);
351351
let handlebars = Handlebars::new();
352-
let mut template = File::open("./static/template.hbs").unwrap();
353-
let mut output = if dir.len() == 1 {
354-
File::create(format!("{}.html", dfile.filename).as_str())
355-
.expect("File cannot be created")
356-
} else {
357-
File::create(format!("{}/{}.html", dir, dfile.filename).as_str())
358-
.expect("File cannot be created")
352+
let mut template = match template_loc {
353+
Some(m) => match File::open(m) {
354+
Ok(o) => o,
355+
Err(_) => {
356+
println!("Provided path is invalid");
357+
exit(1);
358+
}
359+
},
360+
None => File::open("./static/template.hbs").unwrap(),
361+
};
362+
// let mut template = File::open("./static/template.hbs").unwrap();
363+
let mut output = match dir {
364+
Some(d) if Path::new(d).is_dir() => {
365+
File::create(format!("{}/{}.html", d, dfile.filename).as_str())
366+
.expect("File could not be created")
367+
}
368+
None | Some(_) => {
369+
println!("Provided path is invalid");
370+
exit(1);
371+
}
359372
};
360-
handlebars
361-
.render_template_source_to_write(&mut template, &json, &mut output)
362-
.unwrap();
373+
// let mut output = if dir.len() == 1 {
374+
// File::create(format!("{}.html", dfile.filename).as_str())
375+
// .expect("File cannot be created")
376+
// } else {
377+
// File::create(format!("{}/{}.html", dir, dfile.filename).as_str())
378+
// .expect("File cannot be created")
379+
// };
380+
match handlebars
381+
.render_template_source_to_write(&mut template, &json, &mut output).expect("Could not generate documentation");
382+
363383
}
364384
}
365385

@@ -440,3 +460,80 @@ impl<'a> Delimiters<'a> {
440460
}
441461
}
442462
}
463+
464+
#[cfg(test)]
465+
mod tests {
466+
use super::*;
467+
mod kv_tests {
468+
use super::*;
469+
#[test]
470+
fn new_kv() {
471+
let kv = KV::new(String::from("a"), String::from("b"));
472+
assert_eq!(String::from("a"), kv.key);
473+
assert_eq!(String::from("b"), kv.value);
474+
}
475+
476+
#[test]
477+
fn cmp_kv() {
478+
let kv1 = KV::new(String::from("a"), String::from("b"));
479+
let kv2 = KV::new(String::from("a"), String::from("b"));
480+
let kv = KV::new(String::from("b"), String::from("a"));
481+
assert_eq!(kv1, kv2);
482+
assert_ne!(kv1, kv);
483+
}
484+
485+
#[test]
486+
fn is_as_kv() {
487+
let conv = as_kv("type: mp4 or gif");
488+
assert_eq!(
489+
KV {
490+
key: String::from("type"),
491+
value: String::from("mp4 or gif")
492+
},
493+
conv.unwrap()
494+
);
495+
}
496+
497+
#[test]
498+
fn is_as_kv_white() {
499+
let conv = as_kv_whitespace("CTRL-O to open with `open` command,");
500+
assert_eq!(
501+
KV {
502+
key: String::from("CTRL-O"),
503+
value: String::from("to open with `open` command,")
504+
},
505+
conv.unwrap()
506+
);
507+
}
508+
}
509+
510+
mod docfile_tests {
511+
use super::*;
512+
#[test]
513+
fn test_add() {
514+
let mut dfile = DocFile {
515+
thedocs: Vec::new(),
516+
filename: String::from("zshrc"),
517+
};
518+
dfile.add(Doc {
519+
short_description: String::from("lala"),
520+
long_description: String::from("rawr"),
521+
descriptors: Vec::new(),
522+
params: Vec::new(),
523+
returns: Vec::new(),
524+
position: 0,
525+
});
526+
assert_eq!(
527+
dfile.thedocs,
528+
[Doc {
529+
short_description: String::from("lala"),
530+
long_description: String::from("rawr"),
531+
descriptors: Vec::new(),
532+
params: Vec::new(),
533+
returns: Vec::new(),
534+
position: 0,
535+
}]
536+
);
537+
}
538+
}
539+
}

src/main.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ use crate::docs::*;
9494
use clap::{load_yaml, App, ArgMatches};
9595
use dirs::home_dir;
9696
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
97-
use std::sync::mpsc::channel;
98-
use std::time::Duration;
97+
use std::{process::exit, sync::mpsc::channel, time::Duration};
9998

10099
fn main() {
101100
let yaml = load_yaml!("../cli.yml");
@@ -127,8 +126,12 @@ fn generate<'a>(matches: &'a ArgMatches<'a>) {
127126
};
128127
if matches.is_present("json") {
129128
write_json(&all_em, matches.value_of("json").unwrap());
130-
} else if matches.is_present("html") {
131-
to_html(&all_em, matches.value_of("html").unwrap());
129+
} else if matches.is_present("location") {
130+
to_html(
131+
&all_em,
132+
matches.value_of("location"),
133+
matches.value_of("template"),
134+
);
132135
} else {
133136
for doc in &all_em {
134137
if matches.is_present("color") {
@@ -143,7 +146,13 @@ fn generate<'a>(matches: &'a ArgMatches<'a>) {
143146
fn watcher<'a>(matches: &'a ArgMatches<'a>) {
144147
generate(matches);
145148
let (tx, rx) = channel();
146-
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2)).unwrap();
149+
let mut watcher: RecommendedWatcher = match Watcher::new(tx, Duration::from_secs(2)) {
150+
Ok(d) => d,
151+
Err(_) => {
152+
println!("Provided path is invalid");
153+
exit(1);
154+
}
155+
};
147156
let path: String = if cfg!(windows) {
148157
String::from(matches.value_of("INPUT").unwrap())
149158
} else {

0 commit comments

Comments
 (0)