diff --git a/Cargo.toml b/Cargo.toml index 18d6b48..78154c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,4 @@ dirs = "5.0.1" serde = { version = "1.0.216", features = [ "std", "derive" ] } sysinfo = "0.32.0" toml = "0.8.19" -config_parser = { path = "config_parser" } +config-parser = { path = "config-parser" } diff --git a/config-parser/Cargo.toml b/config-parser/Cargo.toml new file mode 100644 index 0000000..cef132b --- /dev/null +++ b/config-parser/Cargo.toml @@ -0,0 +1,17 @@ +[workspace] +members = [ + "config-parser-common", + "config-parser-macro", +] + +[package] +name = "config-parser" +version = "0.1.0" +edition = "2021" + +[lib] + +[dependencies] +config-parser-macro = { path = "config-parser-macro" } +config-parser-common = { path = "config-parser-common" } + diff --git a/config_parser/Cargo.toml b/config-parser/config-parser-common/Cargo.toml similarity index 69% rename from config_parser/Cargo.toml rename to config-parser/config-parser-common/Cargo.toml index 5eefc16..5140110 100644 --- a/config_parser/Cargo.toml +++ b/config-parser/config-parser-common/Cargo.toml @@ -1,16 +1,11 @@ [package] -name = "config_parser" +name = "config-parser-common" version = "0.1.0" -autotests = false edition = "2021" -publish = false [lib] -proc-macro = true [dependencies] proc-macro2 = "1.0.92" quote = "1.0.38" syn = { version = "2.0.94", features = ["full", "extra-traits"] } - - diff --git a/config_parser/src/common.rs b/config-parser/config-parser-common/src/common.rs similarity index 100% rename from config_parser/src/common.rs rename to config-parser/config-parser-common/src/common.rs diff --git a/src/format.rs b/config-parser/config-parser-common/src/format.rs similarity index 66% rename from src/format.rs rename to config-parser/config-parser-common/src/format.rs index dfa9c1e..f401820 100644 --- a/src/format.rs +++ b/config-parser/config-parser-common/src/format.rs @@ -2,11 +2,11 @@ use std::io::{Result, Error}; -pub const ESC: &str = "\x1B"; -pub const PREFIX: &str = "\x1B["; +pub const ESC: &str = "\x1b"; +pub const PREFIX: &str = "\x1b["; pub const RESET_ARG: &str = "0"; pub const TERMINATION: &str = "m"; -pub const RESET_SEQ: &str = "\x1B[0m"; +pub const RESET_SEQ: &str = "\x1b[0m"; pub const FG: ColorContext = ColorContext::Foreground; pub const BG: ColorContext = ColorContext::Background; @@ -60,14 +60,12 @@ pub const COLORS: Colors = Colors { }, }; -#[allow(dead_code)] #[derive(Debug, Clone)] pub struct Styles { pub set: StyleCodes, pub reset: StyleCodes, } -#[allow(dead_code)] #[derive(Debug, Clone)] pub struct StyleCodes { pub bold: &'static str, @@ -80,14 +78,12 @@ pub struct StyleCodes { pub strikethrough: &'static str, } -#[allow(dead_code)] #[derive(Debug, Clone)] pub struct Colors { pub fg: ColorCodes, pub bg: ColorCodes, } -#[allow(dead_code)] #[derive(Debug, Clone)] pub struct ColorCodes { pub black: &'static str, @@ -102,7 +98,6 @@ pub struct ColorCodes { pub default: &'static str, } -#[allow(dead_code)] #[derive(Debug, Clone)] pub enum ColorContext { Foreground, @@ -118,7 +113,7 @@ pub fn apply_format(input: &str, style: &str) -> String { /// `\x1B[;;m` /// all elements are optional, if none is supplied the function returns an error pub fn generate_style_sequence( - style: Option>, + style: Option<&str>, foreground: Option<&str>, background: Option<&str>, ) -> String { @@ -128,9 +123,7 @@ pub fn generate_style_sequence( let mut sequence = PREFIX.to_owned(); let mut arguments = Vec::::new(); if let Some(item) = style { - for entry in item { - arguments.push(entry.to_owned()); - } + arguments.push(item.to_owned()); } if let Some(item) = foreground { arguments.push(item.to_owned()); @@ -140,7 +133,6 @@ pub fn generate_style_sequence( } // panic if no arguments provided since this is a programming mistake - // which should not if arguments.is_empty() { panic!("no arguments provided to 'generate_style_sequence()'"); } @@ -152,6 +144,9 @@ pub fn generate_style_sequence( /// generates a 256 color sequence /// see `generate_rgb_sequence(..)` for details pub fn generate_256color_sequence(context: ColorContext, color: u8) -> String { + if color < 16 { + return "".to_owned(); + } let mut sequence = PREFIX.to_owned(); // choose context match context { @@ -160,7 +155,7 @@ pub fn generate_256color_sequence(context: ColorContext, color: u8) -> String { }; // make it a rgb sequence sequence.push_str(";5;"); - sequence.push_str(&format!("{color}m")); + sequence.push_str(&format!("{color}{TERMINATION}")); sequence } @@ -191,41 +186,73 @@ pub fn make_padding_string(len: usize) -> String { } /// convert color setting to ansi escape sequence -pub fn parse_style(string: String) -> Result { - // check for numbered color - if let Ok(sequence) = parse_numbered_color(&string) { - return Ok(sequence); +/// input format is a quoted string (either double or single) +/// the style can be a combination of **one** color and +/// one or more style options (bold, italic, underlined, strikethrough) +pub fn parse_style(arg: String) -> Result { + let mut colors: Vec = Vec::::new(); + let mut styles: Vec = Vec::::new(); + + // separate style options + let mut tokens: Vec = arg.split([' ', ',', '\"', '\'']).map(|entry| entry.trim().to_lowercase()).collect(); + tokens.retain(|entry| !entry.is_empty()); + + // parse options + for option in tokens { + // parse numbered colors + if let Ok(sequence) = parse_numbered_color(&option) { + colors.push(sequence); + continue; + } + + // parse rgb colors + if let Ok(sequence) = parse_rgb_color(&option) { + colors.push(sequence); + continue; + } + + // parse styles and named colors + match option.as_str() { + // styles + "bold" => styles.push(generate_style_sequence(Some(STYLES.set.bold), 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)), + "underlined" => styles.push(generate_style_sequence(Some(STYLES.set.underline), None, None)), + "blink" => styles.push(generate_style_sequence(Some(STYLES.set.blink), None, None)), + "reverse" => styles.push(generate_style_sequence(Some(STYLES.set.reverse), 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)), + // named colors + "black" => colors.push(generate_style_sequence(None, Some(COLORS.fg.black), None)), + "red" => colors.push(generate_style_sequence(None, Some(COLORS.fg.red), None)), + "green" => colors.push(generate_style_sequence(None, Some(COLORS.fg.green), None)), + "yellow" => colors.push(generate_style_sequence(None, Some(COLORS.fg.yellow), None)), + "blue" => colors.push(generate_style_sequence(None, Some(COLORS.fg.blue), None)), + "magenta" => colors.push(generate_style_sequence(None, Some(COLORS.fg.magenta), None)), + "cyan" => colors.push(generate_style_sequence(None, Some(COLORS.fg.cyan), None)), + "white" => colors.push(generate_style_sequence(None, Some(COLORS.fg.white), None)), + "default" => colors.push(generate_style_sequence(None, Some(COLORS.fg.default), None)), + _ => return Err(Error::other(format!("-- could not parse style token `{}` in config file", option))), + }; + + }; + + if colors.len() > 1 { + return Err(Error::other(format!("-- too many colors found in setting <{}>", arg))); } - // check for rgb color - if let Ok(sequence) = parse_rgb_color(&string) { - return Ok(sequence); - } - // check for named color - match string.to_ascii_lowercase().as_str() { - "black" => Ok(generate_style_sequence(None, Some(COLORS.fg.black), None)), - "red" => Ok(generate_style_sequence(None, Some(COLORS.fg.red), None)), - "green" => Ok(generate_style_sequence(None, Some(COLORS.fg.green), None)), - "yellow" => Ok(generate_style_sequence(None, Some(COLORS.fg.yellow), None)), - "blue" => Ok(generate_style_sequence(None, Some(COLORS.fg.blue), None)), - "magenta" => Ok(generate_style_sequence(None, Some(COLORS.fg.magenta), None)), - "cyan" => Ok(generate_style_sequence(None, Some(COLORS.fg.cyan), None)), - "white" => Ok(generate_style_sequence(None, Some(COLORS.fg.white), None)), - "default" => Ok(generate_style_sequence(None, Some(COLORS.fg.default), None)), - _ => Err(Error::other(format!( - "-- could not parse color `{}` in config file", - string - ))), + if !colors.is_empty() { + styles.push(colors.pop().unwrap()); } + Ok(styles.join("")) } fn parse_numbered_color(string: &String) -> Result { // check for numbered color if let Ok(number) = string.parse::() { - if number >= 16 { return Ok(generate_256color_sequence( ColorContext::Foreground, number, - ));} + )); } Err(Error::other(format!("no numbered color found in '{}'", string))) } @@ -233,7 +260,6 @@ fn parse_numbered_color(string: &String) -> Result { fn parse_rgb_color(string: &String) -> Result { // check for rgb color if string.as_bytes()[0] == b'#' && string.len() == 7 { - // match u8::from_str_radix(&color, 16) { let red = match u8::from_str_radix(&string[1..=2], 16) { Ok(value) => value, Err(_) => { diff --git a/config-parser/config-parser-common/src/lib.rs b/config-parser/config-parser-common/src/lib.rs new file mode 100644 index 0000000..896ad65 --- /dev/null +++ b/config-parser/config-parser-common/src/lib.rs @@ -0,0 +1,3 @@ + +pub mod common; +pub mod format; diff --git a/config-parser/config-parser-macro/Cargo.toml b/config-parser/config-parser-macro/Cargo.toml new file mode 100644 index 0000000..3a61577 --- /dev/null +++ b/config-parser/config-parser-macro/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "config-parser-macro" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.92" +quote = "1.0.38" +syn = { version = "2.0.94", features = ["full", "extra-traits"] } +config-parser-common = { path = "../config-parser-common/" } diff --git a/config_parser/src/lib.rs b/config-parser/config-parser-macro/src/lib.rs similarity index 95% rename from config_parser/src/lib.rs rename to config-parser/config-parser-macro/src/lib.rs index e530983..d3ccaf5 100644 --- a/config_parser/src/lib.rs +++ b/config-parser/config-parser-macro/src/lib.rs @@ -1,11 +1,8 @@ -use common::gen_config_load_function; +use config_parser_common::common::gen_config_load_function; use proc_macro2::TokenStream; use syn::{parse_macro_input, DeriveInput}; use quote::quote; -#[macro_use] -mod common; - /// **for structs only** /// - implements `parse_config(&mut self, input: &String) -> Result<()>` /// which parses a string and fills the fills recognised values into the struct @@ -26,8 +23,10 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { Err(_) => panic!("loading config failed"), }; - //let string = format!("{:#?}", ast); - //_ = std::fs::write("test.txt", string); + if name.to_string() == "Settings" { + let string = format!("{:#?}", ast); + _ = std::fs::write("test.txt", string); + } let expanded_stream: TokenStream = quote! { impl #name { @@ -97,6 +96,5 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } }.into(); expanded_stream.into() - //TokenStream::new() } diff --git a/config-parser/src/lib.rs b/config-parser/src/lib.rs new file mode 100644 index 0000000..bfb70ff --- /dev/null +++ b/config-parser/src/lib.rs @@ -0,0 +1,3 @@ + +pub use config_parser_common::format; +pub use config_parser_macro::ConfigParser; diff --git a/src/bookmarks.rs b/src/bookmarks.rs index 120c7de..eba1f1d 100644 --- a/src/bookmarks.rs +++ b/src/bookmarks.rs @@ -9,7 +9,7 @@ use std::io::{Error, Result}; use std::path::PathBuf; use std::str::FromStr; -use crate::make_padding_string; +use config_parser::format::make_padding_string; use super::{apply_format, config::*}; diff --git a/src/config.rs b/src/config.rs index c0daa0e..de40eec 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,12 +3,12 @@ //! handle the config file and bookmarks stored //! in said config file -use crate::format::*; use dirs::config_dir; use std::fs; use std::io::{Error, Result}; use std::path::PathBuf; use config_parser::ConfigParser; +use config_parser::format::*; #[derive(Debug, Clone)] pub struct Config { @@ -42,11 +42,17 @@ pub struct FormatSettings { #[derive(Debug, Clone, Default, ConfigParser)] pub struct StyleSettings { + #[color_config] pub stack_number: String, + #[color_config] pub stack_separator: String, + #[color_config] pub stack_path: String, + #[color_config] pub bookmarks_name: String, + #[color_config] pub bookmarks_seperator: String, + #[color_config] pub bookmarks_path: String, } diff --git a/src/main.rs b/src/main.rs index 0dfc71e..048400f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,4 @@ mod arguments; -mod format; mod config; mod bookmarks; mod stack; @@ -9,7 +8,7 @@ use arguments::*; use clap::Parser; use config::*; use bookmarks::*; -use format::*; +use config_parser::format::*; use stack::Stack; use std::env::{current_dir, var}; use std::io::{Error, Result}; @@ -18,7 +17,7 @@ use std::str::FromStr; fn main() -> Result<()> { let style_error = - generate_style_sequence(Some(vec![STYLES.set.bold]), Some(COLORS.fg.red), None); + generate_style_sequence(Some(STYLES.set.bold), Some(COLORS.fg.red), None); let args = match Arguments::try_parse() { Ok(a) => a, Err(e) => {