syntax_style — the style registry
SyntaxStyle is a registry of named styles used for syntax highlighting and
token theming. You register styles under names like "keyword" or
"markup.link.url", then merge several names together to get the combined
fg / bg / attributes for a token. It powers the CodeRenderable widget
and is a lighter-weight alternative to driving StyleDefinitions by hand.
let mut styles = SyntaxStyle::create();
The data types
pub struct StyleDefinition {
pub fg: Option<RGBA>,
pub bg: Option<RGBA>,
pub bold: Option<bool>,
pub italic: Option<bool>,
pub underline: Option<bool>,
pub dim: Option<bool>,
}
pub struct StyleDefinitionInput {
pub fg: Option<ColorInput>, // accepts strings like "#ffcc00"
pub bg: Option<ColorInput>,
pub bold: Option<bool>,
pub italic: Option<bool>,
pub underline: Option<bool>,
pub dim: Option<bool>,
}
pub struct MergedStyle {
pub fg: Option<RGBA>,
pub bg: Option<RGBA>,
pub attributes: u32, // packed TextAttributes, see types.md
}
pub struct ThemeTokenStyle {
pub scope: Vec<String>, // e.g. ["keyword.control", "keyword"]
pub style: ThemeTokenStyleInner,
}
pub struct ThemeTokenStyleInner {
pub foreground: Option<ColorInput>,
pub background: Option<ColorInput>,
pub bold: Option<bool>,
pub italic: Option<bool>,
pub underline: Option<bool>,
pub dim: Option<bool>,
}
Constructing
| Constructor | Source of styles |
|---|---|
create() |
Empty registry. |
from_styles(&HashMap<String, StyleDefinitionInput>) |
A flat name → style map. |
from_theme(&[ThemeTokenStyle]) |
A theme token list (each token may list several scopes). |
convert_theme_to_styles(theme: &[ThemeTokenStyle]) -> HashMap<String, StyleDefinition>
is the underlying free function that flattens a theme: every scope in every
token becomes a key.
Registering and resolving
styles.register_style("keyword", &StyleDefinitionInput { fg: Some("#ffb464".into()), ..Default::default() }) -> u64
styles.resolve_style_id("keyword") -> Option<u64> // exact id, or None
styles.get_style_id("keyword.control") -> Option<u64> // falls back to base name before '.'
styles.get_style("keyword.control") -> Option<&StyleDefinition>
styles.get_style_count() -> usize
styles.get_all_styles() -> HashMap<String, StyleDefinition>
styles.get_registered_names() -> Vec<String>
Scoped lookups fall back to the base name: get_style("keyword.control")
returns the style registered under "keyword" if no exact match exists. This
mirrors how editor token scopes inherit from parent scopes.
Merging
let merged: MergedStyle = styles.merge_styles(&["keyword", "keyword.control"]);
merge_styles overlays the named styles in order — later names override
earlier ones field-by-field — packs the resulting booleans into the
attributes bitmask via create_text_attributes, and caches
the result keyed by the joined name list ("keyword:keyword.control"), so
repeated merges of the same set are cheap.
Cache management: clear_cache() empties the merge cache,
get_cache_size() reports its size, clear_name_cache() drops the name → id
map (ids stay valid), and destroy() frees everything.
Lifecycle guard
All methods assert the registry is not destroyed (SyntaxStyle::destroy()).
Calling any method after destroy() panics.
Example — themed tokens for a code widget
use cosh_tui::core::syntax_style::{SyntaxStyle, StyleDefinitionInput, ThemeTokenStyle, ThemeTokenStyleInner};
let theme = vec![
ThemeTokenStyle {
scope: vec!["keyword".into(), "keyword.control".into()],
style: ThemeTokenStyleInner { foreground: Some("#ffb464".into()), ..Default::default() },
},
ThemeTokenStyle {
scope: vec!["string".into()],
style: ThemeTokenStyleInner { foreground: Some("#96c896".into()), ..Default::default() },
},
];
let styles = SyntaxStyle::from_theme(&theme);
let merged = styles.merge_styles(&["keyword.control"]); // inherits "keyword"
// merged.fg == Some(rgba(1.0, 0.71, 0.39, 1.0)), merged.attributes == 0