mirror of
https://github.com/uutils/uutils-args.git
synced 2026-06-10 16:13:08 -07:00
add value names for flags in md and man
This commit is contained in:
+27
-15
@@ -1,19 +1,22 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use crate::{Command, ValueHint};
|
||||
use crate::{Command, Flag, ValueHint};
|
||||
|
||||
/// Create completion script for `fish`
|
||||
///
|
||||
/// Short and long options are combined into single `complete` calls, even if
|
||||
/// they differ in whether they take arguments or not.
|
||||
pub fn render(c: &Command) -> String {
|
||||
let mut out = String::new();
|
||||
let name = &c.name;
|
||||
for arg in &c.args {
|
||||
let mut line = format!("complete -c {name}");
|
||||
for short in &arg.short {
|
||||
line.push_str(&format!(" -s {short}"));
|
||||
for Flag { flag, .. } in &arg.short {
|
||||
line.push_str(&format!(" -s {flag}"));
|
||||
}
|
||||
for long in &arg.long {
|
||||
line.push_str(&format!(" -l {long}"));
|
||||
for Flag { flag, .. } in &arg.long {
|
||||
line.push_str(&format!(" -l {flag}"));
|
||||
}
|
||||
line.push_str(&format!(" -d '{}'", arg.help));
|
||||
if let Some(value) = &arg.value {
|
||||
@@ -42,15 +45,18 @@ fn render_value_hint(value: &ValueHint) -> String {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::render;
|
||||
use crate::{Arg, Command, ValueHint};
|
||||
use crate::{Arg, Command, Flag, Value, ValueHint};
|
||||
|
||||
#[test]
|
||||
fn short() {
|
||||
let c = Command {
|
||||
name: "test".into(),
|
||||
name: "test",
|
||||
args: vec![Arg {
|
||||
short: vec!["a".into()],
|
||||
help: "some flag".into(),
|
||||
short: vec![Flag {
|
||||
flag: "a",
|
||||
value: Value::No,
|
||||
}],
|
||||
help: "some flag",
|
||||
..Arg::default()
|
||||
}],
|
||||
..Command::default()
|
||||
@@ -61,10 +67,13 @@ mod test {
|
||||
#[test]
|
||||
fn long() {
|
||||
let c = Command {
|
||||
name: "test".into(),
|
||||
name: "test",
|
||||
args: vec![Arg {
|
||||
long: vec!["all".into()],
|
||||
help: "some flag".into(),
|
||||
long: vec![Flag {
|
||||
flag: "all",
|
||||
value: Value::No,
|
||||
}],
|
||||
help: "some flag",
|
||||
..Arg::default()
|
||||
}],
|
||||
..Command::default()
|
||||
@@ -92,11 +101,14 @@ mod test {
|
||||
];
|
||||
for (hint, expected) in args {
|
||||
let c = Command {
|
||||
name: "test".into(),
|
||||
name: "test",
|
||||
args: vec![Arg {
|
||||
short: vec!["a".into()],
|
||||
short: vec![Flag {
|
||||
flag: "a",
|
||||
value: Value::No,
|
||||
}],
|
||||
long: vec![],
|
||||
help: "some flag".into(),
|
||||
help: "some flag",
|
||||
value: Some(hint),
|
||||
}],
|
||||
..Command::default()
|
||||
|
||||
+40
-10
@@ -1,28 +1,58 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
//! Generation of completion and documentation
|
||||
//!
|
||||
//! All formats use the [`Command`] struct as input, which specifies all
|
||||
//! information needed. This struct is similar to some structs in the derive
|
||||
//! crate for uutils-args, but there are some key differences:
|
||||
//!
|
||||
//! - This is meant to be more general.
|
||||
//! - Some information is added (such as fields for the summary)
|
||||
//! - We have [`ValueHint`] in this crate.
|
||||
//! - Some information is removed because it is irrelevant for completion and documentation
|
||||
//! - This struct is meant to exist at runtime of the program
|
||||
//!
|
||||
mod fish;
|
||||
mod man;
|
||||
mod md;
|
||||
mod zsh;
|
||||
|
||||
/// A description of a CLI command
|
||||
///
|
||||
/// The completions and documentation will be generated based on this struct.
|
||||
#[derive(Default)]
|
||||
pub struct Command {
|
||||
pub name: String,
|
||||
pub summary: String,
|
||||
pub version: String,
|
||||
pub after_options: String,
|
||||
pub args: Vec<Arg>,
|
||||
pub struct Command<'a> {
|
||||
pub name: &'a str,
|
||||
pub summary: &'a str,
|
||||
pub version: &'a str,
|
||||
pub after_options: &'a str,
|
||||
pub args: Vec<Arg<'a>>,
|
||||
}
|
||||
|
||||
/// Description of an argument
|
||||
///
|
||||
/// An argument may consist of several flags. In completions and documentation
|
||||
/// formats that support it, these flags will be grouped.
|
||||
#[derive(Default)]
|
||||
pub struct Arg {
|
||||
pub short: Vec<String>,
|
||||
pub long: Vec<String>,
|
||||
pub help: String,
|
||||
pub struct Arg<'a> {
|
||||
pub short: Vec<Flag<'a>>,
|
||||
pub long: Vec<Flag<'a>>,
|
||||
pub help: &'a str,
|
||||
pub value: Option<ValueHint>,
|
||||
}
|
||||
|
||||
pub struct Flag<'a> {
|
||||
pub flag: &'a str,
|
||||
pub value: Value<'a>,
|
||||
}
|
||||
|
||||
pub enum Value<'a> {
|
||||
Required(&'a str),
|
||||
Optional(&'a str),
|
||||
No,
|
||||
}
|
||||
|
||||
// Modelled after claps ValueHint
|
||||
pub enum ValueHint {
|
||||
Strings(Vec<String>),
|
||||
|
||||
+34
-9
@@ -1,36 +1,61 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use crate::Command;
|
||||
use roff::{bold, roman, Roff};
|
||||
use crate::{Command, Flag, Value};
|
||||
use roff::{bold, italic, roman, Roff};
|
||||
|
||||
pub fn render(c: &Command) -> String {
|
||||
let mut page = Roff::new();
|
||||
page.control("TH", [&c.name.to_uppercase(), "1"]);
|
||||
page.control("SH", ["NAME"]);
|
||||
page.text([roman(&c.name)]);
|
||||
page.text([roman(c.name)]);
|
||||
page.control("SH", ["DESCRIPTION"]);
|
||||
page.text([roman(&c.summary)]);
|
||||
page.text([roman(c.summary)]);
|
||||
page.control("SH", ["OPTIONS"]);
|
||||
|
||||
for arg in &c.args {
|
||||
page.control("TP", []);
|
||||
|
||||
let mut flags = Vec::new();
|
||||
for l in &arg.long {
|
||||
for Flag { flag, value } in &arg.long {
|
||||
if !flags.is_empty() {
|
||||
flags.push(roman(", "));
|
||||
}
|
||||
flags.push(bold(format!("--{l}")));
|
||||
flags.push(bold(format!("--{flag}")));
|
||||
match value {
|
||||
Value::Required(name) => {
|
||||
flags.push(roman("="));
|
||||
flags.push(italic(*name));
|
||||
}
|
||||
Value::Optional(name) => {
|
||||
flags.push(roman("["));
|
||||
flags.push(roman("="));
|
||||
flags.push(italic(*name));
|
||||
flags.push(roman("]"));
|
||||
}
|
||||
Value::No => {}
|
||||
}
|
||||
}
|
||||
for s in &arg.short {
|
||||
for Flag { flag, value } in &arg.short {
|
||||
if !flags.is_empty() {
|
||||
flags.push(roman(", "));
|
||||
}
|
||||
flags.push(bold(format!("-{s}")));
|
||||
flags.push(bold(format!("-{flag}")));
|
||||
match value {
|
||||
Value::Required(name) => {
|
||||
flags.push(roman(" "));
|
||||
flags.push(italic(*name));
|
||||
}
|
||||
Value::Optional(name) => {
|
||||
flags.push(roman("["));
|
||||
flags.push(italic(*name));
|
||||
flags.push(roman("]"));
|
||||
}
|
||||
Value::No => {}
|
||||
}
|
||||
}
|
||||
page.text(flags);
|
||||
page.text([roman(&arg.help)]);
|
||||
page.text([roman(arg.help)]);
|
||||
}
|
||||
page.render()
|
||||
}
|
||||
|
||||
+17
-7
@@ -1,18 +1,18 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use crate::Command;
|
||||
use crate::{Command, Flag, Value};
|
||||
|
||||
/// Render command to a markdown file for mdbook
|
||||
pub fn render(c: &Command) -> String {
|
||||
let mut out = String::new();
|
||||
out.push_str(&title(c));
|
||||
out.push_str(&additional(c));
|
||||
out.push_str(&c.summary);
|
||||
out.push_str(c.summary);
|
||||
out.push_str("\n\n");
|
||||
out.push_str(&options(c));
|
||||
out.push_str("\n\n");
|
||||
out.push_str(&c.after_options);
|
||||
out.push_str(c.after_options);
|
||||
out.push('\n');
|
||||
out
|
||||
}
|
||||
@@ -40,12 +40,22 @@ fn options(c: &Command) -> String {
|
||||
|
||||
let mut flags = Vec::new();
|
||||
|
||||
for long in &arg.long {
|
||||
flags.push(format!("<code>--{long}</code>"));
|
||||
for Flag { flag, value } in &arg.long {
|
||||
let value_str = match value {
|
||||
Value::Required(name) => format!("={name}"),
|
||||
Value::Optional(name) => format!("[={name}]"),
|
||||
Value::No => String::new(),
|
||||
};
|
||||
flags.push(format!("<code>--{flag}{value_str}</code>"));
|
||||
}
|
||||
|
||||
for short in &arg.short {
|
||||
flags.push(format!("<code>-{short}</code>"))
|
||||
for Flag { flag, value } in &arg.short {
|
||||
let value_str = match value {
|
||||
Value::Required(name) => format!(" {name}"),
|
||||
Value::Optional(name) => format!("[{name}]"),
|
||||
Value::No => String::new(),
|
||||
};
|
||||
flags.push(format!("<code>-{flag}{value_str}</code>"));
|
||||
}
|
||||
|
||||
out.push_str(&flags.join(", "));
|
||||
|
||||
+6
-6
@@ -1,11 +1,11 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use crate::{Arg, Command};
|
||||
use crate::{Arg, Command, Flag};
|
||||
|
||||
/// Create completion script for `zsh`
|
||||
pub fn render(c: &Command) -> String {
|
||||
template(&c.name, &render_args(&c.args))
|
||||
template(c.name, &render_args(&c.args))
|
||||
}
|
||||
|
||||
fn render_args(args: &[Arg]) -> String {
|
||||
@@ -13,11 +13,11 @@ fn render_args(args: &[Arg]) -> String {
|
||||
let indent = " ".repeat(8);
|
||||
for arg in args {
|
||||
let help = &arg.help;
|
||||
for short in &arg.short {
|
||||
out.push_str(&format!("{indent}'-{short}[{help}]' \\\n"));
|
||||
for Flag { flag, .. } in &arg.short {
|
||||
out.push_str(&format!("{indent}'-{flag}[{help}]' \\\n"));
|
||||
}
|
||||
for long in &arg.long {
|
||||
out.push_str(&format!("{indent}'--{long}[{help}]' \\\n"));
|
||||
for Flag { flag, .. } in &arg.long {
|
||||
out.push_str(&format!("{indent}'--{flag}[{help}]' \\\n"));
|
||||
}
|
||||
}
|
||||
out
|
||||
|
||||
Reference in New Issue
Block a user