implemented writing default configuration
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use syn::{Attribute, Field, Meta, MetaList, Path, punctuated::Punctuated, token::Comma};
|
||||
use syn::{punctuated::Punctuated, token::Comma, Attribute, Expr, ExprLit, Field, Meta, MetaList, MetaNameValue, Path};
|
||||
use quote::quote;
|
||||
|
||||
pub fn gen_parse_from_string(config_name: &Ident, output_name: &Ident, assignments: &TokenStream) -> TokenStream {
|
||||
@@ -133,7 +133,75 @@ pub fn gen_default(fields: &Punctuated<Field, Comma>) -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_config_assignments(fields: &Punctuated<Field, Comma>, config_map_name: &syn::Ident, output_name: &syn::Ident) -> TokenStream {
|
||||
pub fn gen_to_string(fields: &Punctuated<Field, Comma>) -> TokenStream {
|
||||
let mut statements: TokenStream = TokenStream::new();
|
||||
let mut nested_statements: TokenStream = TokenStream::new();
|
||||
let mut comment: TokenStream = TokenStream::new();
|
||||
'fields: for field in fields.iter() {
|
||||
let attr = &field.attrs;
|
||||
let name = match &field.ident {
|
||||
Some(value) => value,
|
||||
None => continue 'fields,
|
||||
};
|
||||
let name_string = name.to_string();
|
||||
// TODO: continue here
|
||||
for attribute in attr {
|
||||
if let Attribute{ meta: Meta::Path( Path{segments, ..} ), .. } = attribute {
|
||||
// parse nested configs or skip nonconfig elements
|
||||
match segments.first() {
|
||||
Some(attr_name) => {
|
||||
if attr_name.ident == "nested_config" {
|
||||
statements.extend(quote! {
|
||||
string.push_str(&format!("\n[{}]\n", #name_string));
|
||||
string.push_str(&self.#name.to_string_nested(&format!("{}", #name_string)));
|
||||
});
|
||||
nested_statements.extend(quote! {
|
||||
string.push_str(&format!("\n[{}.{}]\n", parents, #name_string));
|
||||
string.push_str(&self.#name.to_string_nested(&format!("{}.{}", parents, #name_string)));
|
||||
});
|
||||
continue 'fields;
|
||||
} else if attr_name.ident == "no_config" {
|
||||
continue 'fields;
|
||||
}
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
} else if let Attribute{ meta: Meta::NameValue( MetaNameValue{path: Path{ segments, .. }, value: Expr::Lit(ExprLit{lit, ..}), ..} ), .. } = attribute {
|
||||
// write comments to string
|
||||
let attr_type = segments.first().unwrap();
|
||||
if attr_type.ident == "doc" {
|
||||
comment = quote!{
|
||||
format!(" #{}", #lit)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
if comment.is_empty() {
|
||||
comment.extend(quote! {""});
|
||||
}
|
||||
let code = quote!{
|
||||
string.push_str(&format!("{} = {}{}\n", #name_string, self.#name.to_string(), #comment));
|
||||
};
|
||||
statements.extend(code.clone());
|
||||
nested_statements.extend(code);
|
||||
}
|
||||
quote! {
|
||||
pub fn to_string(&self) -> String {
|
||||
let mut string = String::new();
|
||||
#statements
|
||||
string
|
||||
}
|
||||
|
||||
/// macro function - do not call
|
||||
pub fn to_string_nested(&self, parents: &String) -> String {
|
||||
let mut string = String::new();
|
||||
#nested_statements
|
||||
string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_config_assignments(fields: &Punctuated<Field, Comma>, config_map_name: &Ident, output_name: &Ident) -> TokenStream {
|
||||
let mut assignments: TokenStream = TokenStream::new();
|
||||
'fields: for field in fields.iter() {
|
||||
let attr = &field.attrs;
|
||||
|
||||
@@ -35,6 +35,7 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
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_default: TokenStream = gen_default(fields);
|
||||
let func_to_string: TokenStream = gen_to_string(fields);
|
||||
|
||||
quote! {
|
||||
impl #name {
|
||||
@@ -42,8 +43,7 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
#func_parse_map
|
||||
#func_to_ansi_sequences
|
||||
#func_default
|
||||
|
||||
// TODO: implement function to parse style settings
|
||||
#func_to_string
|
||||
}
|
||||
}.into()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ function book {
|
||||
__call_navigate "bookmark $@"
|
||||
}
|
||||
|
||||
function nav_config {
|
||||
__call_navigate "configuration $@"
|
||||
}
|
||||
|
||||
# completion function for `book`
|
||||
function _book {
|
||||
CURRENT_WORD=${COMP_WORDS[COMP_CWORD]}
|
||||
|
||||
@@ -30,6 +30,9 @@ pub enum Action {
|
||||
|
||||
/// navigate to bookmark and add current path to the stack
|
||||
bookmark(BookmarkArgs),
|
||||
|
||||
/// display current configuartion (mostly for debugging)
|
||||
configuration(ConfigArgs),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Args)]
|
||||
@@ -117,6 +120,13 @@ pub struct BookmarkSubArgs {
|
||||
pub path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Args)]
|
||||
pub struct ConfigArgs {
|
||||
/// convert styles to ansi escape sequences
|
||||
#[arg(short, long)]
|
||||
pub convert: Option<bool>,
|
||||
}
|
||||
|
||||
/// empty struct for subcommands with no arguments
|
||||
#[derive(Debug, Clone, Args)]
|
||||
pub struct EmptyArgs {}
|
||||
|
||||
+68
-18
@@ -20,68 +20,109 @@ pub struct Config {
|
||||
|
||||
#[derive(Debug, Clone, Default, ConfigParser)]
|
||||
pub struct GeneralSettings {
|
||||
/// (bool) show stack when pushing a path to the stack
|
||||
#[default_value(false)]
|
||||
pub show_stack_on_push: bool,
|
||||
|
||||
/// (bool) show stack when popping a stack entry
|
||||
#[default_value(false)]
|
||||
pub show_stack_on_pop: bool,
|
||||
|
||||
/// (bool) show book marks when adding, removing or changing to a bookmark
|
||||
#[default_value(false)]
|
||||
pub show_books_on_bookmark: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ConfigParser)]
|
||||
pub struct FormatSettings {
|
||||
/// (bool) add padding before the separator if true, after if false
|
||||
#[default_value(true)]
|
||||
pub align_separators: bool,
|
||||
#[default_value(" - ")]
|
||||
pub stack_separator: String,
|
||||
|
||||
/// (bool) replace home directory path with '~' when displaying the stack or bookmarks
|
||||
#[default_value(false)]
|
||||
pub show_home_as_tilde: bool,
|
||||
#[default_value(" - ")]
|
||||
|
||||
/// (string) separator between stack numbers and paths
|
||||
#[default_value("' - '")]
|
||||
pub stack_separator: String,
|
||||
|
||||
/// (string) separator between bookmark names and paths
|
||||
#[default_value("' - '")]
|
||||
pub bookmarks_separator: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, ConfigParser)]
|
||||
pub struct StyleSettings {
|
||||
/// (string) style applied to warnings
|
||||
#[style_config]
|
||||
#[default_value("yellow, italic")]
|
||||
#[default_value("'yellow, italic'")]
|
||||
pub warning_style: String,
|
||||
|
||||
/// (string) style applied to errors
|
||||
#[style_config]
|
||||
#[default_value("red, bold")]
|
||||
#[default_value("'red, bold'")]
|
||||
pub error_style: String,
|
||||
|
||||
/// (string) style applied to numbers when displaying the stack
|
||||
#[style_config]
|
||||
#[default_value("default")]
|
||||
#[default_value("'default'")]
|
||||
pub stack_number_style: String,
|
||||
|
||||
/// (string) style applied to separators when displaying the stack
|
||||
#[style_config]
|
||||
#[default_value("cyan")]
|
||||
#[default_value("'cyan'")]
|
||||
pub stack_separator_style: String,
|
||||
|
||||
/// (string) style applied to paths when displaying the stack
|
||||
#[style_config]
|
||||
#[default_value("default")]
|
||||
#[default_value("'default'")]
|
||||
pub stack_path_style: String,
|
||||
|
||||
/// (string) style applied to punctuation (i.e. '/') when displaying the stack
|
||||
#[style_config]
|
||||
#[default_value("magenta")]
|
||||
#[default_value("'magenta'")]
|
||||
pub stack_punct_style: String,
|
||||
|
||||
/// (string) style applied to bookmark names when displaying the bookmarks
|
||||
#[style_config]
|
||||
#[default_value("default")]
|
||||
#[default_value("'default'")]
|
||||
pub bookmarks_name_style: String,
|
||||
|
||||
/// (string) style applied to separators when displaying the bookmarks
|
||||
#[style_config]
|
||||
#[default_value("cyan")]
|
||||
#[default_value("'cyan'")]
|
||||
pub bookmarks_seperator_style: String,
|
||||
|
||||
/// (string) style applied to paths when displaying the bookmarks
|
||||
#[style_config]
|
||||
#[default_value("default")]
|
||||
#[default_value("'default'")]
|
||||
pub bookmarks_path_style: String,
|
||||
|
||||
/// (string) style applied to punctuation (i.e. '/') when displaying the bookmarks
|
||||
#[style_config]
|
||||
#[default_value("magenta")]
|
||||
#[default_value("'magenta'")]
|
||||
pub bookmarks_punct_style: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
const CONFIG_DIRECTORY_NAME: &str = "navigate";
|
||||
const CONFIG_FILE_NAME: &str = "navigate.toml";
|
||||
const DEFAULT_CONFIG_NAME: &str = "default.toml";
|
||||
const DEFAULT_FILE_HEADER: &str = "
|
||||
# default configuration file for `navigate`
|
||||
#
|
||||
# value type should be in the comment
|
||||
# string values have to be quoted, both single and double quotes work
|
||||
# integer and boolean values do not need quotes
|
||||
# boolean values are either `true` or `false`
|
||||
";
|
||||
|
||||
/// generates and populates a new instance of Config
|
||||
pub fn new(styles_as_ansi_sequences: bool) -> Result<Self> {
|
||||
let mut config: Config = Self::default();
|
||||
// get configuration directory
|
||||
let mut conf_file = match config_dir() {
|
||||
let mut config_file = match config_dir() {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
return Err(Error::other(
|
||||
@@ -89,12 +130,21 @@ impl Config {
|
||||
))
|
||||
}
|
||||
};
|
||||
// expand path to configuration file
|
||||
conf_file.push(format!("navigate/{}", Self::CONFIG_FILE_NAME));
|
||||
// expand path to configuration file and default configuration file
|
||||
let mut default_file = config_file.clone();
|
||||
default_file.push(format!("{}/{}", Self::CONFIG_DIRECTORY_NAME, Self::DEFAULT_CONFIG_NAME));
|
||||
config_file.push(format!("{}/{}", Self::CONFIG_DIRECTORY_NAME, Self::CONFIG_FILE_NAME));
|
||||
|
||||
// write default configuration file if it does not exist
|
||||
if !default_file.is_file() {
|
||||
let mut default_string = Self::DEFAULT_FILE_HEADER.to_string();
|
||||
default_string.push_str(&config.to_string());
|
||||
_ = fs::write(default_file, default_string);
|
||||
}
|
||||
|
||||
// parse configuration file and populate config struct
|
||||
if conf_file.is_file() {
|
||||
let config_str = match fs::read_to_string(&conf_file) {
|
||||
if config_file.is_file() {
|
||||
let config_str = match fs::read_to_string(&config_file) {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
+21
-7
@@ -28,14 +28,24 @@ fn main() -> Result<()> {
|
||||
Err(error) => {
|
||||
// config object is not ready at this point so the style
|
||||
// has to be created by hand
|
||||
print!("echo '{}{}{}' && false", generate_style_sequence(None, Some(COLORS.fg.red), None), error, RESET_SEQ);
|
||||
print!("echo -e '{}{}{}' && false", generate_style_sequence(None, Some(COLORS.fg.red), None), error, RESET_SEQ);
|
||||
return Ok(())
|
||||
}
|
||||
};
|
||||
let args = match Arguments::try_parse() {
|
||||
Ok(a) => a,
|
||||
Err(error) => {
|
||||
match error.kind() {
|
||||
clap::error::ErrorKind::DisplayHelp | clap::error::ErrorKind::DisplayVersion => {
|
||||
output.push_info(&error.to_string());
|
||||
},
|
||||
clap::error::ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand => {
|
||||
output.push_warning(&error.to_string());
|
||||
},
|
||||
_ => {
|
||||
output.push_error(&error.to_string());
|
||||
},
|
||||
}
|
||||
output.print_output(&config);
|
||||
return Ok(());
|
||||
}
|
||||
@@ -60,6 +70,7 @@ fn main() -> Result<()> {
|
||||
Action::pop(pop_args) => handle_pop(&pop_args, &config, &mut stack, &mut output),
|
||||
Action::stack(stack_args) => handle_stack(&stack_args, &config, &mut stack, &mut output),
|
||||
Action::bookmark(bookmark_args) => handle_bookmark(&bookmark_args, &config, &mut bookmarks, &mut stack, &mut output),
|
||||
Action::configuration(config_args) => handle_config(&config_args, &mut output),
|
||||
};
|
||||
|
||||
if res.is_err() {
|
||||
@@ -156,12 +167,15 @@ fn handle_bookmark(args: &BookmarkArgs, config: &Config, bookmarks: &mut Bookmar
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn handle_config(args: &ConfigArgs, config: &Config) -> Result<()> {
|
||||
// match args {
|
||||
// ConfigAction::show => println!("echo '{}'", config.to_formatted_string()),
|
||||
// }
|
||||
// Ok(())
|
||||
// }
|
||||
fn handle_config(args: &ConfigArgs, output: &mut Output) -> Result<()> {
|
||||
let convert: bool = match args.convert {
|
||||
Some(value) => value,
|
||||
None => false,
|
||||
};
|
||||
let config = Config::new(convert);
|
||||
output.push_info(&format!("config = {:#?}", config));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn list_bookmarks(config: &Config, bookmarks: &mut Bookmarks, output: &mut Output) -> Result<()> {
|
||||
output.push_info(&bookmarks.to_formatted_string(config)?);
|
||||
|
||||
Reference in New Issue
Block a user