Files
Marcos Paulo bb7f8ae79d
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: Linux/Windows feedback, round 3 (trash, composer UI, search sort, reading mode, indent, table helpers, user themes)
Explorer: foldable calendar, hand-laid toolbar, no empty Bookmarks block, Move to... picker, folder notes,
Trash tab. Menu bar as flat text, title bar drawn whole each frame. New Outline pane, scrolling Related tab,
performance overlay (fps, frame time, memory, CPU), first-run UI scale from the desktop on Linux.
Editor: Extract to a new note, Merge into..., reading mode, indent settings, table row/column controls,
tags in notes searchable, search order and collapse, excluded search folders, user themes in the settings
folder. Engine: note.extract, note.merge, trash.list/restore/empty.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 14:17:25 -03:00

52 lines
2.5 KiB
Rust

//! Themes the user puts in `<settings folder>/themes/*.toml`.
mod common;
use common::{temp_config, temp_vault};
use notescraft_engine::{Registry, Session, register_core};
use serde_json::json;
const GOOD: &str = "id = \"midnight\"\nname = \"Midnight\"\nvariant = \"dark\"\n\n[colors]\naccent = \"#ff8800\"\n";
fn session(name: &str, files: &[(&str, &str)]) -> (Session, common::TempVault, common::TempVault) {
let vault = temp_vault(name);
let config = temp_config(name);
std::fs::create_dir_all(config.path().join("themes")).expect("themes folder");
for (file, text) in files {
std::fs::write(config.path().join("themes").join(file), text).expect("theme file");
}
let mut session = Session::open(vault.path()).expect("open");
session.use_settings_dir(config.path());
(session, vault, config)
}
#[test]
fn a_theme_file_is_listed_resolved_and_pickable() {
let (mut session, _vault, _config) = session("user-theme", &[("midnight.toml", GOOD)]);
assert!(session.themes().iter().any(|id| id == "midnight"));
assert_eq!(session.themes().iter().filter(|id| id.as_str() == "catppuccin-mocha").count(), 1, "the built-ins stay");
let theme = session.theme_named("midnight").expect("resolved");
assert_eq!(theme.name, "Midnight");
assert_eq!(theme.colors.accent.to_hex().to_lowercase(), "#ff8800");
let mut registry = Registry::new();
register_core(&mut registry).expect("register");
registry.run("theme.set", &mut session, &json!({"id": "midnight"})).expect("set");
assert_eq!(session.theme().expect("theme").id, "midnight");
}
#[test]
fn bad_files_and_clashing_ids_are_skipped_without_an_error() {
let clash = "id = \"catppuccin-mocha\"\nname = \"Fake\"\nvariant = \"dark\"\n";
let (mut session, _vault, _config) = session(
"user-theme-bad",
&[("a.toml", "not toml at all {{{"), ("b.toml", clash), ("c.toml", "id = \"x\"\n"), ("d.toml", GOOD), ("e.toml", GOOD), ("notes.txt", GOOD)],
);
let ids = session.themes();
assert_eq!(ids.iter().filter(|id| id.as_str() == "midnight").count(), 1, "a repeated id is listed once: {ids:?}");
assert!(!ids.iter().any(|id| id == "x"), "a theme without its required keys is skipped");
assert_ne!(session.theme_named("catppuccin-mocha").map(|theme| theme.name), Some(String::from("Fake")), "a built-in id cannot be taken over");
let mut registry = Registry::new();
register_core(&mut registry).expect("register");
assert!(registry.run("theme.set", &mut session, &json!({"id": "nope"})).is_err());
}