diff --git a/complete/src/fish.rs b/complete/src/fish.rs index 3571b01..f86fc93 100644 --- a/complete/src/fish.rs +++ b/complete/src/fish.rs @@ -3,6 +3,7 @@ use crate::{Command, ValueHint}; +/// Create completion script for `fish` pub fn render(c: &Command) -> String { let mut out = String::new(); let name = &c.name; @@ -52,6 +53,7 @@ mod test { help: "some flag".into(), ..Arg::default() }], + ..Command::default() }; assert_eq!(render(&c), "complete -c test -s a -d 'some flag'\n",) } @@ -65,6 +67,7 @@ mod test { help: "some flag".into(), ..Arg::default() }], + ..Command::default() }; assert_eq!(render(&c), "complete -c test -l all -d 'some flag'\n",) } @@ -96,6 +99,7 @@ mod test { help: "some flag".into(), value: Some(hint), }], + ..Command::default() }; assert_eq!( render(&c), diff --git a/complete/src/lib.rs b/complete/src/lib.rs index a6e5365..4504797 100644 --- a/complete/src/lib.rs +++ b/complete/src/lib.rs @@ -2,10 +2,15 @@ // file that was distributed with this source code. mod fish; +mod md; mod zsh; +#[derive(Default)] pub struct Command { pub name: String, + pub summary: String, + pub version: String, + pub after_options: String, pub args: Vec, } @@ -31,9 +36,11 @@ pub enum ValueHint { pub fn render(c: &Command, shell: &str) -> String { match shell { + "md" => md::render(c), "fish" => fish::render(c), "zsh" => zsh::render(c), - "sh" | "bash" | "csh" | "elvish" | "powershell" => panic!("shell '{shell}' completion is not supported yet!"), - _ => panic!("unknown shell '{shell}'!"), + "man" => panic!("manpages are not implemented yet"), + "sh" | "bash" | "csh" | "elvish" | "powershell" => panic!("shell '{shell}' completion is not implemented yet!"), + _ => panic!("unknown option '{shell}'! Expected one of: \"md\", \"fish\", \"zsh\", \"man\", \"sh\", \"bash\", \"csh\", \"elvish\", \"powershell\""), } } diff --git a/complete/src/md.rs b/complete/src/md.rs new file mode 100644 index 0000000..08f502f --- /dev/null +++ b/complete/src/md.rs @@ -0,0 +1,57 @@ +// For the full copyright and license information, please view the LICENSE +// file that was distributed with this source code. + +use crate::Command; + +/// 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("\n\n"); + out.push_str(&options(c)); + out.push_str("\n\n"); + out.push_str(&c.after_options); + out.push('\n'); + out +} + +fn title(c: &Command) -> String { + format!("# {}\n\n", c.name) +} + +fn additional(c: &Command) -> String { + let version = &c.version; + format!( + "\ +
\ + {version}\ +
\n\n\ + " + ) +} + +fn options(c: &Command) -> String { + let mut out = String::from("## Options\n\n"); + out.push_str("
\n"); + for arg in &c.args { + out.push_str("
"); + + let mut flags = Vec::new(); + + for long in &arg.long { + flags.push(format!("--{long}")); + } + + for short in &arg.short { + flags.push(format!("-{short}")) + } + + out.push_str(&flags.join(", ")); + out.push_str("
\n"); + out.push_str(&format!("
\n\n{}\n\n
\n", arg.help)); + } + out.push_str("
"); + out +} diff --git a/complete/src/zsh.rs b/complete/src/zsh.rs index 143596f..814c904 100644 --- a/complete/src/zsh.rs +++ b/complete/src/zsh.rs @@ -1,8 +1,9 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::{Command, Arg}; +use crate::{Arg, Command}; +/// Create completion script for `zsh` pub fn render(c: &Command) -> String { template(&c.name, &render_args(&c.args)) } @@ -13,14 +14,10 @@ fn render_args(args: &[Arg]) -> String { for arg in args { let help = &arg.help; for short in &arg.short { - out.push_str( - &format!("{indent}'-{short}[{help}]' \\\n") - ); + out.push_str(&format!("{indent}'-{short}[{help}]' \\\n")); } for long in &arg.long { - out.push_str( - &format!("{indent}'--{long}[{help}]' \\\n") - ); + out.push_str(&format!("{indent}'--{long}[{help}]' \\\n")); } } out @@ -55,4 +52,4 @@ else compdef _{name} {name} fi" ) -} \ No newline at end of file +} diff --git a/derive/src/complete.rs b/derive/src/complete.rs index b2d4bae..2d7b365 100644 --- a/derive/src/complete.rs +++ b/derive/src/complete.rs @@ -8,9 +8,15 @@ use crate::{ use proc_macro2::TokenStream; use quote::quote; -pub fn complete(args: &[Argument]) -> TokenStream { +pub fn complete(args: &[Argument], file: &Option) -> TokenStream { let mut arg_specs = Vec::new(); + let (summary, _usage, after_options) = if let Some(file) = file { + crate::help::read_help_file(file) + } else { + ("".into(), "{} [OPTIONS] [ARGUMENTS]".into(), "".into()) + }; + for Argument { help, field, @@ -60,6 +66,9 @@ pub fn complete(args: &[Argument]) -> TokenStream { quote!(Command { name: String::from(option_env!("CARGO_BIN_NAME").unwrap_or(env!("CARGO_PKG_NAME"))), + summary: String::from(#summary), + after_options: String::from(#after_options), + version: String::from(env!("CARGO_PKG_VERSION")), args: vec![#(#arg_specs),*] }) } diff --git a/derive/src/help.rs b/derive/src/help.rs index 877a3d8..9ebeaf2 100644 --- a/derive/src/help.rs +++ b/derive/src/help.rs @@ -99,7 +99,7 @@ pub fn help_string( ) } -fn read_help_file(file: &str) -> (String, String, String) { +pub fn read_help_file(file: &str) -> (String, String, String) { let path = Path::new(file); let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); let mut location = PathBuf::from(manifest_dir); diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 5df241f..e855127 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -45,7 +45,7 @@ pub fn arguments(input: TokenStream) -> TokenStream { &arguments_attr.version_flags, &arguments_attr.file, ); - let complete_command = complete::complete(&arguments); + let complete_command = complete::complete(&arguments, &arguments_attr.file); let help = help_handling(&arguments_attr.help_flags); let version = version_handling(&arguments_attr.version_flags); let version_string = quote!(format!(