use serde::Deserialize;
use tailspin::config::*;
pub mod reader;
#[derive(Deserialize, Debug, Default)]
#[serde(default, deny_unknown_fields)]
pub struct Theme {
pub keywords: Vec<KeywordConfig>,
pub regexes: Vec<RegexConfig>,
pub numbers: NumberConfig,
pub uuids: UuidConfig,
pub quotes: QuoteConfig,
pub ipv4: IpV4Config,
pub ipv6: IpV6Config,
pub dates: DateTimeConfig,
pub durations: DurationConfig,
pub paths: UnixPathConfig,
pub urls: UrlConfig,
pub emails: EmailConfig,
pub pointers: PointerConfig,
pub processes: UnixProcessConfig,
pub key_value_pairs: KeyValueConfig,
pub json: JsonConfig,
pub jvm_stack_traces: JvmStackTraceConfig,
}
#[cfg(test)]
mod tests {
use super::*;
use tailspin::style::{Color, Style};
fn parse(input: &str) -> Theme {
toml::from_str::<Theme>(input).unwrap()
}
#[test]
fn empty_input_yields_defaults() {
let theme = parse("");
assert!(theme.keywords.is_empty());
assert!(theme.regexes.is_empty());
assert_eq!(theme.uuids.letter, UuidConfig::default().letter);
assert_eq!(theme.quotes.quote_token, b'"');
}
#[test]
fn partial_table_keeps_defaults_for_missing_fields() {
let theme = parse(
r#"[uuids]
number = { fg = "red" }"#,
);
assert_eq!(theme.uuids.number, Style::new().fg(Color::Red));
assert_eq!(theme.uuids.letter, UuidConfig::default().letter);
assert_eq!(theme.uuids.separator, UuidConfig::default().separator);
}
#[test]
fn unknown_keys_are_rejected() {
assert!(toml::from_str::<Theme>("bogus = 1").is_err());
assert!(toml::from_str::<Theme>("[uuids]\nbogus = { fg = \"red\" }").is_err());
assert!(toml::from_str::<Theme>("[uuids]\nnumber = { fg = \"red\", itallic = true }").is_err());
assert!(toml::from_str::<Theme>("[numbers]\nnumber = { fg = \"red\" }").is_err());
}
#[test]
fn ipv4_and_ipv6_tables_parse_independently() {
let theme = parse(
r#"[ipv4]
separator = { fg = "yellow" }
[ipv6]
letter = { fg = "green" }"#,
);
assert_eq!(theme.ipv4.separator, Style::new().fg(Color::Yellow));
assert_eq!(theme.ipv4.number, IpV4Config::default().number);
assert_eq!(theme.ipv6.letter, Style::new().fg(Color::Green));
assert_eq!(theme.ipv6.separator, IpV6Config::default().separator);
}
#[test]
fn the_removed_ip_addresses_table_is_rejected() {
let error = toml::from_str::<Theme>("[ip_addresses]\nseparator = { fg = \"red\" }").unwrap_err();
assert!(error.to_string().contains("ip_addresses"));
}
#[test]
fn numbers_table_uses_the_style_key() {
let theme = parse(
r#"[numbers]
style = { fg = "green" }"#,
);
assert_eq!(theme.numbers.style, Style::new().fg(Color::Green));
}
#[test]
fn keywords_and_regexes_parse_into_config_lists() {
let theme = parse(
r#"[[keywords]]
words = ["foo"]
style = { bold = true }
[[regexes]]
regex = "x+"
style = { fg = "blue" }"#,
);
assert_eq!(
theme.keywords,
vec![KeywordConfig {
words: vec!["foo".to_string()],
style: Style::new().bold(),
}]
);
assert_eq!(theme.regexes[0].regex, "x+");
}
#[test]
fn ascii_quote_token_is_accepted() {
let theme = parse(
r#"[quotes]
quote_token = "'""#,
);
assert_eq!(theme.quotes.quote_token, b'\'');
assert_eq!(theme.quotes.style, QuoteConfig::default().style);
}
#[test]
fn non_ascii_quote_token_is_rejected() {
let error = toml::from_str::<Theme>(
r#"[quotes]
quote_token = "«""#,
)
.unwrap_err();
assert!(error.to_string().contains("ASCII"));
}
}