Skip to main content

brief/
config.rs

1use crate::shortcode::{Registry, Shortcode};
2use serde::Deserialize;
3use std::collections::BTreeMap;
4use std::path::Path;
5
6// Every config struct carries `deny_unknown_fields`: a typoed or
7// unsupported key must be a load error, not a silent no-op — the same
8// strictness the language itself promises.
9#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq)]
10#[serde(deny_unknown_fields)]
11pub struct Config {
12    #[serde(default)]
13    pub project: Project,
14    #[serde(default)]
15    pub compile: Compile,
16    #[serde(default)]
17    pub shortcodes: BTreeMap<String, Shortcode>,
18}
19
20#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq)]
21#[serde(deny_unknown_fields)]
22pub struct Project {
23    #[serde(default)]
24    pub name: String,
25    #[serde(default)]
26    pub version: String,
27}
28
29#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq)]
30#[serde(deny_unknown_fields)]
31pub struct Compile {
32    #[serde(default)]
33    pub strict_heading_levels: bool,
34    #[serde(default)]
35    pub default_target: Option<String>,
36    #[serde(default)]
37    pub llm: LlmCompile,
38}
39
40#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
41#[serde(deny_unknown_fields)]
42pub struct LlmCompile {
43    /// Master switch. When false, code blocks are emitted verbatim regardless
44    /// of language tag or `@minify` attribute.
45    #[serde(default = "default_minify_code_blocks")]
46    pub minify_code_blocks: bool,
47    /// Allowlist of language tags eligible for minification. Tags are
48    /// matched case-insensitively. Defaults to the v0.2 set.
49    #[serde(default = "default_minify_languages")]
50    pub minify_languages: Vec<String>,
51    /// Whether to keep the surrounding ```lang fence around minified code.
52    /// True (default) preserves the structural cue for the consumer LLM.
53    #[serde(default = "default_preserve_code_fences")]
54    pub preserve_code_fences: bool,
55}
56
57impl Default for LlmCompile {
58    fn default() -> Self {
59        LlmCompile {
60            minify_code_blocks: default_minify_code_blocks(),
61            minify_languages: default_minify_languages(),
62            preserve_code_fences: default_preserve_code_fences(),
63        }
64    }
65}
66
67fn default_minify_code_blocks() -> bool {
68    true
69}
70fn default_minify_languages() -> Vec<String> {
71    // v0.3 ships minifiers for JSON/JSONL plus the C-family + SQL set.
72    // Aliases are listed explicitly so a user pruning the list by tag name
73    // doesn't accidentally lose a language.
74    vec![
75        "json".into(),
76        "jsonl".into(),
77        "rust".into(),
78        "rs".into(),
79        "c".into(),
80        "h".into(),
81        "cpp".into(),
82        "c++".into(),
83        "cc".into(),
84        "cxx".into(),
85        "hpp".into(),
86        "hxx".into(),
87        "java".into(),
88        "go".into(),
89        "javascript".into(),
90        "js".into(),
91        "typescript".into(),
92        "ts".into(),
93        "sql".into(),
94    ]
95}
96fn default_preserve_code_fences() -> bool {
97    true
98}
99
100pub fn load(path: &Path) -> Result<Config, String> {
101    let text = std::fs::read_to_string(path).map_err(|e| e.to_string())?;
102    toml::from_str(&text).map_err(|e| e.to_string())
103}
104
105pub fn registry_from(cfg: &Config) -> Registry {
106    let mut reg = Registry::with_builtins();
107    reg.extend(cfg.shortcodes.clone());
108    reg
109}