Skip to content

Commit

Permalink
feat: basic support for markdown generation in lib
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Sep 27, 2024
1 parent 0049e95 commit de004c8
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 3 deletions.
1 change: 0 additions & 1 deletion .idea/vcs.xml

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

1 change: 1 addition & 0 deletions Cargo.lock

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

7 changes: 5 additions & 2 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ include = [
"/Cargo.lock",
"/README.md",
"/src/**/*.rs",
"/src/**/*.tera",
]
description = "Library for working with usage specs"
homepage = { workspace = true }
Expand All @@ -21,7 +22,7 @@ name = "usage"

[dependencies]
clap = { version = "4", features = ["derive", "string"], optional = true }
heck = "0.5.0"
heck = "0.5"
indexmap = { version = "2", features = ["serde"] }
itertools = "0.13"
kdl = "4"
Expand All @@ -30,11 +31,13 @@ miette = "5"
once_cell = "1"
serde = { version = "1", features = ["derive"] }
strum = { version = "0.26", features = ["derive"] }
tera = { version = "1", optional = true }
thiserror = "1"
xx = "1"

[features]
default = ["clap"]
default = []
docs = ["tera"]

[dev-dependencies]
ctor = "0.2"
Expand Down
76 changes: 76 additions & 0 deletions lib/src/docs/markdown/cmd_template.tera
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{% set deprecated = "" %}{% if cmd.deprecated %}{% set deprecated = "~~" %}{% endif %}
{{ header }} {{deprecated}}`{{ bin }}{{ cmd.full_cmd | join(sep=" ") }}`{{deprecated}}{% if cmd.deprecated %} [deprecated]{% endif -%}

{% if cmd.before_long_help %}

{{ cmd.before_long_help | trim }}

{% elif cmd.before_help %}
{{ cmd.before_help | trim }}
{% endif -%}

{% if cmd.aliases %}

{{ header }}# Aliases: `{{ cmd.aliases | join(sep="`, `") }}`{{""-}}
{% endif -%}

{% if cmd.long_help %}

{{ cmd.long_help | trim -}}
{% elif cmd.help %}

{{ cmd.help | trim -}}
{% endif -%}

{% for name, cmd in cmd.subcommands -%}
{% if loop.first %}
{{ header }}# Subcommands
{% endif %}
* `{{ cmd.usage }}` - {{ cmd.help -}}
{% endfor -%}

{% if cmd.args -%}
{% for arg in cmd.args %}

{{ header }}# Arg `{{ arg.usage }}`

{% if arg.required %}(required) {% endif -%}
{{ arg.long_help | default(value=arg.help) -}}

{% endfor -%}
{% endif -%}
{% if cmd.flags -%}
{% for flag in cmd.flags %}

{% if flag.deprecated -%}
{{ header }}# Flag ~~`{{ flag.usage }}`~~ [deprecated]
{% else -%}
{{ header }}# Flag `{{ flag.usage }}`
{% endif %}
{{ flag.long_help | default(value=flag.help) -}}
{% endfor -%}
{% endif -%}

{% for ex in cmd.examples -%}
{% if loop.first %}

{{ header}}# Examples
{% endif %}
{% if ex.header -%}
{{ header }}# {{ ex.header }}
{% endif %}
```{{ ex.lang | default(value="") }}
{{ ex.code }}
```
{% if ex.help %}
{{ ex.help -}}
{% endif -%}
{% endfor -%}

{% if cmd.after_long_help %}

{{ cmd.after_long_help | trim }}
{% elif cmd.after_help %}

{{ cmd.after_help | trim }}
{% endif -%}
41 changes: 41 additions & 0 deletions lib/src/docs/markdown/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use crate::error::UsageErr;
use tera::{Context, Tera};

const SPEC_TEMPLATE: &str = include_str!("cmd_template.tera");

impl crate::spec::Spec {
pub fn render_markdown(&self) -> Result<String, UsageErr> {
let mut ctx = Context::new();
ctx.insert("header", "#");
ctx.insert("bin", &self.bin);
ctx.insert("cmd", &self.cmd);
let out = Tera::one_off(SPEC_TEMPLATE, &ctx, false)?;
Ok(out)
}
}

#[cfg(test)]
mod tests {
use crate::Spec;
use insta::assert_snapshot;

#[test]
fn test_render_markdown() {
let spec: Spec = r#"
bin "mycli"
arg "arg1" help="arg1 description"
arg "arg2" help="arg2 description" default="default value" {
choices "choice1" "choice2" "choice3"
}
arg "arg3" help="arg3 description" required=true long_help="arg3 long description"
arg "argrest" var=true
flag "--flag1" help="flag1 description"
flag "--flag2" help="flag2 description" long_help="flag2 long description"
flag "--flag3" help="flag3 description" negate="--no-flag3"
"#
.parse()
.unwrap();
assert_snapshot!(spec.render_markdown().unwrap());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
source: lib/src/docs/markdown/mod.rs
expression: spec.render_markdown().unwrap()
---
# `mycli`

## Arg `<arg1>`
(required) arg1 description
## Arg `<arg2>`
(required) arg2 description
## Arg `<arg3>`
(required) arg3 long description
## Arg `<argrest>...`
(required)
## Flag `--flag1`
flag1 description
## Flag `--flag2`
flag2 long description
## Flag `--flag3`
flag3 description
1 change: 1 addition & 0 deletions lib/src/docs/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod markdown;
4 changes: 4 additions & 0 deletions lib/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ pub enum UsageErr {
#[error(transparent)]
FromUtf8Error(#[from] std::string::FromUtf8Error),

#[cfg(feature = "tera")]
#[error(transparent)]
TeraError(#[from] tera::Error),

#[error(transparent)]
#[diagnostic(transparent)]
KdlError(#[from] kdl::KdlError),
Expand Down
2 changes: 2 additions & 0 deletions lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub mod error;
pub mod complete;
pub mod spec;

#[cfg(feature = "docs")]
mod docs;
pub mod parse;
pub(crate) mod sh;
#[cfg(test)]
Expand Down

0 comments on commit de004c8

Please sign in to comment.