From 6ef696ffc7aa0c50742248673fff37937f5bac64 Mon Sep 17 00:00:00 2001 From: SRetip Date: Mon, 13 May 2024 11:22:35 +0300 Subject: [PATCH 1/8] wip --- module/move/wca/src/ca/aggregator.rs | 23 ++++-- module/move/wca/src/ca/grammar/command.rs | 6 ++ module/move/wca/src/ca/help.rs | 69 +++++++++++++----- .../src/main.rs | 28 ++++++++ .../wca_help_test_nature_order/src/main.rs | 28 ++++++++ .../wca/tests/inc/commands_aggregator/help.rs | 72 +++++++++++++++++++ 6 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs create mode 100644 module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index 9c287326a7..4ee7e0a535 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -107,6 +107,10 @@ pub( crate ) mod private #[ default( Executor::former().form() ) ] executor : Executor, + #[ default( true ) ] + with_nature_sort : bool, + + command_order : Option< Vec< String > >, help_generator : Option< HelpGeneratorFn >, #[ default( HashSet::from([ HelpVariants::All ]) ) ] help_variants : HashSet< HelpVariants >, @@ -133,10 +137,14 @@ pub( crate ) mod private /// # Arguments /// /// * `name` - The name of the command. - pub fn command< IntoName >( self, name : IntoName ) -> CommandFormer< Self, impl former::FormingEnd< Command, Self > > + pub fn command< IntoName >( mut self, name : IntoName ) -> CommandFormer< Self, impl former::FormingEnd< Command, Self > > where IntoName : Into< String >, { + let name = name.into(); + let mut order = self.storage.command_order.unwrap_or_default(); + order.push(name.clone()); + self.storage.command_order = Some(order); let on_end = | command : Command, super_former : Option< Self > | -> Self { let mut super_former = super_former.unwrap(); @@ -234,16 +242,23 @@ pub( crate ) mod private let help_generator = std::mem::take( &mut ca.help_generator ).unwrap_or_default(); let help_variants = std::mem::take( &mut ca.help_variants ); - + let order = if ca.with_nature_sort + { + std::mem::take( &mut ca.command_order ) + } + else + { + None + }; if help_variants.contains( &HelpVariants::All ) { - HelpVariants::All.generate( &help_generator, &mut ca.dictionary ); + HelpVariants::All.generate( &help_generator, &mut ca.dictionary, order.clone() ); } else { for help in help_variants.iter().sorted() { - help.generate( &help_generator, &mut ca.dictionary ); + help.generate( &help_generator, &mut ca.dictionary, order.clone() ); } } diff --git a/module/move/wca/src/ca/grammar/command.rs b/module/move/wca/src/ca/grammar/command.rs index 7d61e0ac38..badb5380b2 100644 --- a/module/move/wca/src/ca/grammar/command.rs +++ b/module/move/wca/src/ca/grammar/command.rs @@ -100,6 +100,8 @@ pub( crate ) mod private pub subjects : Vec< ValueDescription >, /// Hints and types for command options. pub properties : HashMap< String, ValueDescription >, + /// + pub properties_order : Vec< String >, /// Map of aliases. // Aliased key -> Original key pub properties_aliases : HashMap< String, String >, @@ -209,6 +211,8 @@ pub( crate ) mod private { let mut super_former = super_former.unwrap(); let mut properties = super_former.storage.properties.unwrap_or_default(); + let mut order = super_former.storage.properties_order.unwrap_or_default(); + let value = ValueDescription { hint : property.hint, @@ -217,6 +221,7 @@ pub( crate ) mod private }; debug_assert!( !properties.contains_key( &property.name ), "Property name `{}` is already used for `{:?}`", property.name, properties[ &property.name ] ); properties.insert( property.name.clone(), value ); + order.push( property.name.clone() ); let mut aliases = super_former.storage.properties_aliases.unwrap_or_default(); debug_assert!( !aliases.contains_key( &property.name ), "Name `{}` is already used for `{}` as alias", property.name, aliases[ &property.name ] ); @@ -225,6 +230,7 @@ pub( crate ) mod private super_former.storage.properties = Some( properties ); super_former.storage.properties_aliases = Some( aliases ); + super_former.storage.properties_order = Some( order ); super_former }; diff --git a/module/move/wca/src/ca/help.rs b/module/move/wca/src/ca/help.rs index 54d1485a12..601b18a0b4 100644 --- a/module/move/wca/src/ca/help.rs +++ b/module/move/wca/src/ca/help.rs @@ -53,6 +53,11 @@ pub( crate ) mod private pub description_detailing : LevelOfDetail, /// If enabled - shows complete description of subjects and properties pub with_footer : bool, + + order : Option< Vec< String > >, + + #[ default( true ) ] + with_nature_order : bool, } // qqq : for Barsik : make possible to change properties order @@ -90,13 +95,24 @@ pub( crate ) mod private LevelOfDetail::None => "".into(), _ if command.subjects.is_empty() => "".into(), LevelOfDetail::Simple => "< properties >".into(), + LevelOfDetail::Detailed if o.with_nature_order => command.properties_order.iter().map( | n | format!( "< {n}:{}{:?} >", if command.properties.get(n).unwrap().optional { "?" } else { "" }, command.properties.get(n).unwrap().kind ) ).collect::< Vec< _ > >().join( " " ), LevelOfDetail::Detailed => command.properties.iter().map( |( n, v )| format!( "< {n}:{}{:?} >", if v.optional { "?" } else { "" }, v.kind ) ).collect::< Vec< _ > >().join( " " ), }; let footer = if o.with_footer { let full_subjects = command.subjects.iter().map( | subj | format!( "- {} [{}{:?}]", subj.hint, if subj.optional { "?" } else { "" }, subj.kind ) ).join( "\n\t" ); - let full_properties = format_table( command.properties.iter().sorted_by_key( |( name, _ )| *name ).map( |( name, value )| [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] ) ).unwrap().replace( '\n', "\n\t" ); + dbg!(o.with_nature_order); + let full_properties = if o.with_nature_order + { + dbg!("with"); + format_table( command.properties_order.iter().map( | name | [ name.clone(), format!( "- {} [{}{:?}]", command.properties.get(name).unwrap().hint, if command.properties.get(name).unwrap().optional { "?" } else { "" }, command.properties.get(name).unwrap().kind ) ] ) ).unwrap().replace( '\n', "\n\t" ) + } + else + { + dbg!("without"); + format_table( command.properties.iter().sorted_by_key( |( name, _ )| *name ).map( |( name, value )| [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] ) ).unwrap().replace( '\n', "\n\t" ) + }; format! ( "{}{}", @@ -130,14 +146,22 @@ pub( crate ) mod private } else { - let rows = dictionary.commands - .iter() - .sorted_by_key( |( name, _ )| *name ) - .map( |( _, cmd )| cmd ) - .map( for_single_command ) - .map( | row | [ row.name, row.args, row.hint ] ); - - format_table( rows ).unwrap() + if let Some(order) = o.order{ + let rows = order + .iter() + .map( | k | dictionary.commands.get( k ).unwrap() ) + .map( for_single_command ) + .map( | row | [ row.name, row.args, row.hint ] ); + format_table( rows ).unwrap() + } else { + let rows = dictionary.commands + .iter() + .sorted_by_key( |( name, _ )| *name ) + .map( |( _, cmd )| cmd ) + .map( for_single_command ) + .map( | row | [ row.name, row.args, row.hint ] ); + format_table( rows ).unwrap() + } } } @@ -158,17 +182,20 @@ pub( crate ) mod private impl HelpVariants { /// Generates help commands - pub fn generate( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary ) + pub fn generate( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) { + dbg!((dictionary.commands.len(), order.as_ref().map(|a|a.len()))); + debug_assert!( dictionary.commands.len() == order.as_ref().map( | o | o.len() ).unwrap_or( dictionary.commands.len() ) ); + dictionary.commands.keys().for_each( | k | assert!( order.as_ref().map( | a | a.contains( &k ) ).unwrap_or( true ) ) ); match self { HelpVariants::All => { - self.general_help( helper, dictionary ); + self.general_help( helper, dictionary, order ); self.subject_command_help( helper, dictionary ); // self.dot_command_help( helper, dictionary ); }, - HelpVariants::General => self.general_help( helper, dictionary ), + HelpVariants::General => self.general_help( helper, dictionary, order ), HelpVariants::SubjectCommand => self.subject_command_help( helper, dictionary ), _ => unimplemented!() // HelpVariants::DotCommand => self.dot_command_help( helper, dictionary ), @@ -176,7 +203,7 @@ pub( crate ) mod private } // .help - fn general_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary ) + fn general_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) { let phrase = "help".to_string(); @@ -205,17 +232,23 @@ pub( crate ) mod private } else { + let mut options = HelpGeneratorOptions::former() + .command_prefix( "." ) + .description_detailing( LevelOfDetail::Simple ) + .subject_detailing( LevelOfDetail::Simple ) + .property_detailing( LevelOfDetail::Simple ) + .with_nature_order( order.is_some() ); + if let Some(order) = order.as_ref() + { + options = options.order( order.clone() ); + } println! ( "Help command\n\n{text}", text = generator.exec ( &grammar, - HelpGeneratorOptions::former() - .command_prefix( "." ) - .description_detailing( LevelOfDetail::Simple ) - .subject_detailing( LevelOfDetail::Simple ) - .property_detailing( LevelOfDetail::Simple ) + options .form() ) ); diff --git a/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs b/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs new file mode 100644 index 0000000000..7c87449bcf --- /dev/null +++ b/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs @@ -0,0 +1,28 @@ +fn main() +{ + use wca::{ Type, VerifiedCommand }; + + let ca = wca::CommandsAggregator::former() + .command( "c" ) + .hint( "c" ) + .property( "c-property" ).kind( Type::String ).optional( true ).end() + .property( "b-property" ).kind( Type::String ).optional( true ).end() + .property( "a-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("c") } ) + .end() + .command( "b" ) + .hint( "b" ) + .property( "b-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("b") } ) + .end() + .command( "a" ) + .hint( "a" ) + .property( "a-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("a") } ) + .end() + .with_nature_sort( false ) + .perform(); + + let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); + ca.perform( args ).unwrap(); +} \ No newline at end of file diff --git a/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs b/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs new file mode 100644 index 0000000000..0eee28b2c1 --- /dev/null +++ b/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs @@ -0,0 +1,28 @@ +fn main() +{ + use wca::{ Type, VerifiedCommand }; + + let ca = wca::CommandsAggregator::former() + .command( "c" ) + .hint( "c" ) + .property( "c-property" ).kind( Type::String ).optional( true ).end() + .property( "b-property" ).kind( Type::String ).optional( true ).end() + .property( "a-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("c") } ) + .end() + .command( "b" ) + .hint( "b" ) + .property( "b-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("b") } ) + .end() + .command( "a" ) + .hint( "a" ) + .property( "a-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("a") } ) + .end() + .with_nature_sort( true ) + .perform(); + + let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); + ca.perform( args ).unwrap(); +} \ No newline at end of file diff --git a/module/move/wca/tests/inc/commands_aggregator/help.rs b/module/move/wca/tests/inc/commands_aggregator/help.rs index 3c4f01f6a6..2cc5153733 100644 --- a/module/move/wca/tests/inc/commands_aggregator/help.rs +++ b/module/move/wca/tests/inc/commands_aggregator/help.rs @@ -59,3 +59,75 @@ wca = {{path = "{}"}}"#, result ); } + +#[ test ] +fn help_command_with_nature_order() +{ + let toml = format! + ( + r#"[package] +name = "wca_hello_test" +version = "0.1.0" +edition = "2021" +[dependencies] +wca = {{path = "{}"}}"#, + env!( "CARGO_MANIFEST_DIR" ).replace( "\\", "/" ) + ) ; + + let temp = arrange( "wca_help_test_nature_order" ); + let mut file = File::create( temp.path().join( "Cargo.toml" ) ).unwrap(); + file.write_all( toml.as_bytes() ).unwrap(); + let result = start_sync( "cargo", [ "r", ".help" ], temp.path() ); + + // dbg!(&result); + assert_eq! + ( + "Help command\n\n.c - c\n.b - b\n.a - a\n", + result + ); + + let result = start_sync( "cargo", [ "r", ".help", "c" ], temp.path() ); + + dbg!(&result); + assert_eq! + ( + "Help command\n\n.c - c\n\nProperties:\n\tc-property - [?String]\n\tb-property - [?String]\n\ta-property - [?String]\n", + result + ); +} + +#[ test ] +fn help_command_with_lexicography_order() +{ + let toml = format! + ( + r#"[package] +name = "wca_hello_test" +version = "0.1.0" +edition = "2021" +[dependencies] +wca = {{path = "{}"}}"#, + env!( "CARGO_MANIFEST_DIR" ).replace( "\\", "/" ) + ) ; + + let temp = arrange( "wca_help_test_lexicography_order" ); + let mut file = File::create( temp.path().join( "Cargo.toml" ) ).unwrap(); + file.write_all( toml.as_bytes() ).unwrap(); + let result = start_sync( "cargo", [ "r", ".help" ], temp.path() ); + + // dbg!(&result); + assert_eq! + ( + "Help command\n\n.a - a\n.b - b\n.c - c\n", + result + ); + + let result = start_sync( "cargo", [ "r", ".help", "c" ], temp.path() ); + + dbg!(&result); + assert_eq! + ( + "Help command\n\n.c - c\n.b - b\n.a - a\n", + result + ); +} From e59ee4c66aa85829de74fe31d9b188c6e772c418 Mon Sep 17 00:00:00 2001 From: SRetip Date: Mon, 13 May 2024 13:49:44 +0300 Subject: [PATCH 2/8] ready --- module/move/wca/src/ca/aggregator.rs | 24 ++++++++++---- module/move/wca/src/ca/help.rs | 33 +++++++++++-------- .../wca_help_test_nature_order/src/main.rs | 2 +- .../wca/tests/inc/commands_aggregator/help.rs | 5 +-- module/move/willbe/src/command/mod.rs | 2 +- 5 files changed, 42 insertions(+), 24 deletions(-) diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index e5814fa657..792f726c56 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -100,7 +100,7 @@ pub( crate ) mod private /// ``` #[ derive( Debug ) ] #[ derive( former::Former ) ] - #[ storage_fields( help_generator : HelpGeneratorFn, help_variants : HashSet< HelpVariants > ) ] + #[ storage_fields( help_generator : HelpGeneratorFn, help_variants : HashSet< HelpVariants >, with_nature_sort : bool, order : Option< Vec< String > > ) ] #[ mutator( custom = true ) ] // #[ debug ] pub struct CommandsAggregator @@ -118,8 +118,10 @@ pub( crate ) mod private #[ former( default = Verifier ) ] verifier : Verifier, - #[ former( default = true ) ] - with_nature_sort : bool, + // #[ former( default = true ) ] + + // + callback_fn : Option< CommandsAggregatorCallback >, } @@ -133,16 +135,24 @@ pub( crate ) mod private let help_generator = std::mem::take( &mut ca.help_generator ).unwrap_or_default(); let help_variants = std::mem::take( &mut ca.help_variants ).unwrap_or_else( || HashSet::from([ HelpVariants::All ]) ); + dbg!(&ca.with_nature_sort); + dbg!(&ca.order); + let order = if ca.with_nature_sort.unwrap_or_default() { + std::mem::take(&mut ca.order) + } else { + None + }; + dbg!(&order); if help_variants.contains( &HelpVariants::All ) { - HelpVariants::All.generate( &help_generator, dictionary ); + HelpVariants::All.generate( &help_generator, dictionary, order.clone() ); } else { for help in help_variants.iter().sorted() { - help.generate( &help_generator, dictionary ); + help.generate( &help_generator, dictionary, order.clone() ); } } } @@ -162,9 +172,9 @@ pub( crate ) mod private IntoName : Into< String >, { let name = name.into(); - let mut order = self.storage.command_order.unwrap_or_default(); + let mut order = self.storage.order.unwrap_or_default(); order.push(name.clone()); - self.storage.command_order = Some(order); + self.storage.order = Some(order); let on_end = | command : CommandFormerStorage, super_former : Option< Self > | -> Self { let mut super_former = super_former.unwrap(); diff --git a/module/move/wca/src/ca/help.rs b/module/move/wca/src/ca/help.rs index 660c3a290d..b2744a27db 100644 --- a/module/move/wca/src/ca/help.rs +++ b/module/move/wca/src/ca/help.rs @@ -56,13 +56,14 @@ pub( crate ) mod private order : Option< Vec< String > >, - #[ former( default = true ) ] + // #[ former( default = true ) ] with_nature_order : bool, } // qqq : for Barsik : make possible to change properties order pub( crate ) fn generate_help_content( dictionary : &Dictionary, o : HelpGeneratorOptions< '_ > ) -> String { + dbg!(&o); struct Row { name : String, @@ -184,19 +185,18 @@ pub( crate ) mod private /// Generates help commands pub fn generate( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) { - dbg!((dictionary.commands.len(), order.as_ref().map(|a|a.len()))); - debug_assert!( dictionary.commands.len() == order.as_ref().map( | o | o.len() ).unwrap_or( dictionary.commands.len() ) ); - dictionary.commands.keys().for_each( | k | assert!( order.as_ref().map( | a | a.contains( &k ) ).unwrap_or( true ) ) ); + // debug_assert!( dictionary.commands.len() == order.as_ref().map( | o | o.len() ).unwrap_or( dictionary.commands.len() ) ); + // dictionary.commands.keys().for_each( | k | assert!( order.as_ref().map( | a | a.contains( &k ) ).unwrap_or( true ) ) ); match self { HelpVariants::All => { - self.general_help( helper, dictionary, order ); - self.subject_command_help( helper, dictionary ); + self.general_help( helper, dictionary, order.clone() ); + self.subject_command_help( helper, dictionary, order ); // self.dot_command_help( helper, dictionary ); }, HelpVariants::General => self.general_help( helper, dictionary, order ), - HelpVariants::SubjectCommand => self.subject_command_help( helper, dictionary ), + HelpVariants::SubjectCommand => self.subject_command_help( helper, dictionary, order ), _ => unimplemented!() // HelpVariants::DotCommand => self.dot_command_help( helper, dictionary ), } @@ -205,6 +205,7 @@ pub( crate ) mod private // .help fn general_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) { + dbg!(&order); let phrase = "help".to_string(); let grammar = dictionary.clone(); @@ -242,14 +243,15 @@ pub( crate ) mod private { options = options.order( order.clone() ); } + dbg!(&options.storage.with_nature_order); println! ( "Help command\n\n{text}", text = generator.exec ( &grammar, - options - .form() + dbg!(options + .form()) ) ); } @@ -273,7 +275,7 @@ pub( crate ) mod private } // .help command_name - fn subject_command_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary ) + fn subject_command_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) { let phrase = "help".to_string(); @@ -293,15 +295,19 @@ pub( crate ) mod private let command = o.args.get_owned::< String >( 0 ).unwrap(); let cmd = grammar.commands.get( &command ).ok_or_else( || anyhow!( "Can not found help for command `{command}`" ) )?; - let args = HelpGeneratorOptions::former() + let mut args = HelpGeneratorOptions::former() .command_prefix( "." ) .for_commands([ cmd ]) .description_detailing( LevelOfDetail::Detailed ) .subject_detailing( LevelOfDetail::Simple ) .property_detailing( LevelOfDetail::Simple ) .with_footer( true ) - .form(); - let text = generator.exec( &grammar, args ); + .with_nature_order( order.is_some() ); + if let Some(order) = order.as_ref() + { + args = args.order( order.clone() ); + } + let text = generator.exec( &grammar, args.form() ); println!( "Help command\n\n{text}" ); } @@ -423,6 +429,7 @@ pub( crate ) mod private /// Executes the function to generate help content pub fn exec( &self, dictionary : &Dictionary, args : HelpGeneratorOptions< '_ > ) -> String { + dbg!(&args.with_nature_order); self.0( dictionary, args ) } } diff --git a/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs b/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs index 0eee28b2c1..1c9815a364 100644 --- a/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs +++ b/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs @@ -20,7 +20,7 @@ fn main() .property( "a-property" ).kind( Type::String ).optional( true ).end() .routine( | o : VerifiedCommand | { println!("a") } ) .end() - .with_nature_sort( true ) + .with_nature_sort( true ) .perform(); let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); diff --git a/module/move/wca/tests/inc/commands_aggregator/help.rs b/module/move/wca/tests/inc/commands_aggregator/help.rs index 2cc5153733..2fcd38f8e2 100644 --- a/module/move/wca/tests/inc/commands_aggregator/help.rs +++ b/module/move/wca/tests/inc/commands_aggregator/help.rs @@ -88,7 +88,8 @@ wca = {{path = "{}"}}"#, let result = start_sync( "cargo", [ "r", ".help", "c" ], temp.path() ); - dbg!(&result); + println!("{result}"); + assert_eq! ( "Help command\n\n.c - c\n\nProperties:\n\tc-property - [?String]\n\tb-property - [?String]\n\ta-property - [?String]\n", @@ -127,7 +128,7 @@ wca = {{path = "{}"}}"#, dbg!(&result); assert_eq! ( - "Help command\n\n.c - c\n.b - b\n.a - a\n", + "Help command\n\n.c - c\n\nProperties:\n\ta-property - [?String]\n\tb-property - [?String]\n\tc-property - [?String]\n", result ); } diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index d3d5e5950b..6c0a258926 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -11,7 +11,7 @@ pub( crate ) mod private pub fn ca() -> CommandsAggregatorFormer { CommandsAggregator::former() - + .with_nature_sort(true) .command( "publish" ) .hint( "publish the specified package to `crates.io`" ) .long_hint( "used to publish the specified local package, which is located in the provided directory path, to the `crates.io` crate registry." ) From c1b3a6e0a4c6165056b76c508c4ccc6bee9ce872 Mon Sep 17 00:00:00 2001 From: SRetip Date: Mon, 13 May 2024 13:54:05 +0300 Subject: [PATCH 3/8] remove dbg --- module/move/wca/src/ca/aggregator.rs | 24 ++++++++++-------------- module/move/wca/src/ca/help.rs | 10 +--------- module/move/willbe/src/command/mod.rs | 2 +- 3 files changed, 12 insertions(+), 24 deletions(-) diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index 792f726c56..55c84bf7d4 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -117,12 +117,7 @@ pub( crate ) mod private #[ former( default = Verifier ) ] verifier : Verifier, - - // #[ former( default = true ) ] - - // - callback_fn : Option< CommandsAggregatorCallback >, } @@ -135,15 +130,16 @@ pub( crate ) mod private let help_generator = std::mem::take( &mut ca.help_generator ).unwrap_or_default(); let help_variants = std::mem::take( &mut ca.help_variants ).unwrap_or_else( || HashSet::from([ HelpVariants::All ]) ); - dbg!(&ca.with_nature_sort); - dbg!(&ca.order); - let order = if ca.with_nature_sort.unwrap_or_default() { - std::mem::take(&mut ca.order) - } else { + + let order = if ca.with_nature_sort.unwrap_or_default() + { + std::mem::take( &mut ca.order ) + } + else + { None }; - dbg!(&order); - + if help_variants.contains( &HelpVariants::All ) { HelpVariants::All.generate( &help_generator, dictionary, order.clone() ); @@ -173,8 +169,8 @@ pub( crate ) mod private { let name = name.into(); let mut order = self.storage.order.unwrap_or_default(); - order.push(name.clone()); - self.storage.order = Some(order); + order.push( name.clone() ); + self.storage.order = Some( order ); let on_end = | command : CommandFormerStorage, super_former : Option< Self > | -> Self { let mut super_former = super_former.unwrap(); diff --git a/module/move/wca/src/ca/help.rs b/module/move/wca/src/ca/help.rs index b2744a27db..57099dc8ab 100644 --- a/module/move/wca/src/ca/help.rs +++ b/module/move/wca/src/ca/help.rs @@ -63,7 +63,6 @@ pub( crate ) mod private // qqq : for Barsik : make possible to change properties order pub( crate ) fn generate_help_content( dictionary : &Dictionary, o : HelpGeneratorOptions< '_ > ) -> String { - dbg!(&o); struct Row { name : String, @@ -103,15 +102,12 @@ pub( crate ) mod private let footer = if o.with_footer { let full_subjects = command.subjects.iter().map( | subj | format!( "- {} [{}{:?}]", subj.hint, if subj.optional { "?" } else { "" }, subj.kind ) ).join( "\n\t" ); - dbg!(o.with_nature_order); let full_properties = if o.with_nature_order { - dbg!("with"); format_table( command.properties_order.iter().map( | name | [ name.clone(), format!( "- {} [{}{:?}]", command.properties.get(name).unwrap().hint, if command.properties.get(name).unwrap().optional { "?" } else { "" }, command.properties.get(name).unwrap().kind ) ] ) ).unwrap().replace( '\n', "\n\t" ) } else { - dbg!("without"); format_table( command.properties.iter().sorted_by_key( |( name, _ )| *name ).map( |( name, value )| [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] ) ).unwrap().replace( '\n', "\n\t" ) }; format! @@ -205,7 +201,6 @@ pub( crate ) mod private // .help fn general_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) { - dbg!(&order); let phrase = "help".to_string(); let grammar = dictionary.clone(); @@ -243,15 +238,13 @@ pub( crate ) mod private { options = options.order( order.clone() ); } - dbg!(&options.storage.with_nature_order); println! ( "Help command\n\n{text}", text = generator.exec ( &grammar, - dbg!(options - .form()) + options.form() ) ); } @@ -429,7 +422,6 @@ pub( crate ) mod private /// Executes the function to generate help content pub fn exec( &self, dictionary : &Dictionary, args : HelpGeneratorOptions< '_ > ) -> String { - dbg!(&args.with_nature_order); self.0( dictionary, args ) } } diff --git a/module/move/willbe/src/command/mod.rs b/module/move/willbe/src/command/mod.rs index 6c0a258926..d3d5e5950b 100644 --- a/module/move/willbe/src/command/mod.rs +++ b/module/move/willbe/src/command/mod.rs @@ -11,7 +11,7 @@ pub( crate ) mod private pub fn ca() -> CommandsAggregatorFormer { CommandsAggregator::former() - .with_nature_sort(true) + .command( "publish" ) .hint( "publish the specified package to `crates.io`" ) .long_hint( "used to publish the specified local package, which is located in the provided directory path, to the `crates.io` crate registry." ) From 039d5ab46454d116e0abf53812f7848afea1dd5b Mon Sep 17 00:00:00 2001 From: SRetip Date: Mon, 13 May 2024 13:56:31 +0300 Subject: [PATCH 4/8] fmt --- module/move/wca/src/ca/help.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/module/move/wca/src/ca/help.rs b/module/move/wca/src/ca/help.rs index 57099dc8ab..b85b063cbf 100644 --- a/module/move/wca/src/ca/help.rs +++ b/module/move/wca/src/ca/help.rs @@ -104,7 +104,7 @@ pub( crate ) mod private let full_subjects = command.subjects.iter().map( | subj | format!( "- {} [{}{:?}]", subj.hint, if subj.optional { "?" } else { "" }, subj.kind ) ).join( "\n\t" ); let full_properties = if o.with_nature_order { - format_table( command.properties_order.iter().map( | name | [ name.clone(), format!( "- {} [{}{:?}]", command.properties.get(name).unwrap().hint, if command.properties.get(name).unwrap().optional { "?" } else { "" }, command.properties.get(name).unwrap().kind ) ] ) ).unwrap().replace( '\n', "\n\t" ) + format_table( command.properties_order.iter().map( | name | [ name.clone(), format!( "- {} [{}{:?}]", command.properties.get( name ).unwrap().hint, if command.properties.get( name ).unwrap().optional { "?" } else { "" }, command.properties.get( name ).unwrap().kind ) ] ) ).unwrap().replace( '\n', "\n\t" ) } else { @@ -143,14 +143,17 @@ pub( crate ) mod private } else { - if let Some(order) = o.order{ + if let Some(order) = o.order + { let rows = order .iter() .map( | k | dictionary.commands.get( k ).unwrap() ) .map( for_single_command ) .map( | row | [ row.name, row.args, row.hint ] ); format_table( rows ).unwrap() - } else { + } + else + { let rows = dictionary.commands .iter() .sorted_by_key( |( name, _ )| *name ) From d551a3c4707e5e0cbcd7469cb2a870a68c3b7907 Mon Sep 17 00:00:00 2001 From: SRetip Date: Mon, 27 May 2024 11:24:01 +0300 Subject: [PATCH 5/8] after review fix --- module/move/wca/src/ca/aggregator.rs | 2 +- module/move/wca/src/ca/grammar/command.rs | 2 +- module/move/wca/src/ca/help.rs | 28 +++++---- .../wca/tests/inc/commands_aggregator/help.rs | 62 +++++++++++++++++++ 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index 55c84bf7d4..df4b45311a 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -117,7 +117,7 @@ pub( crate ) mod private #[ former( default = Verifier ) ] verifier : Verifier, - + callback_fn : Option< CommandsAggregatorCallback >, } diff --git a/module/move/wca/src/ca/grammar/command.rs b/module/move/wca/src/ca/grammar/command.rs index fac21672d6..d0123a6ea0 100644 --- a/module/move/wca/src/ca/grammar/command.rs +++ b/module/move/wca/src/ca/grammar/command.rs @@ -99,7 +99,7 @@ pub( crate ) mod private pub subjects : Vec< ValueDescription >, /// Hints and types for command options. pub properties : HashMap< String, ValueDescription >, - /// + /// Stores the order in which the properties were described. pub properties_order : Vec< String >, /// Map of aliases. // Aliased key -> Original key diff --git a/module/move/wca/src/ca/help.rs b/module/move/wca/src/ca/help.rs index b85b063cbf..b931f26cb4 100644 --- a/module/move/wca/src/ca/help.rs +++ b/module/move/wca/src/ca/help.rs @@ -53,10 +53,9 @@ pub( crate ) mod private pub description_detailing : LevelOfDetail, /// If enabled - shows complete description of subjects and properties pub with_footer : bool, - + /// Stores the order in which the properties were described. order : Option< Vec< String > >, - - // #[ former( default = true ) ] + /// Flag which means in what order the commands and properties to them will be displayed. with_nature_order : bool, } @@ -102,14 +101,19 @@ pub( crate ) mod private let footer = if o.with_footer { let full_subjects = command.subjects.iter().map( | subj | format!( "- {} [{}{:?}]", subj.hint, if subj.optional { "?" } else { "" }, subj.kind ) ).join( "\n\t" ); - let full_properties = if o.with_nature_order - { - format_table( command.properties_order.iter().map( | name | [ name.clone(), format!( "- {} [{}{:?}]", command.properties.get( name ).unwrap().hint, if command.properties.get( name ).unwrap().optional { "?" } else { "" }, command.properties.get( name ).unwrap().kind ) ] ) ).unwrap().replace( '\n', "\n\t" ) - } - else - { - format_table( command.properties.iter().sorted_by_key( |( name, _ )| *name ).map( |( name, value )| [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] ) ).unwrap().replace( '\n', "\n\t" ) - }; + let full_properties = format_table + ( + if o.with_nature_order + { + command.properties_order.iter().map( | name | ( name, command.properties.get( name ).unwrap() ) ).collect::< Vec< _ > >() + } + else + { + command.properties.iter().sorted_by_key( | ( name, _ ) | *name ).collect::< Vec< _ > >() + } + .into_iter().map( | ( name, value ) | [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] ) + ).unwrap().replace( '\n', "\n\t" ); + format! ( "{}{}", @@ -184,8 +188,6 @@ pub( crate ) mod private /// Generates help commands pub fn generate( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) { - // debug_assert!( dictionary.commands.len() == order.as_ref().map( | o | o.len() ).unwrap_or( dictionary.commands.len() ) ); - // dictionary.commands.keys().for_each( | k | assert!( order.as_ref().map( | a | a.contains( &k ) ).unwrap_or( true ) ) ); match self { HelpVariants::All => diff --git a/module/move/wca/tests/inc/commands_aggregator/help.rs b/module/move/wca/tests/inc/commands_aggregator/help.rs index 2fcd38f8e2..9dcfa92649 100644 --- a/module/move/wca/tests/inc/commands_aggregator/help.rs +++ b/module/move/wca/tests/inc/commands_aggregator/help.rs @@ -60,6 +60,37 @@ wca = {{path = "{}"}}"#, ); } +/// `wca_help_test_nature_order/src/main.rs` : +/// ```rust +/// fn main() +/// { +/// use wca::{ Type, VerifiedCommand }; +/// +/// let ca = wca::CommandsAggregator::former() +/// .command( "c" ) +/// .hint( "c" ) +/// .property( "c-property" ).kind( Type::String ).optional( true ).end() +/// .property( "b-property" ).kind( Type::String ).optional( true ).end() +/// .property( "a-property" ).kind( Type::String ).optional( true ).end() +/// .routine( | o : VerifiedCommand | { println!("c") } ) +/// .end() +/// .command( "b" ) +/// .hint( "b" ) +/// .property( "b-property" ).kind( Type::String ).optional( true ).end() +/// .routine( | o : VerifiedCommand | { println!("b") } ) +/// .end() +/// .command( "a" ) +/// .hint( "a" ) +/// .property( "a-property" ).kind( Type::String ).optional( true ).end() +/// .routine( | o : VerifiedCommand | { println!("a") } ) +/// .end() +/// .with_nature_sort( true ) +/// .perform(); +/// +/// let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); +/// ca.perform( args ).unwrap(); +/// } +/// ``` #[ test ] fn help_command_with_nature_order() { @@ -97,6 +128,37 @@ wca = {{path = "{}"}}"#, ); } +/// `wca_help_test_lexicography_order/src/main.rs` : +/// ```rust +/// fn main() +/// { +/// use wca::{ Type, VerifiedCommand }; +/// +/// let ca = wca::CommandsAggregator::former() +/// .command( "c" ) +/// .hint( "c" ) +/// .property( "c-property" ).kind( Type::String ).optional( true ).end() +/// .property( "b-property" ).kind( Type::String ).optional( true ).end() +/// .property( "a-property" ).kind( Type::String ).optional( true ).end() +/// .routine( | o : VerifiedCommand | { println!("c") } ) +/// .end() +/// .command( "b" ) +/// .hint( "b" ) +/// .property( "b-property" ).kind( Type::String ).optional( true ).end() +/// .routine( | o : VerifiedCommand | { println!("b") } ) +/// .end() +/// .command( "a" ) +/// .hint( "a" ) +/// .property( "a-property" ).kind( Type::String ).optional( true ).end() +/// .routine( | o : VerifiedCommand | { println!("a") } ) +/// .end() +/// .with_nature_sort( false ) +/// .perform(); +/// +/// let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); +/// ca.perform( args ).unwrap(); +/// } +/// ``` #[ test ] fn help_command_with_lexicography_order() { From 7279338476f3fecba1123d70693bb29691a373a4 Mon Sep 17 00:00:00 2001 From: SRetip Date: Mon, 27 May 2024 20:16:45 +0300 Subject: [PATCH 6/8] refactor --- module/move/wca/examples/wca_trivial.rs | 11 +-- module/move/wca/src/ca/aggregator.rs | 33 +++---- module/move/wca/src/ca/formatter.rs | 25 +++--- module/move/wca/src/ca/grammar/command.rs | 37 ++++++-- module/move/wca/src/ca/grammar/dictionary.rs | 89 +++++++++++++++++-- module/move/wca/src/ca/help.rs | 81 +++++------------ module/move/wca/src/ca/verifier/verifier.rs | 7 +- .../src/main.rs | 4 +- .../wca_help_test_nature_order/src/main.rs | 5 +- .../wca/tests/inc/commands_aggregator/help.rs | 4 - 10 files changed, 177 insertions(+), 119 deletions(-) diff --git a/module/move/wca/examples/wca_trivial.rs b/module/move/wca/examples/wca_trivial.rs index 272923ecf5..c228e6e20a 100644 --- a/module/move/wca/examples/wca_trivial.rs +++ b/module/move/wca/examples/wca_trivial.rs @@ -2,7 +2,7 @@ //! A trivial example. //! -use wca::{ CommandsAggregator, Type, VerifiedCommand }; +use wca::{ CommandsAggregator, Order, Type, VerifiedCommand }; fn f1( o : VerifiedCommand ) { @@ -19,16 +19,17 @@ fn exit() fn main() { let ca = CommandsAggregator::former() + .command( "exit" ) + .hint( "just exit" ) + .routine( || exit() ) + .end() .command( "echo" ) .hint( "prints all subjects and properties" ) .subject().hint( "Subject" ).kind( Type::String ).optional( true ).end() .property( "property" ).hint( "simple property" ).kind( Type::String ).optional( true ).end() .routine( f1 ) .end() - .command( "exit" ) - .hint( "just exit" ) - .routine( || exit() ) - .end() + .order( Order::Lexicography ) .perform() ; diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index df4b45311a..abf9a3a1ce 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -26,6 +26,17 @@ pub( crate ) mod private for_lib::*, }; use wtools::Itertools; + + /// Order of commands and properties. + #[ derive( Debug, Default, Clone, Copy, Eq, PartialOrd, PartialEq ) ] + pub enum Order + { + /// Natures order. + #[ default ] + Nature, + /// Lexicography order. + Lexicography, + } /// Validation errors that can occur in application. #[ derive( Error, Debug ) ] @@ -100,7 +111,7 @@ pub( crate ) mod private /// ``` #[ derive( Debug ) ] #[ derive( former::Former ) ] - #[ storage_fields( help_generator : HelpGeneratorFn, help_variants : HashSet< HelpVariants >, with_nature_sort : bool, order : Option< Vec< String > > ) ] + #[ storage_fields( help_generator : HelpGeneratorFn, help_variants : HashSet< HelpVariants >, order : Order ) ] #[ mutator( custom = true ) ] // #[ debug ] pub struct CommandsAggregator @@ -127,28 +138,20 @@ pub( crate ) mod private { let ca = storage; let dictionary = ca.dictionary.get_or_insert_with( Dictionary::default ); + dictionary.order = ca.order.unwrap_or_default(); let help_generator = std::mem::take( &mut ca.help_generator ).unwrap_or_default(); let help_variants = std::mem::take( &mut ca.help_variants ).unwrap_or_else( || HashSet::from([ HelpVariants::All ]) ); - let order = if ca.with_nature_sort.unwrap_or_default() - { - std::mem::take( &mut ca.order ) - } - else - { - None - }; - if help_variants.contains( &HelpVariants::All ) { - HelpVariants::All.generate( &help_generator, dictionary, order.clone() ); + HelpVariants::All.generate( &help_generator, dictionary, ca.order.unwrap_or_default() ); } else { for help in help_variants.iter().sorted() { - help.generate( &help_generator, dictionary, order.clone() ); + help.generate( &help_generator, dictionary, ca.order.unwrap_or_default() ); } } } @@ -163,14 +166,11 @@ pub( crate ) mod private /// # Arguments /// /// * `name` - The name of the command. - pub fn command< IntoName >( mut self, name : IntoName ) -> CommandAsSubformer< Self, impl CommandAsSubformerEnd< Self > > + pub fn command< IntoName >( self, name : IntoName ) -> CommandAsSubformer< Self, impl CommandAsSubformerEnd< Self > > where IntoName : Into< String >, { let name = name.into(); - let mut order = self.storage.order.unwrap_or_default(); - order.push( name.clone() ); - self.storage.order = Some( order ); let on_end = | command : CommandFormerStorage, super_former : Option< Self > | -> Self { let mut super_former = super_former.unwrap(); @@ -292,4 +292,5 @@ crate::mod_interface! exposed use CommandsAggregatorFormer; exposed use Error; exposed use ValidationError; + exposed use Order; } diff --git a/module/move/wca/src/ca/formatter.rs b/module/move/wca/src/ca/formatter.rs index d21979acdf..3b4f989f1d 100644 --- a/module/move/wca/src/ca/formatter.rs +++ b/module/move/wca/src/ca/formatter.rs @@ -3,6 +3,7 @@ pub( crate ) mod private use crate::*; use wtools::Itertools; + use crate::ca::aggregator::private::Order; /// - #[ derive( Debug, Clone, PartialEq ) ] @@ -12,18 +13,18 @@ pub( crate ) mod private Another, } - pub fn md_generator( grammar : &Dictionary ) -> String + pub fn md_generator( grammar : &Dictionary, order: Order ) -> String { - let text = grammar.commands - .iter() - .sorted_by_key( |( name, _ )| *name ) + let text = grammar.commands() + .into_iter() .map( |( name, cmd )| { let subjects = cmd.subjects.iter().fold( String::new(), | _, _ | format!( " `[argument]`" ) ); let properties = if cmd.properties.is_empty() { " " } else { " `[properties]` " }; format! ( - "[.{name}{subjects}{properties}](#{}{}{})", + "[.{}{subjects}{properties}](#{}{}{})", + name, name.replace( '.', "" ), if cmd.subjects.is_empty() { "" } else { "-argument" }, if cmd.properties.is_empty() { "" } else { "-properties" }, @@ -36,16 +37,15 @@ pub( crate ) mod private let list_of_commands = format!( "## Commands\n\n{}", text ); - let about_each_command = grammar.commands - .iter() - .sorted_by_key( |( name, _ )| *name ) + let about_each_command = grammar.commands() + .into_iter() .map( |( name, cmd )| { let subjects = cmd.subjects.iter().fold( String::new(), | _, _ | format!( " `[Subject]`" ) ); let properties = if cmd.properties.is_empty() { " " } else { " `[properties]` " }; let hint = if cmd.hint.is_empty() { &cmd.long_hint } else { &cmd.hint }; - let heading = format!( "## .{name}{subjects}{properties}\n__{}__\n", hint ); + let heading = format!( "## .{}{subjects}{properties}\n__{}__\n", name, hint ); let hint = if cmd.long_hint.is_empty() { &cmd.hint } else { &cmd.long_hint }; let full_subjects = cmd @@ -59,13 +59,12 @@ pub( crate ) mod private ) .join( "\n" ); let full_properties = cmd - .properties - .iter() - .sorted_by_key( |( name, _ )| *name ) + .properties( order ) + .into_iter() .map ( |( name, value )| - format!( "\n- {}{name} - {} `[{:?}]`", if value.optional { "`< optional >` " } else { "" }, value.hint, value.kind ) + format!( "\n- {}{} - {} `[{:?}]`", if value.optional { "`< optional >` " } else { "" }, value.hint, name, value.kind ) ) .join( "\n" ); // aaa : for Bohdan : toooooo log lines. 130 is max diff --git a/module/move/wca/src/ca/grammar/command.rs b/module/move/wca/src/ca/grammar/command.rs index d0123a6ea0..ed1d4e8eee 100644 --- a/module/move/wca/src/ca/grammar/command.rs +++ b/module/move/wca/src/ca/grammar/command.rs @@ -4,8 +4,11 @@ pub( crate ) mod private use { Handler, Routine, Type }; - use std::collections::HashMap; + use std::collections::{ BTreeMap, HashMap }; use former::{ Former, StoragePreform }; + use crate::ca::aggregator::private::Order; + use crate::ca::grammar::dictionary::private::CommandName; + use crate::wtools::Itertools; /// A description of a Value in a command. Used to specify the expected type and provide a hint for the Value. /// @@ -98,9 +101,10 @@ pub( crate ) mod private #[ subform_entry( setter = true ) ] pub subjects : Vec< ValueDescription >, /// Hints and types for command options. - pub properties : HashMap< String, ValueDescription >, - /// Stores the order in which the properties were described. - pub properties_order : Vec< String >, + pub properties : BTreeMap< CommandName, ValueDescription >, + /// Last inserted command id. + #[ scalar( setter = false ) ] + last_id : usize, /// Map of aliases. // Aliased key -> Original key pub properties_aliases : HashMap< String, String >, @@ -112,6 +116,24 @@ pub( crate ) mod private #[ former( default = Routine::from( Handler::from( || { panic!( "No routine available: A handler function for the command is missing" ) } ) ) ) ] pub routine : Routine, } + + impl Command + { + pub( crate ) fn properties( &self, order : Order ) -> Vec< ( &String, &ValueDescription ) > + { + match order + { + Order::Nature => + { + self.properties.iter().map( | ( key, value ) | ( &key.name, value ) ).collect() + } + Order::Lexicography => + { + self.properties.iter().map( | ( key, value ) | ( &key.name, value ) ).sorted_by_key( | ( k, _ ) | *k ).collect() + } + } + } + } impl< Definition > CommandFormer< Definition > where @@ -201,7 +223,6 @@ pub( crate ) mod private let mut super_former = super_former.unwrap(); let mut properties = super_former.storage.properties.unwrap_or_default(); let property = property.preform(); - let mut order = super_former.storage.properties_order.unwrap_or_default(); let value = ValueDescription { @@ -210,8 +231,9 @@ pub( crate ) mod private optional : property.optional, }; debug_assert!( !properties.contains_key( &property.name ), "Property name `{}` is already used for `{:?}`", property.name, properties[ &property.name ] ); - properties.insert( property.name.clone(), value ); - order.push( property.name.clone() ); + super_former.storage.last_id = Some( super_former.storage.last_id.unwrap_or_default() + 1 ); + let name = CommandName{ id : super_former.storage.last_id.unwrap(), name : property.name.clone() }; + properties.insert( name, value ); let mut aliases = super_former.storage.properties_aliases.unwrap_or_default(); debug_assert!( !aliases.contains_key( &property.name ), "Name `{}` is already used for `{}` as alias", property.name, aliases[ &property.name ] ); @@ -220,7 +242,6 @@ pub( crate ) mod private super_former.storage.properties = Some( properties ); super_former.storage.properties_aliases = Some( aliases ); - super_former.storage.properties_order = Some( order ); super_former }; diff --git a/module/move/wca/src/ca/grammar/dictionary.rs b/module/move/wca/src/ca/grammar/dictionary.rs index a9a79d198a..86c4f5b6db 100644 --- a/module/move/wca/src/ca/grammar/dictionary.rs +++ b/module/move/wca/src/ca/grammar/dictionary.rs @@ -1,10 +1,14 @@ pub( crate ) mod private { + use std::cmp::Ordering; use crate::*; use { Command }; - use std::collections::HashMap; + use std::collections::BTreeMap; + use std::fmt::Display; use former::Former; + use crate::ca::aggregator::private::Order; + use crate::wtools::Itertools; // qqq : `Former` does not handle this situation well @@ -14,14 +18,64 @@ pub( crate ) mod private // #[ derive( Debug, Former ) ] // pub struct Dictionary( HashMap< String, Command > ); + /// Command name with id. + #[ derive( Debug, Default, Clone, Eq ) ] + pub struct CommandName + { + pub( crate ) id : usize, + pub name : String, + } + + impl std::borrow::Borrow< String > for CommandName + { + fn borrow( &self ) -> &String + { + &self.name + } + } + + impl Ord for CommandName + { + fn cmp( &self, other : &Self ) -> Ordering + { + if self.name == other.name + { + Ordering::Equal + } + else + { + self.id.cmp( &other.id ) + } + } + } + + impl PartialEq< Self > for CommandName + { + fn eq( &self, other : &Self ) -> bool + { + self.name.eq( &other.name ) + } + } + + impl PartialOrd for CommandName + { + fn partial_cmp( &self, other : &Self ) -> Option< Ordering > + { + self.id.partial_cmp( &other.id ) + } + } + /// A collection of commands. /// - /// This structure holds a hashmap of commands where each command is mapped to its name. + /// This structure holds a btreemap of commands where each command is mapped to its name. #[ derive( Debug, Default, Former, Clone ) ] pub struct Dictionary { #[ scalar( setter = false, hint = false ) ] - pub( crate ) commands : HashMap< String, Command >, + pub( crate ) commands : BTreeMap< CommandName, Command >, + #[ scalar( setter = false, hint = false ) ] + dictionary_last_id : usize, + pub( crate ) order : Order, } // qqq : IDK how to integrate it into the `CommandsAggregatorFormer` @@ -31,7 +85,9 @@ pub( crate ) mod private pub fn command( mut self, command : Command ) -> Self { let mut commands = self.storage.commands.unwrap_or_default(); - commands.extend([( command.phrase.clone(), command )]); + self.storage.dictionary_last_id = Some( self.storage.dictionary_last_id.unwrap_or_default() + 1 ); + let name = CommandName{ id : self.storage.dictionary_last_id.unwrap(), name : command.phrase.clone() }; + commands.insert( name, command ); self.storage.commands = Some( commands ); self @@ -47,7 +103,9 @@ pub( crate ) mod private /// * `command` - The command to be registered. pub fn register( &mut self, command : Command ) -> Option< Command > { - self.commands.insert( command.phrase.clone(), command ) + self.dictionary_last_id += 1; + let name = CommandName{ id : self.dictionary_last_id, name : command.phrase.clone() }; + self.commands.insert( name, command ) } /// Retrieves the command with the specified `name` from the `commands` hashmap. @@ -62,10 +120,9 @@ pub( crate ) mod private /// Returns `None` if no command with the specified `name` is found. pub fn command< Name >( &self, name : &Name ) -> Option< &Command > where - String : std::borrow::Borrow< Name >, - Name : std::hash::Hash + Eq, + Name : std::hash::Hash + Eq + Ord + ToString, { - self.commands.get( name ) + self.commands.iter().find( |(k, _)| k.name == name.to_string() ).map(|(_, v)| v) } /// Find commands that match a given name part. @@ -86,6 +143,22 @@ pub( crate ) mod private { self.commands.values().filter( | command | command.phrase.starts_with( name_part.as_ref() ) ).collect() } + + /// asd + pub fn commands( &self ) -> Vec< ( &String, &Command ) > + { + match self.order + { + Order::Nature => + { + self.commands.iter().map( | ( key, value ) | ( &key.name, value ) ).collect() + } + Order::Lexicography => + { + self.commands.iter().map( | ( key, value ) | ( &key.name, value ) ).sorted_by_key( | ( key, _ ) | *key ).collect() + } + } + } } } diff --git a/module/move/wca/src/ca/help.rs b/module/move/wca/src/ca/help.rs index b931f26cb4..a1ff2ef880 100644 --- a/module/move/wca/src/ca/help.rs +++ b/module/move/wca/src/ca/help.rs @@ -12,6 +12,7 @@ pub( crate ) mod private use error_tools::for_app::anyhow; use former::Former; use ca::tool::table::format_table; + use crate::ca::aggregator::private::Order; // qqq : for Bohdan : it should transparent mechanist which patch list of commands, not a stand-alone mechanism @@ -53,10 +54,8 @@ pub( crate ) mod private pub description_detailing : LevelOfDetail, /// If enabled - shows complete description of subjects and properties pub with_footer : bool, - /// Stores the order in which the properties were described. - order : Option< Vec< String > >, - /// Flag which means in what order the commands and properties to them will be displayed. - with_nature_order : bool, + /// Order of property and commands. + pub order : Order, } // qqq : for Barsik : make possible to change properties order @@ -94,25 +93,13 @@ pub( crate ) mod private LevelOfDetail::None => "".into(), _ if command.subjects.is_empty() => "".into(), LevelOfDetail::Simple => "< properties >".into(), - LevelOfDetail::Detailed if o.with_nature_order => command.properties_order.iter().map( | n | format!( "< {n}:{}{:?} >", if command.properties.get(n).unwrap().optional { "?" } else { "" }, command.properties.get(n).unwrap().kind ) ).collect::< Vec< _ > >().join( " " ), - LevelOfDetail::Detailed => command.properties.iter().map( |( n, v )| format!( "< {n}:{}{:?} >", if v.optional { "?" } else { "" }, v.kind ) ).collect::< Vec< _ > >().join( " " ), + LevelOfDetail::Detailed => command.properties( dictionary.order ).iter().map( |( n, v )| format!( "< {}:{}{:?} >", if v.optional { "?" } else { "" }, n, v.kind ) ).collect::< Vec< _ > >().join( " " ), }; let footer = if o.with_footer { let full_subjects = command.subjects.iter().map( | subj | format!( "- {} [{}{:?}]", subj.hint, if subj.optional { "?" } else { "" }, subj.kind ) ).join( "\n\t" ); - let full_properties = format_table - ( - if o.with_nature_order - { - command.properties_order.iter().map( | name | ( name, command.properties.get( name ).unwrap() ) ).collect::< Vec< _ > >() - } - else - { - command.properties.iter().sorted_by_key( | ( name, _ ) | *name ).collect::< Vec< _ > >() - } - .into_iter().map( | ( name, value ) | [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] ) - ).unwrap().replace( '\n', "\n\t" ); + let full_properties = format_table( command.properties( dictionary.order ).into_iter().map( | ( name, value ) | [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] )).unwrap().replace( '\n', "\n\t" ); format! ( @@ -147,25 +134,12 @@ pub( crate ) mod private } else { - if let Some(order) = o.order - { - let rows = order - .iter() - .map( | k | dictionary.commands.get( k ).unwrap() ) - .map( for_single_command ) - .map( | row | [ row.name, row.args, row.hint ] ); - format_table( rows ).unwrap() - } - else - { - let rows = dictionary.commands - .iter() - .sorted_by_key( |( name, _ )| *name ) - .map( |( _, cmd )| cmd ) - .map( for_single_command ) - .map( | row | [ row.name, row.args, row.hint ] ); - format_table( rows ).unwrap() - } + let rows = dictionary.commands() + .into_iter() + .map( |( _, cmd )| cmd ) + .map( for_single_command ) + .map( | row | [ row.name, row.args, row.hint ] ); + format_table( rows ).unwrap() } } @@ -186,25 +160,25 @@ pub( crate ) mod private impl HelpVariants { /// Generates help commands - pub fn generate( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) + pub fn generate( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Order ) { match self { HelpVariants::All => { - self.general_help( helper, dictionary, order.clone() ); - self.subject_command_help( helper, dictionary, order ); + self.general_help( helper, dictionary, order ); + self.subject_command_help( helper, dictionary ); // self.dot_command_help( helper, dictionary ); }, HelpVariants::General => self.general_help( helper, dictionary, order ), - HelpVariants::SubjectCommand => self.subject_command_help( helper, dictionary, order ), + HelpVariants::SubjectCommand => self.subject_command_help( helper, dictionary ), _ => unimplemented!() // HelpVariants::DotCommand => self.dot_command_help( helper, dictionary ), } } // .help - fn general_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) + fn general_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Order ) { let phrase = "help".to_string(); @@ -229,20 +203,15 @@ pub( crate ) mod private }; if format == HelpFormat::Markdown { - println!( "Help command\n{text}", text = md_generator( &grammar ) ); + println!( "Help command\n{text}", text = md_generator( &grammar, order ) ); } else { - let mut options = HelpGeneratorOptions::former() + let options = HelpGeneratorOptions::former() .command_prefix( "." ) .description_detailing( LevelOfDetail::Simple ) .subject_detailing( LevelOfDetail::Simple ) - .property_detailing( LevelOfDetail::Simple ) - .with_nature_order( order.is_some() ); - if let Some(order) = order.as_ref() - { - options = options.order( order.clone() ); - } + .property_detailing( LevelOfDetail::Simple ); println! ( "Help command\n\n{text}", @@ -273,7 +242,7 @@ pub( crate ) mod private } // .help command_name - fn subject_command_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary, order : Option< Vec< String > > ) + fn subject_command_help( &self, helper : &HelpGeneratorFn, dictionary : &mut Dictionary ) { let phrase = "help".to_string(); @@ -293,18 +262,14 @@ pub( crate ) mod private let command = o.args.get_owned::< String >( 0 ).unwrap(); let cmd = grammar.commands.get( &command ).ok_or_else( || anyhow!( "Can not found help for command `{command}`" ) )?; - let mut args = HelpGeneratorOptions::former() + let args = HelpGeneratorOptions::former() .command_prefix( "." ) .for_commands([ cmd ]) .description_detailing( LevelOfDetail::Detailed ) .subject_detailing( LevelOfDetail::Simple ) .property_detailing( LevelOfDetail::Simple ) - .with_footer( true ) - .with_nature_order( order.is_some() ); - if let Some(order) = order.as_ref() - { - args = args.order( order.clone() ); - } + .with_footer( true ); + let text = generator.exec( &grammar, args.form() ); println!( "Help command\n\n{text}" ); diff --git a/module/move/wca/src/ca/verifier/verifier.rs b/module/move/wca/src/ca/verifier/verifier.rs index 3ddf6efc8e..0c898969fa 100644 --- a/module/move/wca/src/ca/verifier/verifier.rs +++ b/module/move/wca/src/ca/verifier/verifier.rs @@ -4,9 +4,10 @@ pub( crate ) mod private use ca::grammar::command::ValueDescription; // use former::Former; - use std::collections::HashMap; + use std::collections::{ BTreeMap, HashMap }; use wtools::{ error, error::Result, err }; use ca::help::private::{ HelpGeneratorOptions, LevelOfDetail, generate_help_content }; + use crate::ca::grammar::dictionary::private::CommandName; /// Converts a `ParsedCommand` to a `VerifiedCommand` by performing validation and type casting on values. /// @@ -63,7 +64,7 @@ pub( crate ) mod private let sim = dictionary .commands .iter() - .map( |( name, c )| ( jaro.for_str( name, user_input ).nsim(), c ) ) + .map( |( name, c )| ( jaro.for_str( name.name.as_str(), user_input ).nsim(), c ) ) .max_by( |( s1, _ ), ( s2, _ )| s1.total_cmp( s2 ) ); if let Some(( sim, variant )) = sim { @@ -79,7 +80,7 @@ pub( crate ) mod private fn get_count_from_properties ( - properties : &HashMap< String, ValueDescription >, + properties : &BTreeMap< CommandName, ValueDescription >, properties_aliases : &HashMap< String, String >, raw_properties : &HashMap< String, String > ) -> usize diff --git a/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs b/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs index 7c87449bcf..4ce4e06ab6 100644 --- a/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs +++ b/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs @@ -1,6 +1,6 @@ fn main() { - use wca::{ Type, VerifiedCommand }; + use wca::{ Type, VerifiedCommand, Order }; let ca = wca::CommandsAggregator::former() .command( "c" ) @@ -20,7 +20,7 @@ fn main() .property( "a-property" ).kind( Type::String ).optional( true ).end() .routine( | o : VerifiedCommand | { println!("a") } ) .end() - .with_nature_sort( false ) + .order( Order::Lexicography ) .perform(); let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); diff --git a/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs b/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs index 1c9815a364..e43a7054c6 100644 --- a/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs +++ b/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs @@ -1,6 +1,6 @@ fn main() { - use wca::{ Type, VerifiedCommand }; + use wca::{ Type, VerifiedCommand, Order }; let ca = wca::CommandsAggregator::former() .command( "c" ) @@ -20,7 +20,8 @@ fn main() .property( "a-property" ).kind( Type::String ).optional( true ).end() .routine( | o : VerifiedCommand | { println!("a") } ) .end() - .with_nature_sort( true ) + .order( Order::Nature ) + .perform(); let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); diff --git a/module/move/wca/tests/inc/commands_aggregator/help.rs b/module/move/wca/tests/inc/commands_aggregator/help.rs index 9dcfa92649..6e939f505c 100644 --- a/module/move/wca/tests/inc/commands_aggregator/help.rs +++ b/module/move/wca/tests/inc/commands_aggregator/help.rs @@ -29,7 +29,6 @@ pub fn start_sync< AP, Args, Arg, P > let args = args.into_iter().map( | a | a.as_ref().into() ).collect::< Vec< std::ffi::OsString > >(); let child = Command::new( application ).args( &args ).stdout( Stdio::piped() ).stderr( Stdio::piped() ).current_dir( path ).spawn().unwrap(); let output = child.wait_with_output().unwrap(); - dbg!( &output ); String::from_utf8( output.stdout ).unwrap() } @@ -110,7 +109,6 @@ wca = {{path = "{}"}}"#, file.write_all( toml.as_bytes() ).unwrap(); let result = start_sync( "cargo", [ "r", ".help" ], temp.path() ); - // dbg!(&result); assert_eq! ( "Help command\n\n.c - c\n.b - b\n.a - a\n", @@ -178,7 +176,6 @@ wca = {{path = "{}"}}"#, file.write_all( toml.as_bytes() ).unwrap(); let result = start_sync( "cargo", [ "r", ".help" ], temp.path() ); - // dbg!(&result); assert_eq! ( "Help command\n\n.a - a\n.b - b\n.c - c\n", @@ -187,7 +184,6 @@ wca = {{path = "{}"}}"#, let result = start_sync( "cargo", [ "r", ".help", "c" ], temp.path() ); - dbg!(&result); assert_eq! ( "Help command\n\n.c - c\n\nProperties:\n\ta-property - [?String]\n\tb-property - [?String]\n\tc-property - [?String]\n", From e6ab3454b6c7f40078958e71248ae799c02463c6 Mon Sep 17 00:00:00 2001 From: SRetip Date: Tue, 28 May 2024 18:16:55 +0300 Subject: [PATCH 7/8] import fix --- module/move/wca/src/ca/aggregator.rs | 2 +- module/move/wca/src/ca/formatter.rs | 2 +- module/move/wca/src/ca/grammar/command.rs | 12 ++++-------- module/move/wca/src/ca/grammar/dictionary.rs | 19 +++++++++---------- module/move/wca/src/ca/help.rs | 13 +++++++++---- module/move/wca/src/ca/verifier/verifier.rs | 1 - 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index abf9a3a1ce..8336b1df29 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -142,7 +142,7 @@ pub( crate ) mod private let help_generator = std::mem::take( &mut ca.help_generator ).unwrap_or_default(); let help_variants = std::mem::take( &mut ca.help_variants ).unwrap_or_else( || HashSet::from([ HelpVariants::All ]) ); - + if help_variants.contains( &HelpVariants::All ) { HelpVariants::All.generate( &help_generator, dictionary, ca.order.unwrap_or_default() ); diff --git a/module/move/wca/src/ca/formatter.rs b/module/move/wca/src/ca/formatter.rs index 3b4f989f1d..368ec8e88f 100644 --- a/module/move/wca/src/ca/formatter.rs +++ b/module/move/wca/src/ca/formatter.rs @@ -3,7 +3,7 @@ pub( crate ) mod private use crate::*; use wtools::Itertools; - use crate::ca::aggregator::private::Order; + use ca::aggregator::private::Order; /// - #[ derive( Debug, Clone, PartialEq ) ] diff --git a/module/move/wca/src/ca/grammar/command.rs b/module/move/wca/src/ca/grammar/command.rs index ed1d4e8eee..46df984439 100644 --- a/module/move/wca/src/ca/grammar/command.rs +++ b/module/move/wca/src/ca/grammar/command.rs @@ -1,14 +1,10 @@ pub( crate ) mod private { use crate::*; - - use { Handler, Routine, Type }; - + use std::collections::{ BTreeMap, HashMap }; use former::{ Former, StoragePreform }; - use crate::ca::aggregator::private::Order; - use crate::ca::grammar::dictionary::private::CommandName; - use crate::wtools::Itertools; + use wtools::Itertools; /// A description of a Value in a command. Used to specify the expected type and provide a hint for the Value. /// @@ -102,7 +98,7 @@ pub( crate ) mod private pub subjects : Vec< ValueDescription >, /// Hints and types for command options. pub properties : BTreeMap< CommandName, ValueDescription >, - /// Last inserted command id. + /// Last inserted property id. #[ scalar( setter = false ) ] last_id : usize, /// Map of aliases. @@ -232,7 +228,7 @@ pub( crate ) mod private }; debug_assert!( !properties.contains_key( &property.name ), "Property name `{}` is already used for `{:?}`", property.name, properties[ &property.name ] ); super_former.storage.last_id = Some( super_former.storage.last_id.unwrap_or_default() + 1 ); - let name = CommandName{ id : super_former.storage.last_id.unwrap(), name : property.name.clone() }; + let name = CommandName { id : super_former.storage.last_id.unwrap(), name : property.name.clone() }; properties.insert( name, value ); let mut aliases = super_former.storage.properties_aliases.unwrap_or_default(); diff --git a/module/move/wca/src/ca/grammar/dictionary.rs b/module/move/wca/src/ca/grammar/dictionary.rs index 86c4f5b6db..57ad3f1d71 100644 --- a/module/move/wca/src/ca/grammar/dictionary.rs +++ b/module/move/wca/src/ca/grammar/dictionary.rs @@ -1,14 +1,10 @@ pub( crate ) mod private { - use std::cmp::Ordering; use crate::*; - - use { Command }; - use std::collections::BTreeMap; - use std::fmt::Display; use former::Former; - use crate::ca::aggregator::private::Order; - use crate::wtools::Itertools; + use wtools::Itertools; + use std::cmp::Ordering; + use std::collections::BTreeMap; // qqq : `Former` does not handle this situation well @@ -22,7 +18,9 @@ pub( crate ) mod private #[ derive( Debug, Default, Clone, Eq ) ] pub struct CommandName { + /// id of command. pub( crate ) id : usize, + /// Name of command. pub name : String, } @@ -86,7 +84,7 @@ pub( crate ) mod private { let mut commands = self.storage.commands.unwrap_or_default(); self.storage.dictionary_last_id = Some( self.storage.dictionary_last_id.unwrap_or_default() + 1 ); - let name = CommandName{ id : self.storage.dictionary_last_id.unwrap(), name : command.phrase.clone() }; + let name = CommandName { id : self.storage.dictionary_last_id.unwrap(), name : command.phrase.clone() }; commands.insert( name, command ); self.storage.commands = Some( commands ); @@ -104,7 +102,7 @@ pub( crate ) mod private pub fn register( &mut self, command : Command ) -> Option< Command > { self.dictionary_last_id += 1; - let name = CommandName{ id : self.dictionary_last_id, name : command.phrase.clone() }; + let name = CommandName { id : self.dictionary_last_id, name : command.phrase.clone() }; self.commands.insert( name, command ) } @@ -122,7 +120,7 @@ pub( crate ) mod private where Name : std::hash::Hash + Eq + Ord + ToString, { - self.commands.iter().find( |(k, _)| k.name == name.to_string() ).map(|(_, v)| v) + self.commands.iter().find( | ( k, _ ) | k.name == name.to_string() ).map( | ( _, v ) | v ) } /// Find commands that match a given name part. @@ -167,4 +165,5 @@ pub( crate ) mod private crate::mod_interface! { exposed use Dictionary; + exposed use CommandName; } diff --git a/module/move/wca/src/ca/help.rs b/module/move/wca/src/ca/help.rs index a1ff2ef880..cc8c897b70 100644 --- a/module/move/wca/src/ca/help.rs +++ b/module/move/wca/src/ca/help.rs @@ -4,15 +4,20 @@ pub( crate ) mod private use ca:: { Command, - Routine, Type, formatter::private::{ HelpFormat, md_generator }, + Routine, + Type, + formatter::private:: + { + HelpFormat, + md_generator + }, + tool::table::format_table, }; use wtools::Itertools; use std::rc::Rc; use error_tools::for_app::anyhow; use former::Former; - use ca::tool::table::format_table; - use crate::ca::aggregator::private::Order; // qqq : for Bohdan : it should transparent mechanist which patch list of commands, not a stand-alone mechanism @@ -99,7 +104,7 @@ pub( crate ) mod private let footer = if o.with_footer { let full_subjects = command.subjects.iter().map( | subj | format!( "- {} [{}{:?}]", subj.hint, if subj.optional { "?" } else { "" }, subj.kind ) ).join( "\n\t" ); - let full_properties = format_table( command.properties( dictionary.order ).into_iter().map( | ( name, value ) | [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] )).unwrap().replace( '\n', "\n\t" ); + let full_properties = format_table( command.properties( dictionary.order ).into_iter().map( | ( name, value ) | [ name.clone(), format!( "- {} [{}{:?}]", value.hint, if value.optional { "?" } else { "" }, value.kind ) ] ) ).unwrap().replace( '\n', "\n\t" ); format! ( diff --git a/module/move/wca/src/ca/verifier/verifier.rs b/module/move/wca/src/ca/verifier/verifier.rs index 0c898969fa..8fe25073d3 100644 --- a/module/move/wca/src/ca/verifier/verifier.rs +++ b/module/move/wca/src/ca/verifier/verifier.rs @@ -7,7 +7,6 @@ pub( crate ) mod private use std::collections::{ BTreeMap, HashMap }; use wtools::{ error, error::Result, err }; use ca::help::private::{ HelpGeneratorOptions, LevelOfDetail, generate_help_content }; - use crate::ca::grammar::dictionary::private::CommandName; /// Converts a `ParsedCommand` to a `VerifiedCommand` by performing validation and type casting on values. /// From 22f9eac2069892f9c5772229751c019829da2470 Mon Sep 17 00:00:00 2001 From: SRetip Date: Tue, 28 May 2024 18:51:27 +0300 Subject: [PATCH 8/8] test fix --- .../tests/assets/wca_hello_test/src/main.rs | 16 -- .../src/main.rs | 28 --- .../wca_help_test_nature_order/src/main.rs | 29 --- .../wca/tests/inc/commands_aggregator/help.rs | 186 +++++++++--------- 4 files changed, 95 insertions(+), 164 deletions(-) delete mode 100644 module/move/wca/tests/assets/wca_hello_test/src/main.rs delete mode 100644 module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs delete mode 100644 module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs diff --git a/module/move/wca/tests/assets/wca_hello_test/src/main.rs b/module/move/wca/tests/assets/wca_hello_test/src/main.rs deleted file mode 100644 index 796622c3e5..0000000000 --- a/module/move/wca/tests/assets/wca_hello_test/src/main.rs +++ /dev/null @@ -1,16 +0,0 @@ -fn main() -{ - use wca::{ Type, VerifiedCommand }; - - let ca = wca::CommandsAggregator::former() - .command( "echo" ) - .hint( "prints all subjects and properties" ) - .subject().hint( "Subject" ).kind( Type::String ).optional( true ).end() - .property( "property" ).hint( "simple property" ).kind( Type::String ).optional( true ).end() - .routine( | o : VerifiedCommand | { println!( "= Args\n{:?}\n\n= Properties\n{:?}\n", o.args, o.props ) } ) - .end() - .perform(); - - let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); - ca.perform( args ).unwrap(); -} \ No newline at end of file diff --git a/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs b/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs deleted file mode 100644 index 4ce4e06ab6..0000000000 --- a/module/move/wca/tests/assets/wca_help_test_lexicography_order/src/main.rs +++ /dev/null @@ -1,28 +0,0 @@ -fn main() -{ - use wca::{ Type, VerifiedCommand, Order }; - - let ca = wca::CommandsAggregator::former() - .command( "c" ) - .hint( "c" ) - .property( "c-property" ).kind( Type::String ).optional( true ).end() - .property( "b-property" ).kind( Type::String ).optional( true ).end() - .property( "a-property" ).kind( Type::String ).optional( true ).end() - .routine( | o : VerifiedCommand | { println!("c") } ) - .end() - .command( "b" ) - .hint( "b" ) - .property( "b-property" ).kind( Type::String ).optional( true ).end() - .routine( | o : VerifiedCommand | { println!("b") } ) - .end() - .command( "a" ) - .hint( "a" ) - .property( "a-property" ).kind( Type::String ).optional( true ).end() - .routine( | o : VerifiedCommand | { println!("a") } ) - .end() - .order( Order::Lexicography ) - .perform(); - - let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); - ca.perform( args ).unwrap(); -} \ No newline at end of file diff --git a/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs b/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs deleted file mode 100644 index e43a7054c6..0000000000 --- a/module/move/wca/tests/assets/wca_help_test_nature_order/src/main.rs +++ /dev/null @@ -1,29 +0,0 @@ -fn main() -{ - use wca::{ Type, VerifiedCommand, Order }; - - let ca = wca::CommandsAggregator::former() - .command( "c" ) - .hint( "c" ) - .property( "c-property" ).kind( Type::String ).optional( true ).end() - .property( "b-property" ).kind( Type::String ).optional( true ).end() - .property( "a-property" ).kind( Type::String ).optional( true ).end() - .routine( | o : VerifiedCommand | { println!("c") } ) - .end() - .command( "b" ) - .hint( "b" ) - .property( "b-property" ).kind( Type::String ).optional( true ).end() - .routine( | o : VerifiedCommand | { println!("b") } ) - .end() - .command( "a" ) - .hint( "a" ) - .property( "a-property" ).kind( Type::String ).optional( true ).end() - .routine( | o : VerifiedCommand | { println!("a") } ) - .end() - .order( Order::Nature ) - - .perform(); - - let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); - ca.perform( args ).unwrap(); -} \ No newline at end of file diff --git a/module/move/wca/tests/inc/commands_aggregator/help.rs b/module/move/wca/tests/inc/commands_aggregator/help.rs index 6e939f505c..1df2be062e 100644 --- a/module/move/wca/tests/inc/commands_aggregator/help.rs +++ b/module/move/wca/tests/inc/commands_aggregator/help.rs @@ -1,23 +1,8 @@ -use std::fs::File; +use std::fs::{DirBuilder, File}; use std::io::Write; use std::path::Path; use std::process::{Command, Stdio}; -use assert_fs::fixture::PathCopy; -const ASSET_PATH : &str = concat!( env!("CARGO_MANIFEST_DIR"), "/tests/assets/" ); - - -fn arrange( source: &str ) -> assert_fs::TempDir -{ - let root_path = Path::new( env!( "CARGO_MANIFEST_DIR" ) ); - let assets_relative_path = Path::new( ASSET_PATH ); - let assets_path = root_path.join( assets_relative_path ); - - let temp = assert_fs::TempDir::new().unwrap(); - temp.copy_from( assets_path.join( source ), &[ "**" ] ).unwrap(); - - temp -} pub fn start_sync< AP, Args, Arg, P > ( application : AP, @@ -29,13 +14,15 @@ pub fn start_sync< AP, Args, Arg, P > let args = args.into_iter().map( | a | a.as_ref().into() ).collect::< Vec< std::ffi::OsString > >(); let child = Command::new( application ).args( &args ).stdout( Stdio::piped() ).stderr( Stdio::piped() ).current_dir( path ).spawn().unwrap(); let output = child.wait_with_output().unwrap(); - + String::from_utf8( output.stdout ).unwrap() } #[ test ] fn help_command_with_optional_params() { + let temp = assert_fs::TempDir::new().unwrap(); + let toml = format! ( r#"[package] @@ -46,12 +33,26 @@ edition = "2021" wca = {{path = "{}"}}"#, env!( "CARGO_MANIFEST_DIR" ).replace( "\\", "/" ) ) ; - - let temp = arrange( "wca_hello_test" ); - let mut file = File::create( temp.path().join( "Cargo.toml" ) ).unwrap(); - file.write_all( toml.as_bytes() ).unwrap(); + + let main = r#"use wca::{ Type, VerifiedCommand }; + fn main(){ + let ca = wca::CommandsAggregator::former() + .command( "echo" ) + .hint( "prints all subjects and properties" ) + .subject().hint( "Subject" ).kind( Type::String ).optional( true ).end() + .property( "property" ).hint( "simple property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!( "= Args\n{:?}\n\n= Properties\n{:?}\n", o.args, o.props ) } ) + .end() + .perform(); + + let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); + ca.perform( args ).unwrap(); + } + "#; + File::create( temp.path().join( "Cargo.toml" ) ).unwrap().write_all( toml.as_bytes() ).unwrap(); + DirBuilder::new().create( temp.join( "src" ) ).unwrap(); + File::create( temp.path().join( "src" ).join( "main.rs" ) ).unwrap().write_all( main.as_bytes() ).unwrap(); let result = start_sync( "cargo", [ "r", ".help", "echo" ], temp.path() ); - assert_eq! ( "Help command\n\n.echo < subjects > < properties > - prints all subjects and properties\n\nSubjects:\n\t- Subject [?String]\nProperties:\n\tproperty - simple property [?String]\n", @@ -59,40 +60,11 @@ wca = {{path = "{}"}}"#, ); } -/// `wca_help_test_nature_order/src/main.rs` : -/// ```rust -/// fn main() -/// { -/// use wca::{ Type, VerifiedCommand }; -/// -/// let ca = wca::CommandsAggregator::former() -/// .command( "c" ) -/// .hint( "c" ) -/// .property( "c-property" ).kind( Type::String ).optional( true ).end() -/// .property( "b-property" ).kind( Type::String ).optional( true ).end() -/// .property( "a-property" ).kind( Type::String ).optional( true ).end() -/// .routine( | o : VerifiedCommand | { println!("c") } ) -/// .end() -/// .command( "b" ) -/// .hint( "b" ) -/// .property( "b-property" ).kind( Type::String ).optional( true ).end() -/// .routine( | o : VerifiedCommand | { println!("b") } ) -/// .end() -/// .command( "a" ) -/// .hint( "a" ) -/// .property( "a-property" ).kind( Type::String ).optional( true ).end() -/// .routine( | o : VerifiedCommand | { println!("a") } ) -/// .end() -/// .with_nature_sort( true ) -/// .perform(); -/// -/// let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); -/// ca.perform( args ).unwrap(); -/// } -/// ``` #[ test ] fn help_command_with_nature_order() { + let temp = assert_fs::TempDir::new().unwrap(); + let toml = format! ( r#"[package] @@ -104,9 +76,40 @@ wca = {{path = "{}"}}"#, env!( "CARGO_MANIFEST_DIR" ).replace( "\\", "/" ) ) ; - let temp = arrange( "wca_help_test_nature_order" ); - let mut file = File::create( temp.path().join( "Cargo.toml" ) ).unwrap(); - file.write_all( toml.as_bytes() ).unwrap(); + let main = r#"fn main() + { + use wca::{ Type, VerifiedCommand, Order }; + + let ca = wca::CommandsAggregator::former() + .command( "c" ) + .hint( "c" ) + .property( "c-property" ).kind( Type::String ).optional( true ).end() + .property( "b-property" ).kind( Type::String ).optional( true ).end() + .property( "a-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("c") } ) + .end() + .command( "b" ) + .hint( "b" ) + .property( "b-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("b") } ) + .end() + .command( "a" ) + .hint( "a" ) + .property( "a-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("a") } ) + .end() + .order( Order::Nature ) + + .perform(); + + let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); + ca.perform( args ).unwrap(); + }"#; + + File::create( temp.path().join( "Cargo.toml" ) ).unwrap().write_all( toml.as_bytes() ).unwrap(); + DirBuilder::new().create( temp.join( "src" ) ).unwrap(); + File::create( temp.path().join( "src" ).join( "main.rs" ) ).unwrap().write_all( main.as_bytes() ).unwrap(); + let result = start_sync( "cargo", [ "r", ".help" ], temp.path() ); assert_eq! @@ -117,7 +120,7 @@ wca = {{path = "{}"}}"#, let result = start_sync( "cargo", [ "r", ".help", "c" ], temp.path() ); - println!("{result}"); + println!( "{result}" ); assert_eq! ( @@ -126,40 +129,11 @@ wca = {{path = "{}"}}"#, ); } -/// `wca_help_test_lexicography_order/src/main.rs` : -/// ```rust -/// fn main() -/// { -/// use wca::{ Type, VerifiedCommand }; -/// -/// let ca = wca::CommandsAggregator::former() -/// .command( "c" ) -/// .hint( "c" ) -/// .property( "c-property" ).kind( Type::String ).optional( true ).end() -/// .property( "b-property" ).kind( Type::String ).optional( true ).end() -/// .property( "a-property" ).kind( Type::String ).optional( true ).end() -/// .routine( | o : VerifiedCommand | { println!("c") } ) -/// .end() -/// .command( "b" ) -/// .hint( "b" ) -/// .property( "b-property" ).kind( Type::String ).optional( true ).end() -/// .routine( | o : VerifiedCommand | { println!("b") } ) -/// .end() -/// .command( "a" ) -/// .hint( "a" ) -/// .property( "a-property" ).kind( Type::String ).optional( true ).end() -/// .routine( | o : VerifiedCommand | { println!("a") } ) -/// .end() -/// .with_nature_sort( false ) -/// .perform(); -/// -/// let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); -/// ca.perform( args ).unwrap(); -/// } -/// ``` #[ test ] fn help_command_with_lexicography_order() { + let temp = assert_fs::TempDir::new().unwrap(); + let toml = format! ( r#"[package] @@ -171,9 +145,39 @@ wca = {{path = "{}"}}"#, env!( "CARGO_MANIFEST_DIR" ).replace( "\\", "/" ) ) ; - let temp = arrange( "wca_help_test_lexicography_order" ); - let mut file = File::create( temp.path().join( "Cargo.toml" ) ).unwrap(); - file.write_all( toml.as_bytes() ).unwrap(); + let main = r#"fn main() + { + use wca::{ Type, VerifiedCommand, Order }; + + let ca = wca::CommandsAggregator::former() + .command( "c" ) + .hint( "c" ) + .property( "c-property" ).kind( Type::String ).optional( true ).end() + .property( "b-property" ).kind( Type::String ).optional( true ).end() + .property( "a-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("c") } ) + .end() + .command( "b" ) + .hint( "b" ) + .property( "b-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("b") } ) + .end() + .command( "a" ) + .hint( "a" ) + .property( "a-property" ).kind( Type::String ).optional( true ).end() + .routine( | o : VerifiedCommand | { println!("a") } ) + .end() + .order( Order::Lexicography ) + .perform(); + + let args = std::env::args().skip( 1 ).collect::< Vec< String > >(); + ca.perform( args ).unwrap(); + }"#; + + File::create( temp.path().join( "Cargo.toml" ) ).unwrap().write_all( toml.as_bytes() ).unwrap(); + DirBuilder::new().create( temp.join( "src" ) ).unwrap(); + File::create( temp.path().join( "src" ).join( "main.rs" ) ).unwrap().write_all( main.as_bytes() ).unwrap(); + let result = start_sync( "cargo", [ "r", ".help" ], temp.path() ); assert_eq!