changed config-parser macro to check struct hirarchy when parsing

configuration file

fixed formatting of stack and bookmarks
This commit is contained in:
2025-01-19 16:38:35 +01:00
parent 281ca56741
commit 64e12222bd
7 changed files with 62 additions and 235 deletions
@@ -15,9 +15,9 @@ pub const STYLES: Styles = Styles {
bold: "1", bold: "1",
dim: "2", dim: "2",
italic: "3", italic: "3",
underline: "4", underlined: "4",
blink: "5", blinking: "5",
reverse: "7", reversed: "7",
invisible: "8", invisible: "8",
strikethrough: "9", strikethrough: "9",
}, },
@@ -25,9 +25,9 @@ pub const STYLES: Styles = Styles {
bold: "22", bold: "22",
dim: "22", dim: "22",
italic: "23", italic: "23",
underline: "24", underlined: "24",
blink: "25", blinking: "25",
reverse: "27", reversed: "27",
invisible: "28", invisible: "28",
strikethrough: "29", strikethrough: "29",
}, },
@@ -71,9 +71,9 @@ pub struct StyleCodes {
pub bold: &'static str, pub bold: &'static str,
pub dim: &'static str, pub dim: &'static str,
pub italic: &'static str, pub italic: &'static str,
pub underline: &'static str, pub underlined: &'static str,
pub blink: &'static str, pub blinking: &'static str,
pub reverse: &'static str, pub reversed: &'static str,
pub invisible: &'static str, pub invisible: &'static str,
pub strikethrough: &'static str, pub strikethrough: &'static str,
} }
@@ -217,9 +217,9 @@ pub fn parse_style(arg: &String) -> Result<String> {
"bold" => styles.push(generate_style_sequence(Some(STYLES.set.bold), None, None)), "bold" => styles.push(generate_style_sequence(Some(STYLES.set.bold), None, None)),
"dim" => styles.push(generate_style_sequence(Some(STYLES.set.dim), None, None)), "dim" => styles.push(generate_style_sequence(Some(STYLES.set.dim), None, None)),
"italic" => styles.push(generate_style_sequence(Some(STYLES.set.italic), None, None)), "italic" => styles.push(generate_style_sequence(Some(STYLES.set.italic), None, None)),
"underlined" => styles.push(generate_style_sequence(Some(STYLES.set.underline), None, None)), "underlined" => styles.push(generate_style_sequence(Some(STYLES.set.underlined), None, None)),
"blink" => styles.push(generate_style_sequence(Some(STYLES.set.blink), None, None)), "blinking" => styles.push(generate_style_sequence(Some(STYLES.set.blinking), None, None)),
"reverse" => styles.push(generate_style_sequence(Some(STYLES.set.reverse), None, None)), "reversed" => styles.push(generate_style_sequence(Some(STYLES.set.reversed), None, None)),
"invisible" => styles.push(generate_style_sequence(Some(STYLES.set.invisible), None, None)), "invisible" => styles.push(generate_style_sequence(Some(STYLES.set.invisible), None, None)),
"strikethrough" => styles.push(generate_style_sequence(Some(STYLES.set.strikethrough), None, None)), "strikethrough" => styles.push(generate_style_sequence(Some(STYLES.set.strikethrough), None, None)),
// named colors // named colors
@@ -15,24 +15,34 @@ pub fn gen_parse_from_string(config_name: &Ident, output_name: &Ident, assignmen
if !#config_name.is_empty() { if !#config_name.is_empty() {
let leftovers = #config_name.keys().cloned().collect::<Vec<String>>(); let leftovers = #config_name.keys().cloned().collect::<Vec<String>>();
return Err(std::io::Error::other(format!("the following settings were not recognised: {:#?}", leftovers))); #output_name.push(format!("the following settings were not recognised: {:#?}", leftovers));
}
if !#output_name.is_empty() {
return Err(std::io::Error::other(format!("{}", #output_name.join("\n"))));
} }
Ok(()) Ok(())
} }
} }
} }
pub fn gen_parse_from_map(config_name: &Ident, assignments: &TokenStream) -> TokenStream { pub fn gen_parse_from_map(config_name: &Ident, output_name: &Ident, assignments: &TokenStream) -> TokenStream {
quote! { quote! {
/// **do not call** /// **do not call**
/// this function needs to be public for nested configs but is not intended /// this function needs to be public for nested configs but is not intended
/// to be called by the user /// to be called by the user
pub fn parse_from_map(&mut self, input: &mut ConfigMap) -> std::io::Result<()> { pub fn parse_from_map(&mut self, input: ConfigMap) -> std::io::Result<()> {
let mut #config_name = input; let mut #config_name: ConfigMap = input;
let mut output: String = String::new(); let mut #output_name: Vec<String> = Vec::<String>::new();
#assignments #assignments
if !#config_name.is_empty() {
let leftovers = #config_name.keys().cloned().collect::<Vec<String>>();
#output_name.push(format!("the following settings were not recognised: {:#?}", leftovers));
}
if !#output_name.is_empty() {
return Err(std::io::Error::other(format!("{}", #output_name.join("\n"))));
}
Ok(()) Ok(())
} }
} }
@@ -140,10 +150,14 @@ pub fn gen_config_assignments(fields: &Punctuated<Field, Comma>, config_map_name
Some(attr_name) => { Some(attr_name) => {
if attr_name.ident == "nested_config" { if attr_name.ident == "nested_config" {
assignments.extend(quote! { assignments.extend(quote! {
if let Some(value) = #config_map_name.get(#name_string) { match #config_map_name.remove(#name_string) {
self.#name.parse_from_map(&mut value); Some(ConfigElement::Nested(map)) => {
} else { if let Err(error) = self.#name.parse_from_map(map) {
#output_name.push(&format!("no table `{}` found in config file", #name_string)); #output_name.push(error.to_string());
}
},
Some(ConfigElement::Setting(_)) => #output_name.push(format!("`{}` is defined as a nested element, but the configuration file defines it a setting element", #name_string)),
None => #output_name.push(format!("no table `{}` found in config file", #name_string)),
} }
}); });
continue 'fields; continue 'fields;
@@ -157,19 +171,25 @@ pub fn gen_config_assignments(fields: &Punctuated<Field, Comma>, config_map_name
//} else if let Attribute{ meta: Meta::List()} //} else if let Attribute{ meta: Meta::List()}
} }
assignments.extend(quote! { assignments.extend(quote! {
if let Some(value) = #config_map_name.get(#name_string) { match #config_map_name.remove(#name_string) {
self.#name = match value.parse::<#ty>() { Some(ConfigElement::Setting(value)) => {
Ok(parsed) => { self.#name = match value.parse::<#ty>() {
parsed Ok(parsed) => {
}, parsed
Err(_) => { },
#output_name.push(format!("failed to parse value found for `{}`", #name_string)); Err(_) => {
self.#name.clone() #output_name.push(format!("failed to parse value found for `{}`", #name_string));
}, self.#name.clone()
}; },
} else { };
#output_name.push(format!("could not find `{}` in config file", #name_string)); },
self.#name = self.#name.clone(); Some(ConfigElement::Nested(_)) => {
#output_name.push(format!("`{}` is a setting element, but the configuration file defines it as a nested element (Table)", #name_string));
},
None => {
#output_name.push(format!("could not find `{}` in config file", #name_string));
self.#name = self.#name.clone();
},
}; };
}); });
} }
+1 -1
View File
@@ -32,7 +32,7 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
}; };
let assignments: TokenStream = gen_config_assignments(fields, &config_name, &output_name); let assignments: TokenStream = gen_config_assignments(fields, &config_name, &output_name);
let func_parse_string: TokenStream = gen_parse_from_string(&config_name, &output_name, &assignments); let func_parse_string: TokenStream = gen_parse_from_string(&config_name, &output_name, &assignments);
let func_parse_map: TokenStream = gen_parse_from_map(&config_name, &assignments); let func_parse_map: TokenStream = gen_parse_from_map(&config_name, &output_name, &assignments);
let func_to_ansi_sequences: TokenStream = gen_to_ansi_sequences(fields); let func_to_ansi_sequences: TokenStream = gen_to_ansi_sequences(fields);
let func_default: TokenStream = gen_default(fields); let func_default: TokenStream = gen_default(fields);
+3 -1
View File
@@ -114,8 +114,10 @@ impl Bookmarks {
&config.format.bookmarks_separator, &config.format.bookmarks_separator,
&config.styles.bookmarks_seperator_style, &config.styles.bookmarks_seperator_style,
); );
let mut path = apply_format(path.to_str().unwrap(), &config.styles.bookmarks_path_style); let mut path = apply_format(path.to_str().unwrap(), &config.styles.bookmarks_path_style);
path = path.replace('/', &format!("{}/{}", config.styles.bookmarks_punct_style, RESET_SEQ)); path = path.replace('/', &format!("{}/{}{}", config.styles.bookmarks_punct_style, RESET_SEQ, &config.styles.bookmarks_path_style));
if config.format.align_separators { if config.format.align_separators {
buffer.push_str(&format!("{}{}{}{}\n", name, padding, separator, path)); buffer.push_str(&format!("{}{}{}{}\n", name, padding, separator, path));
} else { } else {
+3 -3
View File
@@ -60,7 +60,7 @@ pub struct StyleSettings {
#[default_value("default")] #[default_value("default")]
pub stack_path_style: String, pub stack_path_style: String,
#[style_config] #[style_config]
#[default_value("magenta")] #[default_value("green")]
pub stack_punct_style: String, pub stack_punct_style: String,
#[style_config] #[style_config]
#[default_value("default")] #[default_value("default")]
@@ -72,7 +72,7 @@ pub struct StyleSettings {
#[default_value("default")] #[default_value("default")]
pub bookmarks_path_style: String, pub bookmarks_path_style: String,
#[style_config] #[style_config]
#[default_value("magenta")] #[default_value("green")]
pub bookmarks_punct_style: String, pub bookmarks_punct_style: String,
} }
@@ -81,7 +81,7 @@ impl Config {
/// generates and populates a new instance of Config /// generates and populates a new instance of Config
pub fn new(styles_as_ansi_sequences: bool) -> Result<Self> { pub fn new(styles_as_ansi_sequences: bool) -> Result<Self> {
let mut config = Self::default(); let mut config: Config = Self::default();
// get configuration directory // get configuration directory
let mut conf_file = match config_dir() { let mut conf_file = match config_dir() {
Some(value) => value, Some(value) => value,
+1 -1
View File
@@ -49,7 +49,7 @@ impl Stack {
&config.styles.stack_separator_style, &config.styles.stack_separator_style,
); );
let mut path = apply_format(item.to_str().unwrap(), &config.styles.stack_path_style); let mut path = apply_format(item.to_str().unwrap(), &config.styles.stack_path_style);
path = path.replace('/', &format!("{}/{}", config.styles.stack_punct_style, RESET_SEQ)); path = path.replace('/', &format!("{}/{}{}", config.styles.stack_punct_style, RESET_SEQ, config.styles.stack_path_style));
if config.format.align_separators { if config.format.align_separators {
buffer.push_str(&format!("{}{}{}{}\n", number, padding, separator, path)); buffer.push_str(&format!("{}{}{}{}\n", number, padding, separator, path));
} else { } else {
-195
View File
@@ -1,195 +0,0 @@
ast = DeriveInput {
attrs: [],
vis: Visibility::Public(
Pub,
),
ident: Ident {
ident: "GeneralSettings",
span: #0 bytes(10021..10036),
},
generics: Generics {
lt_token: None,
params: [],
gt_token: None,
where_clause: None,
},
data: Data::Struct {
struct_token: Struct,
fields: Fields::Named {
brace_token: Brace,
named: [
Field {
attrs: [
Attribute {
pound_token: Pound,
style: AttrStyle::Outer,
bracket_token: Bracket,
meta: Meta::List {
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "default_value",
span: #0 bytes(10045..10058),
},
arguments: PathArguments::None,
},
],
},
delimiter: MacroDelimiter::Paren(
Paren,
),
tokens: TokenStream [
Ident {
ident: "false",
span: #0 bytes(10059..10064),
},
],
},
},
],
vis: Visibility::Public(
Pub,
),
mutability: FieldMutability::None,
ident: Some(
Ident {
ident: "show_stack_on_push",
span: #0 bytes(10075..10093),
},
),
colon_token: Some(
Colon,
),
ty: Type::Path {
qself: None,
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "bool",
span: #0 bytes(10095..10099),
},
arguments: PathArguments::None,
},
],
},
},
},
Comma,
Field {
attrs: [
Attribute {
pound_token: Pound,
style: AttrStyle::Outer,
bracket_token: Bracket,
meta: Meta::Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "no_config",
span: #0 bytes(10107..10116),
},
arguments: PathArguments::None,
},
],
},
},
],
vis: Visibility::Public(
Pub,
),
mutability: FieldMutability::None,
ident: Some(
Ident {
ident: "show_stack_on_pop",
span: #0 bytes(10126..10143),
},
),
colon_token: Some(
Colon,
),
ty: Type::Path {
qself: None,
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "bool",
span: #0 bytes(10145..10149),
},
arguments: PathArguments::None,
},
],
},
},
},
Comma,
Field {
attrs: [
Attribute {
pound_token: Pound,
style: AttrStyle::Outer,
bracket_token: Bracket,
meta: Meta::NameValue {
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "default_value",
span: #0 bytes(10157..10170),
},
arguments: PathArguments::None,
},
],
},
eq_token: Eq,
value: Expr::Lit {
attrs: [],
lit: Lit::Bool {
value: false,
},
},
},
},
],
vis: Visibility::Public(
Pub,
),
mutability: FieldMutability::None,
ident: Some(
Ident {
ident: "show_books_on_bookmark",
span: #0 bytes(10188..10210),
},
),
colon_token: Some(
Colon,
),
ty: Type::Path {
qself: None,
path: Path {
leading_colon: None,
segments: [
PathSegment {
ident: Ident {
ident: "bool",
span: #0 bytes(10212..10216),
},
arguments: PathArguments::None,
},
],
},
},
},
Comma,
],
},
semi_token: None,
},
}