mirror of
https://github.com/uutils/coreutils
synced 2024-12-14 15:22:38 +00:00
Merge pull request #4385 from cakebaker/uucore_procs_help_about
uucore_procs: extract "about" and "usage" info from new help structure
This commit is contained in:
commit
f77a44df8b
17 changed files with 133 additions and 74 deletions
|
@ -1,12 +1,9 @@
|
|||
# base32
|
||||
|
||||
## Usage
|
||||
```
|
||||
base32 [OPTION]... [FILE]
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
encode/decode data and print to standard output
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
use std::io::{stdin, Read};
|
||||
|
||||
use clap::Command;
|
||||
use uucore::{encoding::Format, error::UResult, help_section, help_usage};
|
||||
use uucore::{encoding::Format, error::UResult, help_about, help_usage};
|
||||
|
||||
pub mod base_common;
|
||||
|
||||
const ABOUT: &str = help_section!("about", "base32.md");
|
||||
const ABOUT: &str = help_about!("base32.md");
|
||||
const USAGE: &str = help_usage!("base32.md");
|
||||
|
||||
#[uucore::main]
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
# base64
|
||||
|
||||
## Usage
|
||||
```
|
||||
base64 [OPTION]... [FILE]
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
encode/decode data and print to standard output
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
use uu_base32::base_common;
|
||||
pub use uu_base32::uu_app;
|
||||
|
||||
use uucore::{encoding::Format, error::UResult, help_section, help_usage};
|
||||
use uucore::{encoding::Format, error::UResult, help_about, help_usage};
|
||||
|
||||
use std::io::{stdin, Read};
|
||||
|
||||
const ABOUT: &str = help_section!("about", "base64.md");
|
||||
const ABOUT: &str = help_about!("base64.md");
|
||||
const USAGE: &str = help_usage!("base64.md");
|
||||
|
||||
#[uucore::main]
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
# cat
|
||||
|
||||
## Usage
|
||||
```
|
||||
cat [OPTION]... [FILE]...
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
Concatenate FILE(s), or standard input, to standard output
|
||||
With no FILE, or when FILE is -, read standard input.
|
||||
|
|
|
@ -33,10 +33,10 @@ use std::net::Shutdown;
|
|||
use std::os::unix::fs::FileTypeExt;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::net::UnixStream;
|
||||
use uucore::{format_usage, help_section, help_usage};
|
||||
use uucore::{format_usage, help_about, help_usage};
|
||||
|
||||
const USAGE: &str = help_usage!("cat.md");
|
||||
const ABOUT: &str = help_section!("about", "cat.md");
|
||||
const ABOUT: &str = help_about!("cat.md");
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
enum CatError {
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
# cp
|
||||
|
||||
## Usage
|
||||
```
|
||||
cp [OPTION]... [-T] SOURCE DEST
|
||||
cp [OPTION]... SOURCE... DIRECTORY
|
||||
cp [OPTION]... -t DIRECTORY SOURCE...
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.
|
||||
|
|
|
@ -40,7 +40,7 @@ use uucore::error::{set_exit_code, UClapError, UError, UResult, UUsageError};
|
|||
use uucore::fs::{
|
||||
canonicalize, paths_refer_to_same_file, FileInformation, MissingHandling, ResolveMode,
|
||||
};
|
||||
use uucore::{crash, format_usage, help_section, help_usage, prompt_yes, show_error, show_warning};
|
||||
use uucore::{crash, format_usage, help_about, help_usage, prompt_yes, show_error, show_warning};
|
||||
|
||||
use crate::copydir::copy_directory;
|
||||
|
||||
|
@ -228,11 +228,11 @@ pub struct Options {
|
|||
progress_bar: bool,
|
||||
}
|
||||
|
||||
const ABOUT: &str = help_section!("about", "cp.md");
|
||||
static EXIT_ERR: i32 = 1;
|
||||
|
||||
const ABOUT: &str = help_about!("cp.md");
|
||||
const USAGE: &str = help_usage!("cp.md");
|
||||
|
||||
static EXIT_ERR: i32 = 1;
|
||||
|
||||
// Argument constants
|
||||
mod options {
|
||||
pub const ARCHIVE: &str = "archive";
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
<!-- spell-checker:ignore convs iseek oseek -->
|
||||
# dd
|
||||
|
||||
## About
|
||||
```
|
||||
dd [OPERAND]...
|
||||
dd OPTION
|
||||
```
|
||||
|
||||
Copy, and optionally convert, a file system resource
|
||||
|
||||
## After Help
|
||||
|
|
|
@ -39,11 +39,11 @@ use clap::{crate_version, Arg, Command};
|
|||
use gcd::Gcd;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{FromIo, UResult};
|
||||
use uucore::help_section;
|
||||
use uucore::show_error;
|
||||
use uucore::{format_usage, help_about, help_section, help_usage, show_error};
|
||||
|
||||
const ABOUT: &str = help_section!("about", "dd.md");
|
||||
const ABOUT: &str = help_about!("dd.md");
|
||||
const AFTER_HELP: &str = help_section!("after help", "dd.md");
|
||||
const USAGE: &str = help_usage!("dd.md");
|
||||
const BUF_INIT_BYTE: u8 = 0xDD;
|
||||
|
||||
/// Final settings after parsing
|
||||
|
@ -832,6 +832,7 @@ pub fn uu_app() -> Command {
|
|||
Command::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(ABOUT)
|
||||
.override_usage(format_usage(USAGE))
|
||||
.after_help(AFTER_HELP)
|
||||
.infer_long_args(true)
|
||||
.arg(Arg::new(options::OPERANDS).num_args(1..))
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
# expr
|
||||
|
||||
## About
|
||||
|
||||
Print the value of `EXPRESSION` to standard output
|
||||
|
||||
## Usage
|
||||
```
|
||||
expr [EXPRESSION]
|
||||
expr [OPTIONS]
|
||||
```
|
||||
|
||||
Print the value of `EXPRESSION` to standard output
|
||||
|
||||
## After help
|
||||
|
||||
Print the value of `EXPRESSION` to standard output. A blank line below
|
||||
|
@ -58,4 +55,4 @@ Environment variables:
|
|||
- `EXPR_DEBUG_TOKENS=1`: dump expression's tokens
|
||||
- `EXPR_DEBUG_RPN=1`: dump expression represented in reverse polish notation
|
||||
- `EXPR_DEBUG_SYA_STEP=1`: dump each parser step
|
||||
- `EXPR_DEBUG_AST=1`: dump expression represented abstract syntax tree
|
||||
- `EXPR_DEBUG_AST=1`: dump expression represented abstract syntax tree
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
use clap::{crate_version, Arg, ArgAction, Command};
|
||||
use uucore::{
|
||||
error::{UResult, USimpleError},
|
||||
format_usage, help_section, help_usage,
|
||||
format_usage, help_about, help_section, help_usage,
|
||||
};
|
||||
|
||||
mod syntax_tree;
|
||||
|
@ -23,7 +23,7 @@ mod options {
|
|||
pub fn uu_app() -> Command {
|
||||
Command::new(uucore::util_name())
|
||||
.version(crate_version!())
|
||||
.about(help_section!("about", "expr.md"))
|
||||
.about(help_about!("expr.md"))
|
||||
.override_usage(format_usage(help_usage!("expr.md")))
|
||||
.after_help(help_section!("after help", "expr.md"))
|
||||
.infer_long_args(true)
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
<!-- spell-checker:ignore N'th M'th -->
|
||||
# numfmt
|
||||
|
||||
## Usage
|
||||
```
|
||||
numfmt [OPTION]... [NUMBER]...
|
||||
```
|
||||
|
||||
## About
|
||||
|
||||
Convert numbers from/to human-readable strings
|
||||
|
||||
## After Help
|
||||
|
|
|
@ -14,16 +14,15 @@ use std::io::{BufRead, Write};
|
|||
use units::{IEC_BASES, SI_BASES};
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::UResult;
|
||||
use uucore::format_usage;
|
||||
use uucore::ranges::Range;
|
||||
use uucore::{help_section, help_usage};
|
||||
use uucore::{format_usage, help_about, help_section, help_usage};
|
||||
|
||||
pub mod errors;
|
||||
pub mod format;
|
||||
pub mod options;
|
||||
mod units;
|
||||
|
||||
const ABOUT: &str = help_section!("about", "numfmt.md");
|
||||
const ABOUT: &str = help_about!("numfmt.md");
|
||||
const AFTER_HELP: &str = help_section!("after help", "numfmt.md");
|
||||
const USAGE: &str = help_usage!("numfmt.md");
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@ use uucore::fsext::{
|
|||
pretty_filetype, pretty_fstype, pretty_time, read_fs_list, statfs, BirthTime, FsMeta,
|
||||
};
|
||||
use uucore::libc::mode_t;
|
||||
use uucore::{entries, format_usage, help_section, help_usage, show_error, show_warning};
|
||||
use uucore::{
|
||||
entries, format_usage, help_about, help_section, help_usage, show_error, show_warning,
|
||||
};
|
||||
|
||||
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
|
||||
use std::borrow::Cow;
|
||||
|
@ -24,7 +26,7 @@ use std::os::unix::fs::{FileTypeExt, MetadataExt};
|
|||
use std::os::unix::prelude::OsStrExt;
|
||||
use std::path::Path;
|
||||
|
||||
const ABOUT: &str = help_section!("about", "stat.md");
|
||||
const ABOUT: &str = help_about!("stat.md");
|
||||
const USAGE: &str = help_usage!("stat.md");
|
||||
const LONG_USAGE: &str = help_section!("long usage", "stat.md");
|
||||
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
# stat
|
||||
|
||||
## About
|
||||
|
||||
Display file or file system status.
|
||||
|
||||
## Usage
|
||||
```
|
||||
stat [OPTION]... FILE...
|
||||
```
|
||||
|
||||
Display file or file system status.
|
||||
|
||||
## Long Usage
|
||||
|
||||
The valid format sequences for files (without `--file-system`):
|
||||
|
|
|
@ -7,6 +7,8 @@ use std::{fs::File, io::Read, path::PathBuf};
|
|||
use proc_macro::{Literal, TokenStream, TokenTree};
|
||||
use quote::quote;
|
||||
|
||||
const MARKDOWN_CODE_FENCES: &str = "```";
|
||||
|
||||
//## rust proc-macro background info
|
||||
//* ref: <https://dev.to/naufraghi/procedural-macro-in-rust-101-k3f> @@ <http://archive.is/Vbr5e>
|
||||
//* ref: [path construction from LitStr](https://oschwald.github.io/maxminddb-rust/syn/struct.LitStr.html) @@ <http://archive.is/8YDua>
|
||||
|
@ -51,7 +53,19 @@ fn render_markdown(s: &str) -> String {
|
|||
s.replace('`', "")
|
||||
}
|
||||
|
||||
/// Get the usage from the "Usage" section in the help file.
|
||||
/// Get the about text from the help file.
|
||||
///
|
||||
/// The about text is assumed to be the text between the first markdown
|
||||
/// code block and the next header, if any. It may span multiple lines.
|
||||
#[proc_macro]
|
||||
pub fn help_about(input: TokenStream) -> TokenStream {
|
||||
let input: Vec<TokenTree> = input.into_iter().collect();
|
||||
let filename = get_argument(&input, 0, "filename");
|
||||
let text: String = parse_about(&read_help(&filename));
|
||||
TokenTree::Literal(Literal::string(&text)).into()
|
||||
}
|
||||
|
||||
/// Get the usage from the help file.
|
||||
///
|
||||
/// The usage is assumed to be surrounded by markdown code fences. It may span
|
||||
/// multiple lines. The first word of each line is assumed to be the name of
|
||||
|
@ -61,7 +75,7 @@ fn render_markdown(s: &str) -> String {
|
|||
pub fn help_usage(input: TokenStream) -> TokenStream {
|
||||
let input: Vec<TokenTree> = input.into_iter().collect();
|
||||
let filename = get_argument(&input, 0, "filename");
|
||||
let text: String = parse_usage(&parse_help("usage", &filename));
|
||||
let text: String = parse_usage(&read_help(&filename));
|
||||
TokenTree::Literal(Literal::string(&text)).into()
|
||||
}
|
||||
|
||||
|
@ -94,7 +108,7 @@ pub fn help_section(input: TokenStream) -> TokenStream {
|
|||
let input: Vec<TokenTree> = input.into_iter().collect();
|
||||
let section = get_argument(&input, 0, "section");
|
||||
let filename = get_argument(&input, 1, "filename");
|
||||
let text = parse_help(§ion, &filename);
|
||||
let text = parse_help_section(§ion, &read_help(&filename));
|
||||
let rendered = render_markdown(&text);
|
||||
TokenTree::Literal(Literal::string(&rendered)).into()
|
||||
}
|
||||
|
@ -121,13 +135,11 @@ fn get_argument(input: &[TokenTree], index: usize, name: &str) -> String {
|
|||
.to_string()
|
||||
}
|
||||
|
||||
/// Read the help file and extract a section
|
||||
fn parse_help(section: &str, filename: &str) -> String {
|
||||
let section = section.to_lowercase();
|
||||
let section = section.trim_matches('"');
|
||||
/// Read the help file
|
||||
fn read_help(filename: &str) -> String {
|
||||
let mut content = String::new();
|
||||
let mut path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
|
||||
let mut path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
path.push(filename);
|
||||
|
||||
File::open(path)
|
||||
|
@ -135,7 +147,7 @@ fn parse_help(section: &str, filename: &str) -> String {
|
|||
.read_to_string(&mut content)
|
||||
.unwrap();
|
||||
|
||||
parse_help_section(section, &content)
|
||||
content
|
||||
}
|
||||
|
||||
/// Get a single section from content
|
||||
|
@ -147,6 +159,8 @@ fn parse_help_section(section: &str, content: &str) -> String {
|
|||
.map_or(false, |l| l.trim().to_lowercase() == section)
|
||||
}
|
||||
|
||||
let section = §ion.to_lowercase();
|
||||
|
||||
// We cannot distinguish between an empty or non-existing section below,
|
||||
// so we do a quick test to check whether the section exists to provide
|
||||
// a nice error message.
|
||||
|
@ -167,17 +181,17 @@ fn parse_help_section(section: &str, content: &str) -> String {
|
|||
.to_string()
|
||||
}
|
||||
|
||||
/// Parses a markdown code block into a usage string
|
||||
/// Parses the first markdown code block into a usage string
|
||||
///
|
||||
/// The code fences are removed and the name of the util is replaced
|
||||
/// with `{}` so that it can be replaced with the appropriate name
|
||||
/// at runtime.
|
||||
fn parse_usage(content: &str) -> String {
|
||||
content
|
||||
.strip_suffix("```")
|
||||
.unwrap()
|
||||
.lines()
|
||||
.skip(1) // Skip the "```" of markdown syntax
|
||||
.skip_while(|l| !l.starts_with(MARKDOWN_CODE_FENCES))
|
||||
.skip(1)
|
||||
.take_while(|l| !l.starts_with(MARKDOWN_CODE_FENCES))
|
||||
.map(|l| {
|
||||
// Replace the util name (assumed to be the first word) with "{}"
|
||||
// to be replaced with the runtime value later.
|
||||
|
@ -187,12 +201,31 @@ fn parse_usage(content: &str) -> String {
|
|||
"{}\n".to_string()
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
.collect::<Vec<_>>()
|
||||
.join("")
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Parses the text between the first markdown code block and the next header, if any,
|
||||
/// into an about string.
|
||||
fn parse_about(content: &str) -> String {
|
||||
content
|
||||
.lines()
|
||||
.skip_while(|l| !l.starts_with(MARKDOWN_CODE_FENCES))
|
||||
.skip(1)
|
||||
.skip_while(|l| !l.starts_with(MARKDOWN_CODE_FENCES))
|
||||
.skip(1)
|
||||
.take_while(|l| !l.starts_with('#'))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{parse_help_section, parse_usage};
|
||||
use super::{parse_about, parse_help_section, parse_usage};
|
||||
|
||||
#[test]
|
||||
fn section_parsing() {
|
||||
|
@ -209,6 +242,10 @@ mod tests {
|
|||
parse_help_section("some section", input),
|
||||
"This is some section"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_help_section("SOME SECTION", input),
|
||||
"This is some section"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_help_section("another section", input),
|
||||
"This is the other section\nwith multiple lines"
|
||||
|
@ -233,7 +270,6 @@ mod tests {
|
|||
fn usage_parsing() {
|
||||
let input = "\
|
||||
# ls\n\
|
||||
## Usage\n\
|
||||
```\n\
|
||||
ls -l\n\
|
||||
```\n\
|
||||
|
@ -244,17 +280,55 @@ mod tests {
|
|||
This is the other section\n\
|
||||
with multiple lines\n";
|
||||
|
||||
assert_eq!(parse_usage(&parse_help_section("usage", input)), "{} -l",);
|
||||
assert_eq!(parse_usage(input), "{} -l");
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
parse_usage(
|
||||
"\
|
||||
```\n\
|
||||
util [some] [options]\n\
|
||||
```\
|
||||
"
|
||||
),
|
||||
"{} [some] [options]"
|
||||
);
|
||||
#[test]
|
||||
fn multi_line_usage_parsing() {
|
||||
let input = "\
|
||||
# ls\n\
|
||||
```\n\
|
||||
ls -a\n\
|
||||
ls -b\n\
|
||||
ls -c\n\
|
||||
```\n\
|
||||
## some section\n\
|
||||
This is some section\n";
|
||||
|
||||
assert_eq!(parse_usage(input), "{} -a\n{} -b\n{} -c");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn about_parsing() {
|
||||
let input = "\
|
||||
# ls\n\
|
||||
```\n\
|
||||
ls -l\n\
|
||||
```\n\
|
||||
\n\
|
||||
This is the about section\n\
|
||||
\n\
|
||||
## some section\n\
|
||||
This is some section\n";
|
||||
|
||||
assert_eq!(parse_about(input), "This is the about section");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_line_about_parsing() {
|
||||
let input = "\
|
||||
# ls\n\
|
||||
```\n\
|
||||
ls -l\n\
|
||||
```\n\
|
||||
\n\
|
||||
about a\n\
|
||||
\n\
|
||||
about b\n\
|
||||
\n\
|
||||
## some section\n\
|
||||
This is some section\n";
|
||||
|
||||
assert_eq!(parse_about(input), "about a\n\nabout b");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue