Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx committed Jan 14, 2024
1 parent e663005 commit 76f5180
Show file tree
Hide file tree
Showing 13 changed files with 313 additions and 270 deletions.
2 changes: 1 addition & 1 deletion cli/src/cli/generate/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl Completion {
let (spec, _) = Spec::parse_file(file)?;
spec
} else {
self.spec.as_ref().unwrap().parse()?
Spec::parse_spec(self.spec.as_ref().unwrap())?
};
let script = match self.shell.as_str() {
"bash" => usage::complete::bash::complete_bash(&spec),
Expand Down
16 changes: 11 additions & 5 deletions cli/src/cli/generate/markdown.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::{Display, Formatter};
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use std::{env, fs};

use clap::Args;
use contracts::requires;
Expand Down Expand Up @@ -54,7 +54,7 @@ impl Markdown {
context::set_load_root(inject.parent().unwrap().to_path_buf());
let out = parse_readme_directives(inject, &raw)?
.into_iter()
.try_fold(UsageMdContext::new(), |ctx, d| d.run(ctx))?
.try_fold(UsageMdContext::new(inject), |ctx, d| d.run(ctx))?
.out
.lock()
.unwrap()
Expand Down Expand Up @@ -259,18 +259,20 @@ impl Display for UsageMdDirective {

struct UsageMdContext {
plain: bool,
root: PathBuf,
spec: Option<Spec>,
out: Mutex<Vec<String>>,
tera: tera::Context,
}

impl UsageMdContext {
fn new() -> Self {
fn new(inject: &Path) -> Self {
Self {
plain: true,
spec: None,
out: Mutex::new(vec![]),
tera: tera::Context::new(),
root: inject.parent().unwrap().to_path_buf(),
}
}

Expand All @@ -286,7 +288,10 @@ impl UsageMdDirective {
fn run(&self, mut ctx: UsageMdContext) -> miette::Result<UsageMdContext> {
match self {
UsageMdDirective::Load { file } => {
let file = context::prepend_load_root(file);
let file = match file.is_relative() {
true => ctx.root.join(file),
false => file.to_path_buf(),
};
let spec: Spec = Spec::parse_file(&file)?.0;
ctx.tera.insert("spec", &spec.clone());
let commands: Vec<_> = gather_subcommands(&[&spec.cmd])
Expand Down Expand Up @@ -318,7 +323,8 @@ impl UsageMdDirective {
let args = spec.cmd.args.iter().filter(|a| !a.hide).collect::<Vec<_>>();
if !args.is_empty() {
for arg in args {
let name = &arg.usage();
// let name = &arg.usage();
let name = "USAGE";
if let Some(about) = &arg.long_help {
ctx.push(format!("### {name}", name = name));
ctx.push(about.to_string());
Expand Down
2 changes: 1 addition & 1 deletion cli/src/cli/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ pub fn file_or_spec(file: &Option<PathBuf>, spec: &Option<String>) -> Result<Spe
let (spec, _) = Spec::parse_file(file)?;
Ok(spec)
} else {
spec.as_ref().unwrap().parse()
Spec::parse_spec(spec.as_ref().unwrap())
}
}
4 changes: 2 additions & 2 deletions examples/MISE_README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<!-- [USAGE] load file="./mise.usage.kdl" -->
<!-- [USAGE] title -->

# {spec.name}
# mise

<!-- [USAGE] -->
<!-- [USAGE] usage_overview -->

## Usage

```bash
mise [flags] [args]
Usage: mise [OPTIONS] <COMMAND>
```

<!-- [USAGE] -->
Expand Down
18 changes: 6 additions & 12 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::Spec;
use miette::{Diagnostic, NamedSource, SourceSpan};
use thiserror::Error;

Expand Down Expand Up @@ -33,21 +32,16 @@ pub enum UsageErr {
XXError(#[from] xx::error::XXError),
}

impl UsageErr {
pub fn new(msg: String, span: &SourceSpan) -> Self {
let named_source = Spec::get_parsing_file();
Self::InvalidInput(msg, *span, named_source)
}
}

#[macro_export]
macro_rules! bail_parse {
($span:expr, $fmt:literal) => {{
($ctx:expr, $span:expr, $fmt:literal) => {{
let msg = format!($fmt);
return std::result::Result::Err(UsageErr::new(msg, $span.span()));
let err = $ctx.build_err(msg, $span);
return std::result::Result::Err(err);
}};
($span:expr, $fmt:literal, $($arg:tt)*) => {{
($ctx:expr, $span:expr, $fmt:literal, $($arg:tt)*) => {{
let msg = format!($fmt, $($arg)*);
return std::result::Result::Err(UsageErr::new(msg, $span.span()));
let err = $ctx.build_err(msg, $span);
return std::result::Result::Err(err);
}};
}
47 changes: 23 additions & 24 deletions src/parse/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use kdl::{KdlEntry, KdlNode};
use serde::Serialize;

use crate::error::UsageErr;
use crate::parse::context::ParsingContext;
use crate::parse::helpers::NodeHelper;

#[derive(Debug, Default, Serialize, Clone)]
Expand All @@ -23,7 +24,28 @@ pub struct Arg {
}

impl Arg {
pub fn usage(&self) -> String {
pub(crate) fn parse(ctx: &ParsingContext, node: &NodeHelper) -> Result<Self, UsageErr> {
let mut arg: Arg = node.arg(0)?.ensure_string()?.parse()?;
for (k, v) in node.props() {
match k {
"help" => arg.help = Some(v.ensure_string()?),
"long_help" => arg.long_help = Some(v.ensure_string()?),
"required" => arg.required = v.ensure_bool()?,
"var" => arg.var = v.ensure_bool()?,
"hide" => arg.hide = v.ensure_bool()?,
"var_min" => arg.var_min = v.ensure_i64().map(Some)?,
"var_max" => arg.var_max = v.ensure_i64().map(Some)?,
"default" => arg.default = v.ensure_string().map(Some)?,
k => bail_parse!(ctx, *v.entry.span(), "unsupported arg key {k}"),
}
}
arg.usage = arg.usage();
Ok(arg)
}
}

impl Arg {
pub(crate) fn usage(&self) -> String {
let mut name = if self.required {
format!("<{}>", self.name)
} else {
Expand Down Expand Up @@ -65,29 +87,6 @@ impl From<&Arg> for KdlNode {
}
}

impl TryFrom<&KdlNode> for Arg {
type Error = UsageErr;
fn try_from(node: &KdlNode) -> Result<Self, UsageErr> {
let hnode: NodeHelper = node.into();
let mut arg: Arg = hnode.arg(0)?.ensure_string()?.parse()?;
for (k, v) in hnode.props() {
match k {
"help" => arg.help = Some(v.ensure_string()?),
"long_help" => arg.long_help = Some(v.ensure_string()?),
"required" => arg.required = v.ensure_bool()?,
"var" => arg.var = v.ensure_bool()?,
"hide" => arg.hide = v.ensure_bool()?,
"var_min" => arg.var_min = v.ensure_i64().map(Some)?,
"var_max" => arg.var_max = v.ensure_i64().map(Some)?,
"default" => arg.default = v.ensure_string().map(Some)?,
k => bail_parse!(v.entry, "unsupported key {k}"),
}
}
arg.usage = arg.usage();
Ok(arg)
}
}

impl From<&str> for Arg {
fn from(input: &str) -> Self {
let mut arg = Arg {
Expand Down
117 changes: 58 additions & 59 deletions src/parse/cmd.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::error::UsageErr;
use crate::parse::context::ParsingContext;
use crate::parse::helpers::NodeHelper;
use crate::{Arg, Flag, Spec};
use indexmap::IndexMap;
Expand All @@ -24,6 +25,63 @@ pub struct SchemaCmd {
pub after_long_help: Option<String>,
}

impl SchemaCmd {
pub(crate) fn parse(ctx: &ParsingContext, node: &NodeHelper) -> Result<Self, UsageErr> {
node.ensure_args_count(1, 1)?;
let mut cmd = Self {
name: node.arg(0)?.ensure_string()?.to_string(),
..Default::default()
};
for (k, v) in node.props() {
match k {
"help" => cmd.help = Some(v.ensure_string()?),
"long_help" => cmd.long_help = Some(v.ensure_string()?),
"before_help" => cmd.before_help = Some(v.ensure_string()?),
"before_long_help" => cmd.before_long_help = Some(v.ensure_string()?),
"after_help" => cmd.after_help = Some(v.ensure_string()?),
"after_long_help" => {
cmd.after_long_help = Some(v.ensure_string()?);
}
"subcommand_required" => cmd.subcommand_required = v.ensure_bool()?,
"hide" => cmd.hide = v.ensure_bool()?,
k => bail_parse!(ctx, node.span(), "unsupported cmd key {k}"),
}
}
for child in node.children() {
let child: NodeHelper = child.into();
match child.name() {
"flag" => cmd.flags.push(Flag::parse(ctx, &child)?),
"arg" => cmd.args.push(Arg::parse(ctx, &child)?),
"cmd" => {
let node = SchemaCmd::parse(ctx, &child)?;
cmd.subcommands.insert(node.name.to_string(), node);
}
"alias" => {
let alias = child
.node
.entries()
.iter()
.filter_map(|e| e.value().as_string().map(|v| v.to_string()))
.collect::<Vec<_>>();
let hide = child
.props()
.get("hide")
.map(|n| n.ensure_bool())
.transpose()?
.unwrap_or(false);
if hide {
cmd.hidden_aliases.extend(alias);
} else {
cmd.aliases.extend(alias);
}
}
k => bail_parse!(ctx, *child.node.span(), "unsupported cmd key {k}"),
}
}
Ok(cmd)
}
}

impl From<&SchemaCmd> for KdlNode {
fn from(cmd: &SchemaCmd) -> Self {
let mut node = Self::new("cmd");
Expand Down Expand Up @@ -92,65 +150,6 @@ impl From<&SchemaCmd> for KdlNode {
}
}

impl TryFrom<&KdlNode> for SchemaCmd {
type Error = UsageErr;
fn try_from(node: &KdlNode) -> Result<Self, UsageErr> {
let hnode: NodeHelper = node.into();
hnode.ensure_args_count(1, 1)?;
let mut cmd = Self {
name: hnode.arg(0)?.ensure_string()?.to_string(),
..Default::default()
};
for (k, v) in hnode.props() {
match k {
"help" => cmd.help = Some(v.ensure_string()?),
"long_help" => cmd.long_help = Some(v.ensure_string()?),
"before_help" => cmd.before_help = Some(v.ensure_string()?),
"before_long_help" => cmd.before_long_help = Some(v.ensure_string()?),
"after_help" => cmd.after_help = Some(v.ensure_string()?),
"after_long_help" => {
cmd.after_long_help = Some(v.ensure_string()?);
}
"subcommand_required" => cmd.subcommand_required = v.ensure_bool()?,
"hide" => cmd.hide = v.ensure_bool()?,
k => bail_parse!(node, "unsupported key {k}"),
}
}
for child in node.children().map(|c| c.nodes()).unwrap_or_default() {
let child: NodeHelper = child.into();
match child.name() {
"flag" => cmd.flags.push(child.node.try_into()?),
"arg" => cmd.args.push(child.node.try_into()?),
"cmd" => {
let node: SchemaCmd = child.node.try_into()?;
cmd.subcommands.insert(node.name.to_string(), node);
}
"alias" => {
let alias = child
.node
.entries()
.iter()
.filter_map(|e| e.value().as_string().map(|v| v.to_string()))
.collect::<Vec<_>>();
let hide = child
.props()
.get("hide")
.map(|n| n.ensure_bool())
.transpose()?
.unwrap_or(false);
if hide {
cmd.hidden_aliases.extend(alias);
} else {
cmd.aliases.extend(alias);
}
}
k => bail_parse!(child.node, "unsupported key {k}"),
}
}
Ok(cmd)
}
}

#[cfg(feature = "clap")]
impl From<&clap::Command> for SchemaCmd {
fn from(cmd: &clap::Command) -> Self {
Expand Down
Loading

0 comments on commit 76f5180

Please sign in to comment.