Releases: razkar-studio/farben
[BREAKING] v0.18.0 - Comp-time Unification, Part 1
Farben is constantly updating. Here are the new changes to v0.18.0: Comp-time Unification, Part 1.
Note
This implementation was suggested by redditor u/manpacket on the r/Rust subreddit. The post can be seen here. Thank you manpacket!
core0.13.4 / macros0.6.0 / frb0.18.0 / build0.1.4 — 2026-04-20
Compile-time Runtime Detection
Important
This update introduces breaking changes to compile users. See the Breaking section down below and the migration guide.
Added
strip_markup(input: &str) -> Stringinfarben-core::strip: strips farben
markup tags from a string, returning plain text. Re-exported fromfarbenas
farben::strip_markup.markup_strip!macro that behaves the same asansi_strip!but usesstrip_markuprender_forced(tokens: Vec<Token>) -> Stringinfarben-core::parser: renders
tokens to ANSI unconditionally, bypassingcolor_enabled(). Used internally by
thecolor!andcolorb!proc macros to ensure the styled variant is always
baked in regardless of the build environment.FarbenStrinfarben: a compile-time string pair holding both a styled
(&'static str) and plain (&'static str) variant, resolved at the user's
runtime viaFarbenStr::resolve()andDisplay.color_enabled()re-exported fromfarben: previously only accessible via
farben_core.- Doc comments of
init_styles()offarben-build.
Changed
color!andcolorb!now emit aFarbenStrinstead of a bare&'static str,
baking both ANSI and plain variants into the binary and deferring the
NO_COLOR/FORCE_COLOR/TTY decision to the end user's runtime.render()now delegates its ANSI rendering path torender_forced().
Breaking
color!andcolorb!no longer return&'static str. Code storing the result
as&strmust call.resolve()explicitly. Usage insidecprintln!,cprint!,
cwrite!, and all other print/write macros is unaffected as they go through
Display.
Migrating (compile users)
- If you only use
cprintln!,cprint!, etc, then you are safe. No changes needed. - But when you directly use
color!and/orcolorb!, then follow the steps:
color!andcolorb!no longer return&'static str.- Change calls that use
color!,colorb!as an expression of&'static strto use.resolve() - Example:
use farben::prelude::*;
// change this
let previous: &str = color!("[bold red]Hi");
// to be
let new: &str = color!("[bold red]Hi").resolve();- Why? See changes above. The
color!,colorb!procedural macros now return a specialFarbenStrinstead of a&str.
Make great things with Farben.
Cheers, RazkarStudio.
v0.17
Check the CHANGELOG.md of this repository, I don't feel like writing them here right now.
It seems that unnecessarily changing conventions and stuff is becoming the norm across tech.
And that's why I'm planning on changing how the members' versions are being referenced!
Right now they use the classic old v prefix. From now, the version prefix will be changed across crates:
farben:v*farben-core:core*farben-macros:macros*farben-build:build*farben-md:md*
Why am I changing them? I'm not sure. It's just better to look at the versions in a glance and know which crates they represent instead of having to put their whole name infront of it. This wouldn't change anything about Farben itself, just how I'll represent the versions in future CHANGELOG entries.
Cheers, RazkarStudio
Make great things with Farben.
v0.16.0 - A Style
Hmm, by English grammar, "an style" should've been "a style" instead. But who am I to say, my library's named in German.
Farben is constantly updating. All notable changes to Farben will be documented here.
[farben-core 0.12.0 / farben 0.16.0] - 2026-04-12 - anstyle Interop
Added
anstylefeature flag - enables interoperability with theanstylecrate.anstyle_convmodule infarben-core- provides bidirectionalFrom
implementations for converting between farben types (Color,NamedColor,
Style) andanstyletypes (anstyle::Color,anstyle::AnsiColor,
anstyle::Style).anstyle!macro infarben- parses farben markup and converts the result
into ananstyle::Style. Requires theanstylefeature flag.anstylecrate added as an optional dependency to bothfarben-coreand
farben.
v0.15.0 - OPTIMUSZ MIZED
Farben is constantly updating. All notable changes to Farben will be documented here.
[farben-core 0.11.0 / farben 0.15.0] - 2026-04-12 - Global
Performance Optimizations
v0.15 is ~1.4x faster on average across the core pipeline (geometric mean of 7 benchmarks).
ANSI encoding is the biggest winner: named color encoding is 1.9x faster, RGB encoding 1.7x faster,
and emphasis sequences 1.6x faster. The full tokenize-to-render pipeline is 1.35x faster.
All figures measured against the v0.14 criterion baseline on x86-64 Linux.
Important
Breaking changes in farben-core 0.11.0. See the Breaking Changes section below.
Breaking Changes (farben-core)
TagType::Reset(Option<Box<TagType>>)has been split into two variants.TagType::ResetAll
replacesReset(None)andTagType::ResetOne(Box<TagType>)replacesReset(Some(...)).
Update all match arms that pattern-match onTagType::Reset.Token::Text(String)is nowToken::Text(Cow<'static, str>). Construction sites must use
Cow::Owned(string)for runtime strings orCow::Borrowed("literal")for static string
literals. Pattern-matching andpush_strusage are unaffected, sinceCow<'static, str>
deref-coerces to&str.
Changed
tokenizepre-allocates the tokenVecwith capacityinput.len() / 4, reducing
reallocations for typical markup strings.parse_part(lexer) consolidates theansi(...)andrgb(...)prefix checks into a
singlestrip_prefixcall each, removing a redundant scan of the tag string per call.- The style registry now stores
Arc<Style>internally. Each lookup clones anArc
(one atomic increment) instead of cloning the fullStylestruct. emphasis_to_ansibypasses the intermediateVec<u8>and formats the escape sequence
directly viaformat!, saving a heap allocation per emphasis tag.color_to_ansibypasses the intermediateVec<u8>for all color types, formatting the
escape sequence directly. A new privatenamed_sgrconst fn mapsNamedColorto its
base SGR code without a runtime lookup table.renderpre-allocates the output buffer with capacitytokens.len() * 16.- Release profile:
lto = "thin",codegen-units = 1,opt-level = 3added to root
Cargo.toml, enabling cross-crate inlining in optimized builds. env.rsunsafe blocks now carry// SAFETY:comments documenting the invariants for
isatty(1)(Unix) and theGetStdHandlequery path (Windows).
Added
- Criterion benchmark suite in
farben-core/benches/farben_bench.rscovering: tokenize
(plain and complex), render, full tokenize + render pipeline,emphasis_to_ansi,
color_to_ansi(named and RGB), and registry lookup via tokenize. - Tests for
renderwith color disabled: verify that tag tokens are stripped and only
Token::TextandToken::Tag(Prefix(...))content is emitted. - Edge case tests for
strip_ansi: empty string, bareESCbyte, sequences-only input,
mixed content, RGB and ANSI256 sequences.
Performance
Measured against the v0.14 baseline using criterion 0.5.1 on x86-64 Linux (CachyOS, Rust 1.94.1):
| Benchmark | v0.14 | v0.15 | Change |
|---|---|---|---|
| tokenize plain | 61.1 ns | 50.6 ns | -22% |
| tokenize complex | 1.176 µs | 866.6 ns | -26% |
| render | 188.6 ns | 182.9 ns | -2% (within noise) |
| pipeline | 1.485 µs | 1.099 µs | -26% |
| emphasis_to_ansi | 91.1 ns | 56.0 ns | -37% |
| color_to_ansi named | 111.6 ns | 59.5 ns | -47% |
| color_to_ansi rgb | 367.3 ns | 214.3 ns | -43% |
| registry lookup | 361.3 ns | 346.6 ns | -5% |
v0.14.0 - i forgot to post this lmao
[farben-build 0.1.0 / farben-macros 0.5.0 / farben-core 0.10.0 / farben-md 0.2.0 / farben 0.14.0] - 2026-04-05 - Global
Compile-time Custom Style Support
Added
farben-build0.1.0 - new build script helper crate. Callfarben_build::run()from
build.rsto readfarben.frb.tomland generate two artifacts inOUT_DIR:farben_styles.rs- a Rust source file containing aninit_styles()function that
registers all styles and prefixes at runtime. Include it viaload_styles!()at startup.farben_registry.lsv- a line-separated values file consumed byfarben-macrosproc
macros at compile time, socolor!,colorb!, andvalidate_color!can see user-defined
style tags. Usefarben_build::run_with(&[paths])to supply custom config file paths
instead of the defaultfarben.frb.toml.- Config format: INI-like
[styles]and[prefixes]sections withkey = "value"pairs.
Namespaced sections like[styles.myns]produce keys of the formmyns:key.
- Absolutely zero external dependencies added.
Changed
farben-macrosbumped to0.5.0. Every proc macro invocation now callsload_registry()
at startup, which readsfarben_registry.lsvfromOUT_DIRand pre-populates the
compile-time registry. As a result,color!("[myTag]text")now compiles successfully when
myTagwas declared in a.frb.tomlconfig file.farben-corebumped to0.10.0. No new public API.farben-mdbumped to0.2.0, picking up thefarben-core 0.10.0dependency. No new
public API.
v0.13.0 - I'm Lost!
Changelog
Farben is constantly updating. All notable changes to Farben will be documented here.
[0.9.0] - 2026-04-04 - farben-core
Added
- Lossy degrading. When the terminal does not support 24-bit true color, RGB values are
automatically degraded to the nearest ANSI256 color. When the terminal only supports
basic ANSI colors (8/16 colors), RGB and ANSI256 values are degraded to the nearest
named color. The degrader module uses theCOLORTERMandTERMenvironment variables
to detect terminal color capabilities at runtime. Opt-out-able vialossydefault feature. - Zero external dependencies added to core library internals.
[0.13.0] - 2026-04-04 - farben
Changed
farben-coredependency bumped to0.9.0, picking up lossy degrading support.- opt-out-able
lossydefault feature, piping tofarben-core's ownlossyfeature.
v0.12.0 - Write With Color
Changelog
Farben is constantly updating. Notable changes are documented here.
[0.12.0] - 2026-04-04 - farben
Added
cwrite!,cwriteln!,cwriteb!,cwritebln!- writer variants of the colored print macros.
Work with anyWriteimplementor. Useful for writing to files,Stringbuffers, or custom writers.
All four support the same markup features as the stdout variants (named colors, RGB, ANSI256, emphasis,
bleeding via thebvariants).
v0.11.0: Nice Errors Man
...shut up. Regardless,
Changelog
All notable changes to Farben will be documented here.
[0.8.0] - 2026-04-04 - farben-core
Added
RegistryErrorenum — a separate error type for registry operations (set_prefix,insert_style).
Split out fromLexErrorbecause registry errors have no source position (they occur outside markup
parsing). Has one variant:UnknownStyle(String).LexErrorDisplay<'a>struct — wraps a&LexErrorand the original&strinput to produce
compiler-style diagnostic output. Renders two lines: the full input string, then a caret (^)
aligned to the byte offset of the error. Example:| [bold unknown]text | ^^^^^^^ invalid tag: 'unknown'
Changed
- All
LexErrorvariants now carry aposition: usizefield (byte offset into the markup string).
Affected variants:UnclosedTag,InvalidTag,UnclosedValue,InvalidArgumentCount,
InvalidValue,InvalidResetTarget. Previously no variants stored position info. LexError::UnknownStyleremoved — registry errors now useRegistryError::UnknownStyleinstead.LexError'sDisplayimpl now includes position in every message
(e.g."invalid tag 'foo' at position 5").
[0.11.0] - 2026-04-04 - farben
Added
farben::preludemodule - the recommended import path going forward.use farben::prelude::*
brings every user-facing item into scope (functions, macros, types) gated by the same feature
flags as their definitions. Prefer this overuse farben::*, which also pulls in
color_runtimeandvalidate_color- items that arepubonly to satisfy macro expansion,
not intended for direct use.
Changed
farben-coredependency bumped to0.8.0, picking up position-awareLexErrorvariants and
the newLexErrorDisplaydiagnostic formatter.try_colorerror messages now include the byte
offset of the offending token.- All documentation and examples updated to use
use farben::prelude::*.
v0.10.0 - ANStripsI and Respects
Changelog
Farben is constantly shipping. Notable changes will be documented here.
[2026-04-04]
Added
ansi_strip!(...)— macro that acceptsformat!-style arguments, builds the string,
then strips all CSI ANSI escape sequences from the result. Non-CSIESCbytes pass
through unchanged. ReturnsString.strip_ansire-exported at thefarbencrate root fromfarben-core::strip::strip_ansi,
making it available viause farben::*and as the expansion target foransi_strip!.
Changed
farben-coredependency bumped to0.7.0.
[0.7.0] - 2026-04-04 - farben-core
Added
envmodule: runtime detection of whether ANSI color output should be enabled.
Respects theNO_COLORandFORCE_COLORenvironment variable conventions (in that
order), then falls back to TTY detection. Result is computed once per process and
cached viaOnceLock.color_enabled(): returns the cached bool for the current process.- TTY detection on Unix via
isatty(1); on Windows viaGetStdHandle+
GetConsoleMode;falseon all other targets.
stripmodule: utilities for removing ANSI escape sequences from strings.strip_ansi(input): strips CSI sequences (ESC [ ... <letter>) from a string
and returns plain text. Non-CSIESCbytes are passed through unchanged.
Useful for measuring display width, plain-text logging, or piping to tools that
do not interpret ANSI codes.
v0.9.0
v0.9.0: Errors, and nothing else.
All notable changes to Farben will be documented here.
[0.9.0] - 2026-03-20 - farben
Added
ceprint!,ceprintln!,ceprintb!,ceprintbln!— stderr variants of the colored print macros.mdeprint!,mdeprintln!— stderr variants of the inline markdown print macros.- Empty invocation support for all print macros.
cprintln!()now prints a bare newline,
cprint!()prints nothing — consistent with howprintln!()andprint!()behave in std.
Applies toceprint!,ceprintln!,mdprint!,mdprintln!,mdeprint!,mdeprintln!,
and all bleed variants.
Changed
src/lib.rssplit into focused modules:functions.rs,macros/color.rs,
macros/format.rs,macros/markdown.rs,macros/eprint.rs, andtests.rs.
No public API changes.