feat(theme): themes as files (theme crate: toml subset + ints, contrast check, wire); whimsy dark + light; display reads themes/, serves THEME/THEME_NAME, init SET_THEME -> THEME_CHANGED to all windows, bar themed; k-ui follows; settings appearance; init keeps choice in sealed users/<id>/settings/, reapplies at sign-in + display restart
This commit is contained in:
@@ -9,7 +9,7 @@ mod capability;
|
||||
mod decision;
|
||||
mod fields;
|
||||
mod manifest;
|
||||
mod toml;
|
||||
pub mod toml;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -52,7 +52,7 @@ fn set<T>(slot: &mut Option<T>, value: Option<T>, line: usize) -> Result<(), Err
|
||||
fn text<'a>(value: Value<'a>) -> Option<&'a str> {
|
||||
match value {
|
||||
Value::Str(s) => Some(s),
|
||||
Value::List(_) => None,
|
||||
Value::List(_) | Value::Int(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +167,8 @@ fn only_the_subset_parses() {
|
||||
"id = kos.snake", // bare value
|
||||
"id \"kos.snake\"", // no =
|
||||
"[app", // unclosed table
|
||||
"id = 12x", // not a whole number
|
||||
"id = 1.5", // no fractions
|
||||
] {
|
||||
assert!(
|
||||
matches!(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//! The strict TOML subset manifests and decisions are written in:
|
||||
//! `[table]` headers, `key = "string"`, `key = ["a", "b"]` on one line,
|
||||
//! `#` comments. Strings are printable ASCII without `"` or `\`.
|
||||
//! `key = 42` (a whole number), `#` comments. Strings are printable ASCII
|
||||
//! without `"` or `\`.
|
||||
|
||||
use crate::Error;
|
||||
|
||||
@@ -18,6 +19,8 @@ pub enum Value<'a> {
|
||||
Str(&'a str),
|
||||
/// A one-line array of strings, already checked.
|
||||
List(List<'a>),
|
||||
/// Digits only: no sign, no fraction.
|
||||
Int(u32),
|
||||
}
|
||||
|
||||
/// The inside of `[...]`: iterate it for its strings.
|
||||
@@ -119,6 +122,10 @@ fn string(s: &str, line: usize) -> Result<&str, Error> {
|
||||
}
|
||||
|
||||
fn value_of(s: &str, line: usize) -> Result<Value<'_>, Error> {
|
||||
if s.bytes().next().is_some_and(|b| b.is_ascii_digit()) {
|
||||
let digits = s.bytes().all(|b| b.is_ascii_digit());
|
||||
return digits.then(|| s.parse().ok()).flatten().map(Value::Int).ok_or(Error::Syntax { line });
|
||||
}
|
||||
let Some(inner) = s.strip_prefix('[') else {
|
||||
return string(s, line).map(Value::Str);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user