Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

READY : Allow to save nature order in commands & props #1325

Merged
merged 11 commits into from
May 29, 2024
11 changes: 6 additions & 5 deletions module/move/wca/examples/wca_trivial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! A trivial example.
//!

use wca::{ CommandsAggregator, Type, VerifiedCommand };
use wca::{ CommandsAggregator, Order, Type, VerifiedCommand };

fn f1( o : VerifiedCommand )
{
Expand All @@ -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()
;

Expand Down
20 changes: 17 additions & 3 deletions module/move/wca/src/ca/aggregator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) ]
Expand Down Expand Up @@ -100,7 +111,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 >, order : Order ) ]
#[ mutator( custom = true ) ]
// #[ debug ]
pub struct CommandsAggregator
Expand All @@ -127,19 +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 ]) );

if help_variants.contains( &HelpVariants::All )
{
HelpVariants::All.generate( &help_generator, dictionary );
HelpVariants::All.generate( &help_generator, dictionary, ca.order.unwrap_or_default() );
}
else
{
for help in help_variants.iter().sorted()
{
help.generate( &help_generator, dictionary );
help.generate( &help_generator, dictionary, ca.order.unwrap_or_default() );
}
}
}
Expand All @@ -158,6 +170,7 @@ pub( crate ) mod private
where
IntoName : Into< String >,
{
let name = name.into();
let on_end = | command : CommandFormerStorage, super_former : Option< Self > | -> Self
{
let mut super_former = super_former.unwrap();
Expand Down Expand Up @@ -279,4 +292,5 @@ crate::mod_interface!
exposed use CommandsAggregatorFormer;
exposed use Error;
exposed use ValidationError;
exposed use Order;
}
25 changes: 12 additions & 13 deletions module/move/wca/src/ca/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub( crate ) mod private

use crate::*;
use wtools::Itertools;
use ca::aggregator::private::Order;

/// -
#[ derive( Debug, Clone, PartialEq ) ]
Expand All @@ -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" },
Expand All @@ -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
Expand All @@ -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
Expand Down
36 changes: 29 additions & 7 deletions module/move/wca/src/ca/grammar/command.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
pub( crate ) mod private
{
use crate::*;

use { Handler, Routine, Type };

use std::collections::HashMap;

use std::collections::{ BTreeMap, HashMap };
use former::{ Former, StoragePreform };
use wtools::Itertools;

/// A description of a Value in a command. Used to specify the expected type and provide a hint for the Value.
///
Expand Down Expand Up @@ -86,7 +85,6 @@ pub( crate ) mod private

#[ derive( Debug, Clone, PartialEq, Eq ) ]
#[ derive( Former ) ]
// #[ debug ]
pub struct Command
{
/// Command common hint.
Expand All @@ -99,7 +97,10 @@ pub( crate ) mod private
#[ subform_entry( setter = true ) ]
pub subjects : Vec< ValueDescription >,
/// Hints and types for command options.
pub properties : HashMap< String, ValueDescription >,
pub properties : BTreeMap< CommandName, ValueDescription >,
/// Last inserted property id.
#[ scalar( setter = false ) ]
last_id : usize,
/// Map of aliases.
// Aliased key -> Original key
pub properties_aliases : HashMap< String, String >,
Expand All @@ -111,6 +112,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
Expand Down Expand Up @@ -200,14 +219,17 @@ 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 value = ValueDescription
{
hint : property.hint,
kind : property.kind,
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 );
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 ] );
Expand Down
92 changes: 82 additions & 10 deletions module/move/wca/src/ca/grammar/dictionary.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
pub( crate ) mod private
{
use crate::*;

use { Command };
use std::collections::HashMap;
use former::Former;
use wtools::Itertools;
use std::cmp::Ordering;
use std::collections::BTreeMap;

// qqq : `Former` does not handle this situation well

Expand All @@ -14,14 +14,66 @@ 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
{
/// id of command.
pub( crate ) id : usize,
/// Name of command.
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`
Expand All @@ -31,7 +83,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
Expand All @@ -47,7 +101,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.
Expand All @@ -62,10 +118,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.
Expand All @@ -86,6 +141,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()
}
}
}
}
}

Expand All @@ -94,4 +165,5 @@ pub( crate ) mod private
crate::mod_interface!
{
exposed use Dictionary;
exposed use CommandName;
}
Loading
Loading