Skip to content

Commit

Permalink
feat: feature for automatically adding code fences (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx authored Dec 14, 2024
1 parent 6705de4 commit 77ed2f8
Show file tree
Hide file tree
Showing 23 changed files with 484 additions and 83 deletions.
7 changes: 6 additions & 1 deletion cli/src/cli/generate/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub struct Markdown {
#[clap(long)]
html_encode: bool,

#[clap(long)]
replace_pre_with_code_fences: bool,

/// Output markdown files to this directory
#[clap(long, value_hint = clap::ValueHint::DirPath)]
out_dir: Option<PathBuf>,
Expand All @@ -41,7 +44,9 @@ impl Markdown {
Ok(())
};
let (spec, _) = Spec::parse_file(&self.file)?;
let mut ctx = MarkdownRenderer::new(&spec).with_html_encode(self.html_encode);
let mut ctx = MarkdownRenderer::new(spec.clone())
.with_html_encode(self.html_encode)
.with_replace_pre_with_code_fences(self.replace_pre_with_code_fences);
if let Some(url_prefix) = &self.url_prefix {
ctx = ctx.with_url_prefix(url_prefix);
}
Expand Down
1 change: 1 addition & 0 deletions cli/usage.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ cmd "generate" subcommand_required=true {
arg "<URL_PREFIX>"
}
flag "--html-encode" help="Escape HTML in markdown"
flag "--replace-pre-with-code-fences"
flag "--out-dir" help="Output markdown files to this directory" {
arg "<OUT_DIR>"
}
Expand Down
7 changes: 0 additions & 7 deletions docs/cli/reference/bash.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ to properly escape and quote values with spaces in them.

### `<SCRIPT>`

Executes a bash script

Typically, this will be called by a script's shebang

If using `var=true` on args/flags, they will be joined with spaces using `shell_words::join()`
to properly escape and quote values with spaces in them.

### `[ARGS]...`

arguments to pass to script
Expand Down
8 changes: 8 additions & 0 deletions docs/cli/reference/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,14 @@
"hide": false,
"global": false
},
{
"name": "replace-pre-with-code-fences",
"usage": "--replace-pre-with-code-fences",
"short": [],
"long": ["replace-pre-with-code-fences"],
"hide": false,
"global": false
},
{
"name": "out-dir",
"usage": "--out-dir <OUT_DIR>",
Expand Down
2 changes: 2 additions & 0 deletions docs/cli/reference/generate/markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Prefix to add to all URLs

Escape HTML in markdown

### `--replace-pre-with-code-fences`

### `--out-dir <OUT_DIR>`

Output markdown files to this directory
Expand Down
4 changes: 0 additions & 4 deletions examples/docs/MISE_INLINE.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,6 @@ If not provided, the nearest mise.toml file will be used

#### `-t --type <TYPE>`

Display the value of a setting in a mise.toml file

**Choices:**

- `string`
Expand Down Expand Up @@ -738,8 +736,6 @@ root directory to search for tasks

#### `-s --style <STYLE>`

[experimental] Generate documentation for tasks in a project

**Choices:**

- `simple`
Expand Down
4 changes: 0 additions & 4 deletions examples/docs/MISE_MULTI.md
Original file line number Diff line number Diff line change
Expand Up @@ -433,8 +433,6 @@ If not provided, the nearest mise.toml file will be used

#### `-t --type <TYPE>`

Display the value of a setting in a mise.toml file

**Choices:**

- `string`
Expand Down Expand Up @@ -738,8 +736,6 @@ root directory to search for tasks

#### `-s --style <STYLE>`

[experimental] Generate documentation for tasks in a project

**Choices:**

- `simple`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ bin "mycli"
source_code_link_template "https://github.com/jdx/mise/blob/main/src/cli/{{path}}.rs"
flag "--flag1" help="flag1 description"
flag "--flag2" help="flag2 description" {
long_help "flag2 long description"
long_help "flag2 long description\n\nincludes a code block:\n\n $ echo hello world\n hello world\n \n more code\n\nsome docs\n\n $ echo hello world\n hello world\n"
}
flag "--flag3" help="flag3 description" negate="--no-flag3"
flag "--with-default"
Expand All @@ -36,7 +36,8 @@ arg "[with-default]" default="default value"
complete "plugin" run="echo \"plugin-1\nplugin-2\nplugin-3\""
cmd "plugin" {
cmd "install" {
flag "-g --global"
long_help r"install a plugin"
flag "-g --global" global=true
flag "-d --dir" {
arg "<dir>"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: lib/src/complete/fish.rs
expression: "complete_fish(&CompleteOptions\n{\n shell: \"fish\".to_string(), bin: \"mycli\".to_string(), cache_key: None,\n spec: Some(SPEC_KITCHEN_SINK.clone()), usage_cmd: None,\n})"
expression: "complete_fish(&CompleteOptions\n{\n shell: \"fish\".to_string(), bin: \"mycli\".to_string(), cache_key: None,\n spec: Some(SPEC_KITCHEN_SINK.clone()), usage_cmd: None,\n include_bash_completion_lib: false,\n})"
snapshot_kind: text
---
# if "usage" is not installed show an error
Expand All @@ -16,7 +16,7 @@ bin "mycli"
source_code_link_template "https://github.com/jdx/mise/blob/main/src/cli/{{path}}.rs"
flag "--flag1" help="flag1 description"
flag "--flag2" help="flag2 description" {
long_help "flag2 long description"
long_help "flag2 long description\n\nincludes a code block:\n\n $ echo hello world\n hello world\n \n more code\n\nsome docs\n\n $ echo hello world\n hello world\n"
}
flag "--flag3" help="flag3 description" negate="--no-flag3"
flag "--with-default"
Expand All @@ -35,7 +35,8 @@ arg "[with-default]" default="default value"
complete "plugin" run="echo \"plugin-1\nplugin-2\nplugin-3\""
cmd "plugin" {
cmd "install" {
flag "-g --global"
long_help r"install a plugin"
flag "-g --global" global=true
flag "-d --dir" {
arg "<dir>"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: lib/src/complete/zsh.rs
expression: "complete_zsh(&CompleteOptions\n{\n shell: \"zsh\".to_string(), bin: \"mycli\".to_string(), cache_key: None, spec:\n Some(SPEC_KITCHEN_SINK.clone()), usage_cmd: None,\n})"
expression: "complete_zsh(&CompleteOptions\n{\n shell: \"zsh\".to_string(), bin: \"mycli\".to_string(), cache_key: None, spec:\n Some(SPEC_KITCHEN_SINK.clone()), usage_cmd: None,\n include_bash_completion_lib: false,\n})"
snapshot_kind: text
---
#compdef mycli
Expand All @@ -22,7 +22,7 @@ bin "mycli"
source_code_link_template "https://github.com/jdx/mise/blob/main/src/cli/{{path}}.rs"
flag "--flag1" help="flag1 description"
flag "--flag2" help="flag2 description" {
long_help "flag2 long description"
long_help "flag2 long description\n\nincludes a code block:\n\n $ echo hello world\n hello world\n \n more code\n\nsome docs\n\n $ echo hello world\n hello world\n"
}
flag "--flag3" help="flag3 description" negate="--no-flag3"
flag "--with-default"
Expand All @@ -41,7 +41,8 @@ arg "[with-default]" default="default value"
complete "plugin" run="echo \"plugin-1\nplugin-2\nplugin-3\""
cmd "plugin" {
cmd "install" {
flag "-g --global"
long_help r"install a plugin"
flag "-g --global" global=true
flag "-d --dir" {
arg "<dir>"
}
Expand Down
18 changes: 8 additions & 10 deletions lib/src/docs/markdown/arg.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::docs::markdown::renderer::MarkdownRenderer;
use crate::docs::models::SpecArg;
use crate::error::UsageErr;
use crate::SpecArg;

impl MarkdownRenderer<'_> {
pub fn render_arg(&self, arg: &SpecArg) -> Result<String, UsageErr> {
impl MarkdownRenderer {
pub fn render_arg(&self, arg: &crate::SpecArg) -> Result<String, UsageErr> {
let mut arg = SpecArg::from(arg);
arg.render_md(self);
let mut ctx = self.clone();
ctx.insert("arg", arg);
ctx.insert("arg", &arg);
ctx.render("arg_template.md.tera")
}
}
Expand All @@ -19,11 +21,7 @@ mod tests {
#[test]
fn test_render_markdown_arg() {
let spec = spec! { r#"arg "arg1" help="arg1 description""# }.unwrap();
let ctx = MarkdownRenderer::new(&spec);
assert_snapshot!(ctx.render_arg(&spec.cmd.args[0]).unwrap(), @r#"
arg1 description
"#);
let ctx = MarkdownRenderer::new(spec.clone());
assert_snapshot!(ctx.render_arg(&spec.cmd.args[0]).unwrap(), @"arg1 description");
}
}
30 changes: 25 additions & 5 deletions lib/src/docs/markdown/cmd.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::docs::markdown::renderer::MarkdownRenderer;
use crate::docs::models::SpecCommand;
use crate::error::UsageErr;
use crate::SpecCommand;

impl MarkdownRenderer<'_> {
pub fn render_cmd(&self, cmd: &SpecCommand) -> Result<String, UsageErr> {
impl MarkdownRenderer {
pub fn render_cmd(&self, cmd: &crate::SpecCommand) -> Result<String, UsageErr> {
let mut cmd = SpecCommand::from(cmd);
cmd.render_md(self);
let mut ctx = self.clone();
ctx.insert("cmd", cmd);
ctx.insert("cmd", &cmd);
ctx.render("cmd_template.md.tera")
}
}
Expand All @@ -18,7 +20,9 @@ mod tests {

#[test]
fn test_render_markdown_cmd() {
let ctx = MarkdownRenderer::new(&SPEC_KITCHEN_SINK).with_multi(true);
let ctx = MarkdownRenderer::new(SPEC_KITCHEN_SINK.clone())
.with_multi(true)
.with_replace_pre_with_code_fences(true);
assert_snapshot!(ctx.render_cmd(&SPEC_KITCHEN_SINK.cmd).unwrap(), @r"
# `mycli`
Expand Down Expand Up @@ -62,6 +66,22 @@ mod tests {
flag2 long description
includes a code block:
```
$ echo hello world
hello world
more code
```
some docs
```
$ echo hello world
hello world
```
### `--flag3`
flag3 description
Expand Down
16 changes: 7 additions & 9 deletions lib/src/docs/markdown/flag.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::docs::markdown::renderer::MarkdownRenderer;
use crate::docs::models::SpecFlag;
use crate::error::UsageErr;
use crate::SpecFlag;

impl MarkdownRenderer<'_> {
pub fn render_flag(&self, flag: &SpecFlag) -> Result<String, UsageErr> {
impl MarkdownRenderer {
pub fn render_flag(&self, flag: &crate::SpecFlag) -> Result<String, UsageErr> {
let mut flag = SpecFlag::from(flag);
flag.render_md(self);
let mut ctx = self.clone();
ctx.insert("flag", &flag);
ctx.render("flag_template.md.tera")
Expand All @@ -19,11 +21,7 @@ mod tests {
#[test]
fn test_render_markdown_flag() {
let spec = spec! { r#"flag "--flag1" help="flag1 description""# }.unwrap();
let ctx = MarkdownRenderer::new(&spec);
assert_snapshot!(ctx.render_flag(&spec.cmd.flags[0]).unwrap(), @r#"
flag1 description
"#);
let ctx = MarkdownRenderer::new(spec.clone()).with_replace_pre_with_code_fences(true);
assert_snapshot!(ctx.render_flag(&spec.cmd.flags[0]).unwrap(), @"flag1 description");
}
}
58 changes: 49 additions & 9 deletions lib/src/docs/markdown/renderer.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,37 @@
use crate::docs::markdown::tera::TERA;
use crate::docs::models::Spec;
use crate::error::UsageErr;
use crate::Spec;
use itertools::Itertools;
use serde::Serialize;
use std::collections::HashMap;
use xx::regex;

#[derive(Debug, Clone)]
pub struct MarkdownRenderer<'a> {
pub(crate) spec: &'a Spec,
pub struct MarkdownRenderer {
pub(crate) spec: Spec,
pub(crate) header_level: usize,
pub(crate) multi: bool,
tera_ctx: tera::Context,
url_prefix: Option<String>,
html_encode: bool,
replace_pre_with_code_fences: bool,
}

impl<'a> MarkdownRenderer<'a> {
pub fn new(spec: &'a Spec) -> Self {
Self {
spec,
impl MarkdownRenderer {
pub fn new(spec: crate::Spec) -> Self {
let mut renderer = Self {
spec: spec.into(),
header_level: 1,
multi: false,
tera_ctx: tera::Context::new(),
url_prefix: None,
html_encode: true,
}
replace_pre_with_code_fences: false,
};
let mut spec = renderer.spec.clone();
spec.render_md(&renderer);
renderer.spec = spec;
renderer
}

pub fn with_header_level(mut self, header_level: usize) -> Self {
Expand All @@ -48,13 +54,18 @@ impl<'a> MarkdownRenderer<'a> {
self
}

pub fn with_replace_pre_with_code_fences(mut self, replace_pre_with_code_fences: bool) -> Self {
self.replace_pre_with_code_fences = replace_pre_with_code_fences;
self
}

pub(crate) fn insert<T: Serialize + ?Sized, S: Into<String>>(&mut self, key: S, val: &T) {
self.tera_ctx.insert(key, val);
}

fn tera_ctx(&self) -> tera::Context {
let mut ctx = self.tera_ctx.clone();
ctx.insert("spec", self.spec);
ctx.insert("spec", &self.spec);
ctx.insert("header_level", &self.header_level);
ctx.insert("multi", &self.multi);
ctx.insert("url_prefix", &self.url_prefix);
Expand Down Expand Up @@ -126,4 +137,33 @@ impl<'a> MarkdownRenderer<'a> {

Ok(tera.render(template_name, &self.tera_ctx())?)
}

pub(crate) fn replace_code_fences(&self, md: String) -> String {
if !self.replace_pre_with_code_fences {
return md;
}
// TODO: handle fences inside of <pre> or <code>
let mut in_code_block = false;
let mut new_md = String::new();
for line in md.lines() {
if let Some(line) = line.strip_prefix(" ") {
if in_code_block {
new_md.push_str(&format!("{}\n", line));
} else {
new_md.push_str(&format!("```\n{}\n", line));
in_code_block = true;
}
} else {
if in_code_block {
new_md.push_str("```\n");
in_code_block = false;
}
new_md.push_str(&format!("{}\n", line));
}
}
if in_code_block {
new_md.push_str("```\n");
}
new_md
}
}
Loading

0 comments on commit 77ed2f8

Please sign in to comment.