Skip to main content

farben_core/
state.rs

1//! Per-thread persistent style state.
2//!
3//! Style "bleed" calls (e.g. cprintb!) intentionally don't reset at the end,
4//! so subsequent calls see the leftover ANSI styles in the terminal. To handle
5//! `[/red]`-style targeted resets correctly across calls, we persist the
6//! active style stack between renders.
7//!
8//! Per-thread because terminal output is inherently per-thread state — two
9//! threads writing to the same stdout are already racing; they shouldn't also
10//! be racing over style state.
11
12use std::cell::RefCell;
13use crate::lexer::TagType;
14
15thread_local! {
16    static ACTIVE_STACK: RefCell<Vec<TagType>> = const { RefCell::new(Vec::new()) };
17}
18
19/// Returns a clone of the current persisted stack.
20/// Used by the parser at the start of `render` to resume from prior state.
21pub fn active_stack() -> Vec<TagType> {
22    ACTIVE_STACK.with(|s| s.borrow().clone())
23}
24
25/// Replaces the persisted stack.
26/// Used by the parser at the end of `render` to save its working state.
27pub fn set_active_stack(new_stack: Vec<TagType>) {
28    ACTIVE_STACK.with(|s| *s.borrow_mut() = new_stack);
29}
30
31/// Clears the persisted stack.
32/// Called by the upper layer after a non-bleed print (which appends \x1b[0m,
33/// so the terminal is back to a clean slate).
34pub fn clear_active_stack() {
35    ACTIVE_STACK.with(|s| s.borrow_mut().clear());
36}