did a little clean up in config_parser

This commit is contained in:
2025-01-09 23:29:42 +01:00
parent 1d4688cf95
commit 57dbafac3d
3 changed files with 44 additions and 76 deletions
+11 -36
View File
@@ -1,7 +1,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::{quote, TokenStreamExt}; use quote::quote;
use syn::{Attribute, Error, Field, Meta, Path, punctuated::Punctuated, token::Comma}; use syn::{Attribute, Error, Field, Meta, Path, punctuated::Punctuated, token::Comma};
@@ -21,9 +21,11 @@ pub fn gen_config_load_function(fields: &Punctuated<Field, Comma>, config_map_na
match attr_name.first() { match attr_name.first() {
Some(value) => if value.ident == "nested_config" { Some(value) => if value.ident == "nested_config" {
assignments.extend(quote! { assignments.extend(quote! {
self.#name.parse_from_map(&#config_map_name); self.#name.parse_from_map(&mut #config_map_name);
}); });
continue 'field_loop; continue 'field_loop;
} else if value.ident == "no_config" {
continue 'field_loop;
}, },
None => (), None => (),
} }
@@ -32,8 +34,13 @@ pub fn gen_config_load_function(fields: &Punctuated<Field, Comma>, config_map_na
assignments.extend(quote! { assignments.extend(quote! {
self.#name = match #config_map_name.get(#name_string) { self.#name = match #config_map_name.get(#name_string) {
Some(value) => match value.parse::<#ty>() { Some(value) => match value.parse::<#ty>() {
Ok(parsed) => parsed, Ok(parsed) => {
Err(_) => self.#name.clone(), _ = #config_map_name.remove(#name_string);
parsed
},
Err(_) => {
self.#name.clone()
},
}, },
None => self.#name.clone(), None => self.#name.clone(),
}; };
@@ -42,35 +49,3 @@ pub fn gen_config_load_function(fields: &Punctuated<Field, Comma>, config_map_na
Ok(assignments.into()) Ok(assignments.into())
} }
//pub fn parse_config_file(input: &String) -> std::io::Result<std::collections::HashMap<String, String>> {
// let mut config = std::collections::HashMap::<String, String>::new();
// let lines = input.lines();
//
// for line in lines {
// let line = line.trim();
// // ignore empty lines
// if line.is_empty() { continue; }
//
// if line.starts_with("[") {
// // check for table
// if !line.ends_with("]") {
// // TODO: implement error handling
// } else if line.contains(' ') {
// // TODO: implement error handling
// }
// //let tokens = line.split('.');
// // TODO: implement hirarchical map
// } else {
// // check for config
// let mut tokens: Vec<&str> = line.split('=').map(|entry| entry.trim()).collect();
// tokens.retain(|entry| !entry.is_empty());
// if tokens.len() != 2 {
// // println!("error in line'", line);
// continue;
// }
// config.insert(tokens[0].to_string(), tokens[1].to_string());
// }
// }
// Ok(config)
//}
//
+14 -9
View File
@@ -1,7 +1,7 @@
use common::gen_config_load_function; use common::gen_config_load_function;
use proc_macro2::{TokenStream}; // TODO: change to proc_macro2, to hopefully fix #assignments use proc_macro2::TokenStream;
use syn::{parse_macro_input, spanned::Spanned, DeriveInput, Ident}; use syn::{parse_macro_input, DeriveInput};
use quote::{quote}; use quote::quote;
#[macro_use] #[macro_use]
mod common; mod common;
@@ -11,7 +11,7 @@ mod common;
/// which parses a string and fills the fills recognised values into the struct /// which parses a string and fills the fills recognised values into the struct
/// - implements `write_default_config() -> Result<String>` /// - implements `write_default_config() -> Result<String>`
/// which write a default configuration, in case the documentation is lacking /// which write a default configuration, in case the documentation is lacking
#[proc_macro_derive(ConfigParser, attributes(nested_config))] #[proc_macro_derive(ConfigParser, attributes(color_config, nested_config, no_config))]
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(input as DeriveInput); let ast = parse_macro_input!(input as DeriveInput);
let name = &ast.ident; let name = &ast.ident;
@@ -19,7 +19,7 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let fields = if let syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Named(syn::FieldsNamed{ ref named, .. }), .. }) = ast.data { let fields = if let syn::Data::Struct(syn::DataStruct{ fields: syn::Fields::Named(syn::FieldsNamed{ ref named, .. }), .. }) = ast.data {
named named
} else { } else {
todo!("use `syn::Error` to return comprehensive error message"); panic!("the macro `ConfigParser` applies only to structs!");
}; };
let assignments = match gen_config_load_function(fields, &config_name) { let assignments = match gen_config_load_function(fields, &config_name) {
Ok(value) => value, Ok(value) => value,
@@ -29,21 +29,26 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
//let string = format!("{:#?}", ast); //let string = format!("{:#?}", ast);
//_ = std::fs::write("test.txt", string); //_ = std::fs::write("test.txt", string);
let expanded_stream: TokenStream = quote::quote! { let expanded_stream: TokenStream = quote! {
impl #name { impl #name {
/// tries to parse config from a string
pub fn parse_from_string(&mut self, input: &String) -> std::io::Result<()> { pub fn parse_from_string(&mut self, input: &String) -> std::io::Result<()> {
let #config_name : std::collections::HashMap<String, String> = Self::parse_config_file(input)?; let mut #config_name : std::collections::HashMap<String, String> = Self::parse_config_file(input)?;
#assignments #assignments
if !#config_name.is_empty() {
let leftovers = #config_name.keys().cloned().collect::<Vec<String>>();
return Err(std::io::Error::other(format!("the following settings were not recognised: {:#?}", leftovers)));
}
Ok(()) Ok(())
} }
/// **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: &std::collections::HashMap<String, String>) -> std::io::Result<()> { pub fn parse_from_map(&mut self, input: &mut std::collections::HashMap<String, String>) -> std::io::Result<()> {
let #config_name = input; let mut #config_name = input;
#assignments #assignments
+19 -31
View File
@@ -8,7 +8,7 @@ use dirs::config_dir;
use std::fs; use std::fs;
use std::io::{Error, Result}; use std::io::{Error, Result};
use std::path::PathBuf; use std::path::PathBuf;
use derive_config_parser::ConfigParser; use config_parser::ConfigParser;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Config { pub struct Config {
@@ -16,21 +16,24 @@ pub struct Config {
pub settings: Settings, pub settings: Settings,
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default, ConfigParser)]
pub struct Settings { pub struct Settings {
#[nested_config]
pub general: GeneralSettings, pub general: GeneralSettings,
#[nested_config]
pub format: FormatSettings, pub format: FormatSettings,
#[nested_config]
pub styles: StyleSettings, pub styles: StyleSettings,
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default, ConfigParser)]
pub struct GeneralSettings { pub struct GeneralSettings {
pub show_stack_on_push: bool, pub show_stack_on_push: bool,
pub show_stack_on_pop: bool, pub show_stack_on_pop: bool,
pub show_stack_on_bookmark: bool, pub show_stack_on_bookmark: bool,
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default, ConfigParser)]
pub struct FormatSettings { pub struct FormatSettings {
pub stack_separator: String, pub stack_separator: String,
pub bookmarks_separator: String, pub bookmarks_separator: String,
@@ -90,12 +93,19 @@ impl Config {
.push(format!("navigate/{}", Self::CONFIG_FILE_NAME)); .push(format!("navigate/{}", Self::CONFIG_FILE_NAME));
// parse configuration file and populate config struct // parse configuration file and populate config struct
let file_error = config.build_settings(); if config.conf_file.is_file() {
config.set_default_settings()?; let config_str = match fs::read_to_string(&config.conf_file) {
if file_error.is_err() { Ok(value) => value,
config.write_config_file()?; Err(error) => return Err(error),
};
_ = config.settings.parse_from_string(&config_str);
} else {
// TODO: write default configuration
} }
config.parse_color_settings()?;
// TODO: ALSDKJFJFJASDkk
//config.set_default_settings()?;
//config.parse_color_settings()?;
Ok(config) Ok(config)
} }
@@ -107,19 +117,6 @@ impl Config {
/// reads and parses the configuration file /// reads and parses the configuration file
fn build_settings(&mut self) -> Result<()> { fn build_settings(&mut self) -> Result<()> {
if !self.conf_file.is_file() {
return Err(Error::other(
"-- config file `navigation.conf` does not exist",
));
}
let config_str = match fs::read_to_string(&self.conf_file) {
Ok(value) => value,
Err(error) => return Err(error),
};
self.settings = match toml::from_str(&config_str) {
Ok(value) => value,
Err(error) => return Err(Error::other(error.to_string())),
};
Ok(()) Ok(())
} }
@@ -159,15 +156,6 @@ impl Config {
Ok(()) Ok(())
} }
/// write configuration file to save changed settings
pub fn write_config_file(&self) -> Result<()> {
let conf_str = match toml::to_string(&self.settings) {
Ok(value) => value,
Err(error) => return Err(Error::other(error.to_string())),
};
fs::write(self.conf_file.clone(), conf_str)
}
/// convert color settings to ansi escape sequences /// convert color settings to ansi escape sequences
pub fn parse_color_settings(&mut self) -> Result<()> { pub fn parse_color_settings(&mut self) -> Result<()> {
self.settings.styles.stack_number = parse_style(self.settings.styles.stack_number.clone())?; self.settings.styles.stack_number = parse_style(self.settings.styles.stack_number.clone())?;