11use crate :: args:: Args ;
22use clap:: { Arg , ArgAction , Command , CommandFactory } ;
3+ use itertools:: Itertools ;
34use std:: { borrow:: Cow , collections:: BTreeMap , fmt:: Write } ;
45
56/// A map from argument ID to the set of argument IDs it conflicts with (bidirectional).
@@ -73,21 +74,20 @@ fn render_name_section(out: &mut String, command: &Command) {
7374
7475fn render_synopsis_section ( out : & mut String , command : & Command ) {
7576 out. push_str ( ".SH SYNOPSIS\n " ) ;
76- out. push_str ( & format ! ( "\\ fB{}\\ fR" , command. get_name( ) ) ) ;
77- for arg in command. get_arguments ( ) {
78- if arg. is_positional ( ) {
79- continue ;
80- }
81- if arg. is_hide_set ( ) {
82- continue ;
83- }
77+ write ! ( out, "\\ fB{}\\ fR" , command. get_name( ) ) . unwrap ( ) ;
78+ let options = command
79+ . get_arguments ( )
80+ . filter ( |arg| !arg. is_positional ( ) )
81+ . filter ( |arg| !arg. is_hide_set ( ) ) ;
82+ for arg in options {
8483 out. push ( ' ' ) ;
8584 render_synopsis_option ( out, arg) ;
8685 }
87- for arg in command. get_arguments ( ) {
88- if !arg. is_positional ( ) || arg. is_hide_set ( ) {
89- continue ;
90- }
86+ let positionals = command
87+ . get_arguments ( )
88+ . filter ( |arg| arg. is_positional ( ) )
89+ . filter ( |arg| !arg. is_hide_set ( ) ) ;
90+ for arg in positionals {
9191 out. push ( ' ' ) ;
9292 render_synopsis_positional ( out, arg) ;
9393 }
@@ -202,17 +202,21 @@ fn render_option_header_positional(out: &mut String, arg: &Arg) {
202202}
203203
204204fn render_option_header_flag ( out : & mut String , arg : & Arg ) {
205- let mut parts = Vec :: new ( ) ;
206- if let Some ( short) = arg. get_short ( ) {
207- parts. push ( format ! ( "\\ fB\\ -{}\\ fR" , roff_escape( & short. to_string( ) ) ) ) ;
208- }
209- if let Some ( long) = arg. get_long ( ) {
210- parts. push ( format ! ( "\\ fB\\ -\\ -{}\\ fR" , roff_escape( long) ) ) ;
211- }
212- for alias in arg. get_visible_aliases ( ) . unwrap_or_default ( ) {
213- parts. push ( format ! ( "\\ fB\\ -\\ -{}\\ fR" , roff_escape( alias) ) ) ;
214- }
215- let header = parts. join ( ", " ) ;
205+ let short = arg
206+ . get_short ( )
207+ . map ( |short| roff_escape ( & short. to_string ( ) ) )
208+ . map ( |short| format ! ( "\\ fB\\ -{short}\\ fR" ) ) ;
209+ let long = arg
210+ . get_long ( )
211+ . map ( roff_escape)
212+ . map ( |long| format ! ( "\\ fB\\ -\\ -{long}\\ fR" ) ) ;
213+ let aliases = arg
214+ . get_visible_aliases ( )
215+ . into_iter ( )
216+ . flatten ( )
217+ . map ( roff_escape)
218+ . map ( |arg| format ! ( "\\ fB\\ -\\ -{arg}\\ fR" ) ) ;
219+ let header = short. into_iter ( ) . chain ( long) . chain ( aliases) . join ( ", " ) ;
216220 if arg. get_action ( ) . takes_values ( ) {
217221 let value_str = render_value_hint ( arg) ;
218222 writeln ! ( out, "{header} {value_str}" ) . unwrap ( ) ;
@@ -222,25 +226,26 @@ fn render_option_header_flag(out: &mut String, arg: &Arg) {
222226}
223227
224228fn render_value_hint ( arg : & Arg ) -> String {
225- let mut parts = Vec :: new ( ) ;
226- if let Some ( value_names) = arg. get_value_names ( ) {
227- for name in value_names {
228- parts. push ( format ! ( "\\ fI<{}>\\ fR" , roff_escape( name) ) ) ;
229- }
230- } else {
231- parts. push ( format ! ( "\\ fI<{}>\\ fR" , roff_escape( arg. get_id( ) . as_str( ) ) ) ) ;
232- }
233- let value_part = parts. join ( " " ) ;
229+ let value_part = arg
230+ . get_value_names ( )
231+ . map ( <[ _ ] >:: iter)
232+ . map ( |names| names. map ( |name| name. as_str ( ) ) )
233+ . map ( |names| names. collect :: < Vec < _ > > ( ) )
234+ . unwrap_or_else ( || vec ! [ arg. get_id( ) . as_str( ) ] )
235+ . into_iter ( )
236+ . map ( roff_escape)
237+ . map ( |name| format ! ( "\\ fI<{name}>\\ fR" ) )
238+ . join ( " " ) ;
234239 let defaults: Vec < _ > = arg
235240 . get_default_values ( )
236241 . iter ( )
237242 . map ( |value| value. to_string_lossy ( ) )
238243 . map ( Cow :: into_owned)
239244 . collect ( ) ;
240- if defaults. is_empty ( )
245+ let hide_defaults = defaults. is_empty ( )
241246 || arg. is_hide_default_value_set ( )
242- || matches ! ( arg. get_action( ) , ArgAction :: SetTrue )
243- {
247+ || matches ! ( arg. get_action( ) , ArgAction :: SetTrue ) ;
248+ if hide_defaults {
244249 value_part
245250 } else {
246251 format ! ( "{value_part} [default: {}]" , defaults. join( ", " ) )
@@ -289,23 +294,15 @@ fn render_possible_values(out: &mut String, arg: &Arg) {
289294
290295fn render_conflicts ( out : & mut String , command : & Command , arg : & Arg , conflict_map : & ConflictMap ) {
291296 let arg_id = arg. get_id ( ) . as_str ( ) ;
292- let conflict_ids = match conflict_map. get ( arg_id) {
293- Some ( ids) if !ids. is_empty ( ) => ids,
294- _ => return ,
295- } ;
296- let conflict_names: Vec < _ > = conflict_ids
297- . iter ( )
298- . filter_map ( |conflict_id| resolve_flag_name ( command, conflict_id) )
299- . collect ( ) ;
300- if conflict_names. is_empty ( ) {
301- return ;
297+ let conflicts = conflict_map
298+ . get ( arg_id)
299+ . into_iter ( )
300+ . flatten ( )
301+ . filter_map ( |id| resolve_flag_name ( command, id) )
302+ . join ( ", " ) ;
303+ if !conflicts. is_empty ( ) {
304+ writeln ! ( out, ".RS\n .PP\n Cannot be used with {conflicts}.\n .RE" ) . unwrap ( ) ;
302305 }
303- writeln ! (
304- out,
305- ".RS\n .PP\n Cannot be used with {}.\n .RE" ,
306- conflict_names. join( ", " )
307- )
308- . unwrap ( ) ;
309306}
310307
311308fn render_examples_section ( out : & mut String , command : & Command ) {
0 commit comments