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 cf18b70 commit c6c830a
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 39 deletions.
4 changes: 2 additions & 2 deletions cli/src/cli/generate/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use thiserror::Error;
use xx::file;

use usage::parse::config::SpecConfig;
use usage::{SchemaCmd, Spec};
use usage::{Spec, SpecCommand};

use crate::errors::UsageCLIError;

Expand Down Expand Up @@ -450,7 +450,7 @@ impl MarkdownBuilder {
}
}

fn gather_subcommands(cmds: &[&SchemaCmd]) -> Vec<SchemaCmd> {
fn gather_subcommands(cmds: &[&SpecCommand]) -> Vec<SpecCommand> {
let mut subcommands = vec![];
for cmd in cmds {
if cmd.hide {
Expand Down
11 changes: 11 additions & 0 deletions examples/mise.usage.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,15 @@ config {
cmd "zzz" \
help="Sleeps for a while." \
long_help="Sleeps for a while. The amount of time is determined by the --timeout option." {

example r#"
mise zzz
mise zzz --timeout 2
"#

example r#"
$ mise zzz
Sleeping for 1.5 seconds...
Done.
"#
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ pub(crate) mod env;
pub mod parse;

pub use crate::parse::arg::Arg;
pub use crate::parse::cmd::SchemaCmd;
pub use crate::parse::cmd::SpecCommand;
pub use crate::parse::flag::Flag;
pub use crate::parse::spec::Spec;
47 changes: 26 additions & 21 deletions src/parse/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use kdl::{KdlDocument, KdlEntry, KdlNode};
use serde::Serialize;

#[derive(Debug, Default, Serialize, Clone)]
pub struct SchemaCmd {
pub struct SpecCommand {
pub full_cmd: Vec<String>,
pub subcommands: IndexMap<String, SchemaCmd>,
pub subcommands: IndexMap<String, SpecCommand>,
pub args: Vec<Arg>,
pub flags: Vec<Flag>,
pub hide: bool,
Expand All @@ -23,11 +23,12 @@ pub struct SchemaCmd {
pub before_long_help: Option<String>,
pub after_help: Option<String>,
pub after_long_help: Option<String>,
pub examples: Vec<String>,
}

impl SchemaCmd {
impl SpecCommand {
pub(crate) fn parse(ctx: &ParsingContext, node: &NodeHelper) -> Result<Self, UsageErr> {
node.ensure_args_count(1, 1)?;
node.ensure_arg_len(1..=1)?;
let mut cmd = Self {
name: node.arg(0)?.ensure_string()?.to_string(),
..Default::default()
Expand All @@ -44,37 +45,41 @@ impl SchemaCmd {
}
"subcommand_required" => cmd.subcommand_required = v.ensure_bool()?,
"hide" => cmd.hide = v.ensure_bool()?,
k => bail_parse!(ctx, node.span(), "unsupported cmd key {k}"),
k => bail_parse!(ctx, node.span(), "unsupported cmd prop {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)?;
let node = SpecCommand::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<_>>();
.ensure_arg_len(1..)?
.args()
.map(|e| e.ensure_string())
.collect::<Result<Vec<_>, _>>()?;
let hide = child
.props()
.get("hide")
.map(|n| n.ensure_bool())
.transpose()?
.unwrap_or(false);
.unwrap_or(Ok(false))?;
if hide {
cmd.hidden_aliases.extend(alias);
} else {
cmd.aliases.extend(alias);
}
}
"example" => {
let example = child
.ensure_arg_len(1..=1)?
.args()
.map(|e| e.ensure_string())
.collect::<Result<Vec<_>, _>>()?;
cmd.examples.extend(example);
}
k => bail_parse!(ctx, *child.node.span(), "unsupported cmd key {k}"),
}
}
Expand Down Expand Up @@ -125,8 +130,8 @@ impl SchemaCmd {
}
}

impl From<&SchemaCmd> for KdlNode {
fn from(cmd: &SchemaCmd) -> Self {
impl From<&SpecCommand> for KdlNode {
fn from(cmd: &SpecCommand) -> Self {
let mut node = Self::new("cmd");
node.entries_mut().push(cmd.name.clone().into());
if cmd.hide {
Expand Down Expand Up @@ -194,7 +199,7 @@ impl From<&SchemaCmd> for KdlNode {
}

#[cfg(feature = "clap")]
impl From<&clap::Command> for SchemaCmd {
impl From<&clap::Command> for SpecCommand {
fn from(cmd: &clap::Command) -> Self {
let mut spec = Self {
name: cmd.get_name().to_string(),
Expand Down Expand Up @@ -225,7 +230,7 @@ impl From<&clap::Command> for SchemaCmd {
}
spec.subcommand_required = cmd.is_subcommand_required_set();
for subcmd in cmd.get_subcommands() {
let mut scmd: SchemaCmd = subcmd.into();
let mut scmd: SpecCommand = subcmd.into();
scmd.name = subcmd.get_name().to_string();
spec.subcommands.insert(scmd.name.clone(), scmd);
}
Expand All @@ -234,8 +239,8 @@ impl From<&clap::Command> for SchemaCmd {
}

#[cfg(feature = "clap")]
impl From<&SchemaCmd> for clap::Command {
fn from(cmd: &SchemaCmd) -> Self {
impl From<&SpecCommand> for clap::Command {
fn from(cmd: &SpecCommand) -> Self {
let mut app = Self::new(cmd.name.to_string());
if let Some(help) = &cmd.help {
app = app.about(help);
Expand Down
2 changes: 1 addition & 1 deletion src/parse/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl SpecConfig {
pub(crate) fn parse(ctx: &ParsingContext, node: &NodeHelper) -> Result<Self, UsageErr> {
let mut config = Self::default();
for node in node.children() {
node.ensure_args_count(1, 1)?;
node.ensure_arg_len(1..=1)?;
match node.name() {
"prop" => {
let key = node.arg(0)?;
Expand Down
30 changes: 20 additions & 10 deletions src/parse/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use indexmap::IndexMap;
use kdl::{KdlEntry, KdlNode, KdlValue};
use miette::SourceSpan;
use std::fmt::Debug;
use std::ops::{Range, RangeBounds, RangeFrom};

use crate::error::UsageErr;
use crate::parse::context::ParsingContext;
Expand All @@ -22,19 +24,20 @@ impl<'a> NodeHelper<'a> {
pub(crate) fn span(&self) -> SourceSpan {
*self.node.span()
}
pub(crate) fn ensure_args_count(&self, min: usize, max: usize) -> Result<(), UsageErr> {
let count = self
.node
.entries()
.iter()
.filter(|e| e.name().is_none())
.count();
if count < min || count > max {
pub(crate) fn ensure_arg_len<R>(&self, range: R) -> Result<&Self, UsageErr>
where
R: RangeBounds<usize> + Debug,
{
let count = self.args().count();
if !range.contains(&count) {
let ctx = self.ctx;
let span = self.span();
bail_parse!(ctx, span, "expected {min} to {max} arguments, got {count}")
bail_parse!(ctx, span, "expected {range:?} arguments, got {count}",)
}
Ok(())
Ok(self)
}
pub(crate) fn get(&self, key: &str) -> Option<ParseEntry> {
self.node.get(key).map(|e| ParseEntry::new(self.ctx, e))
}
pub(crate) fn arg(&self, i: usize) -> Result<ParseEntry, UsageErr> {
if let Some(entry) = self.node.entries().get(i) {
Expand All @@ -48,6 +51,13 @@ impl<'a> NodeHelper<'a> {
}
bail_parse!(self.ctx, self.span(), "missing argument")
}
pub(crate) fn args(&self) -> impl Iterator<Item = ParseEntry> + '_ {
self.node
.entries()
.iter()
.filter(|e| e.name().is_none())
.map(|e| ParseEntry::new(self.ctx, e))
}
pub(crate) fn props(&self) -> IndexMap<&str, ParseEntry> {
self.node
.entries()
Expand Down
8 changes: 4 additions & 4 deletions src/parse/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use serde::Serialize;
use xx::file;

use crate::error::UsageErr;
use crate::parse::cmd::SchemaCmd;
use crate::parse::cmd::SpecCommand;
use crate::parse::config::SpecConfig;
use crate::parse::context::ParsingContext;
use crate::parse::helpers::NodeHelper;
Expand All @@ -17,7 +17,7 @@ use crate::{Arg, Flag};
pub struct Spec {
pub name: String,
pub bin: String,
pub cmd: SchemaCmd,
pub cmd: SpecCommand,
pub config: SpecConfig,
pub version: Option<String>,
pub usage: String,
Expand Down Expand Up @@ -69,7 +69,7 @@ impl Spec {
"arg" => schema.cmd.args.push(Arg::parse(ctx, &node)?),
"flag" => schema.cmd.flags.push(Flag::parse(ctx, &node)?),
"cmd" => {
let node: SchemaCmd = SchemaCmd::parse(ctx, &node)?;
let node: SpecCommand = SpecCommand::parse(ctx, &node)?;
schema.cmd.subcommands.insert(node.name.to_string(), node);
}
"config" => schema.config = SpecConfig::parse(ctx, &node)?,
Expand Down Expand Up @@ -128,7 +128,7 @@ fn split_script(file: &Path) -> Result<(String, String), UsageErr> {
Ok((schema, body))
}

fn set_subcommand_ancestors(cmd: &mut SchemaCmd, ancestors: &[String]) {
fn set_subcommand_ancestors(cmd: &mut SpecCommand, ancestors: &[String]) {
let ancestors = ancestors.to_vec();
for subcmd in cmd.subcommands.values_mut() {
subcmd.full_cmd = ancestors
Expand Down

0 comments on commit c6c830a

Please sign in to comment.