Skip to content

Commit

Permalink
Merge branch 'master' into exit-status
Browse files Browse the repository at this point in the history
  • Loading branch information
codesections committed Jan 22, 2019
2 parents 0c639db + af9a6df commit 9e9598c
Show file tree
Hide file tree
Showing 7 changed files with 489 additions and 0 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ fn main() {
.long("--output")
.help("The file path to write output to"),
)
.example(
Example::new()
.text("run basic in debug mode")
.command("basic -d")
.output("Debug Mode: basic will print errors to the console")
)
.custom(
Section::new("usage note")
.paragraph("This program will overwrite any file currently stored at the output path")
Expand Down Expand Up @@ -72,13 +78,19 @@ OPTIONS
USAGE NOTE
This file will overwrite any file currently stored at the output path.
EXIT STATUS
0 Successful program execution.
1 Unsuccessful program execution.
101 The program panicked.
EXAMPLES
run basic in debug mode
$ basic -d
Debug Mode: basic will print errors to the console
AUTHORS
Alice Person <[email protected]>
Bob Human <[email protected]>
Expand Down
12 changes: 12 additions & 0 deletions examples/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ fn main() {
.long("--port")
.help("The network port to listen to."),
)
.example(
Example::new()
.text("listen on port 3000")
.command("auth-service -p 3000")
.output("now listening on port 3000"),
)
.example(
Example::new()
.text("auth-service may need to be run by root")
.prompt("#")
.command("auth-service"),
)
.custom(
Section::new("custom section")
.paragraph("text for the custom section")
Expand Down
39 changes: 39 additions & 0 deletions src/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/// Add a examples section
#[derive(Debug, Clone, Default)]
pub struct Example {
pub(crate) prompt: &'static str,
pub(crate) text: Option<&'static str>,
pub(crate) command: Option<&'static str>,
pub(crate) output: Option<&'static str>,
}

impl Example {
pub fn new() -> Self {
Self {
prompt: "$",
text: None,
command: None,
output: None,
}
}

pub fn prompt(mut self, prompt: &'static str) -> Self {
self.prompt = prompt;
self
}

pub fn text(mut self, text: &'static str) -> Self {
self.text = Some(text);
self
}

pub fn command(mut self, command: &'static str) -> Self {
self.command = Some(command);
self
}

pub fn output(mut self, output: &'static str) -> Self {
self.output = Some(output);
self
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern crate roff;
mod arg;
mod author;
mod environment;
mod example;
mod exit_status;
mod flag;
mod man;
Expand All @@ -19,6 +20,7 @@ pub mod prelude;
pub use arg::Arg;
pub use author::Author;
pub use environment::Env;
pub use example::Example;
pub use exit_status::ExitStatus;
pub use flag::Flag;
pub use man::Manual;
Expand Down
54 changes: 54 additions & 0 deletions src/man.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct Manual {
arguments: Vec<Arg>,
custom_sections: Vec<Section>,
exit_statuses: Vec<ExitStatus>,
examples: Vec<Example>,
}

impl Manual {
Expand All @@ -30,6 +31,7 @@ impl Manual {
environment: vec![],
custom_sections: vec![],
exit_statuses: vec![],
examples: vec![],
}
}

Expand Down Expand Up @@ -75,6 +77,12 @@ impl Manual {
self
}

/// Add an examples section
pub fn example(mut self, example: Example) -> Self {
self.examples.push(example);
self
}

/// Add a positional argument. The items are displayed in the order they're
/// pushed.
// TODO: make this accept argument vecs / optional args too. `arg...`, `arg?`
Expand Down Expand Up @@ -108,6 +116,7 @@ impl Manual {
page = custom(page, section);
}
page = exit_status(page, &self.exit_statuses);
page = examples(page, &self.examples);
page = authors(page, &self.authors);
page.render()
}
Expand Down Expand Up @@ -398,6 +407,51 @@ fn custom(page: Roff, custom_section: Section) -> Roff {
page.section(&custom_section.name, &paragraphs)
}

/// Create an examples section
///
/// examples can have text (shown before the example command) and the command
/// itself. Optionally, you can also display the output of the command, but
/// this is typically not necessary. You may also change the prompt displayed
/// before the command (the default is `$`).
///
/// The command is printed in bold.
///
/// ## Formatting
/// ```txt
/// EXAMPLES
/// Explanatory text
/// $ command
/// output
/// ```
fn examples(page: Roff, examples: &[Example]) -> Roff {
if examples.is_empty() {
return page;
};
let mut arr = vec![];
for example in examples {
let text = example.text.unwrap_or("");
let mut full_command = String::from(example.prompt);
if let Some(command) = example.command {
full_command.push_str(" ");
full_command.push_str(command);
};
let output = match example.output {
Some(output) => {
// For now, we need to manually add the line break in the list
// see https://github.com/killercup/roff-rs/issues/5
let mut full_output = String::from("\n.br\n");
full_output.push_str(output);
full_output.push_str("\n");
full_output
}
None => String::from("\n"),
};
let example = list(&[text], &[bold(full_command.as_str()), output]);
arr.push(example);
}
page.section("examples", &arr)
}

// NOTE(yw): This code was taken from the npm-install(1) command. The location
// on your system may vary. In all honesty I just copy-pasted this. We should
// probably port this to troff-rs at some point.
Expand Down
Loading

0 comments on commit 9e9598c

Please sign in to comment.