Skip to content

Releases: razkar-studio/farben

[BREAKING] v0.18.0 - Comp-time Unification, Part 1

20 Apr 01:42

Choose a tag to compare

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) -> String in farben-core::strip: strips farben
    markup tags from a string, returning plain text. Re-exported from farben as
    farben::strip_markup.
  • markup_strip! macro that behaves the same as ansi_strip! but uses strip_markup
  • render_forced(tokens: Vec<Token>) -> String in farben-core::parser: renders
    tokens to ANSI unconditionally, bypassing color_enabled(). Used internally by
    the color! and colorb! proc macros to ensure the styled variant is always
    baked in regardless of the build environment.
  • FarbenStr in farben: a compile-time string pair holding both a styled
    (&'static str) and plain (&'static str) variant, resolved at the user's
    runtime via FarbenStr::resolve() and Display.
  • color_enabled() re-exported from farben: previously only accessible via
    farben_core.
  • Doc comments of init_styles() of farben-build.

Changed

  • color! and colorb! now emit a FarbenStr instead 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 to render_forced().

Breaking

  • color! and colorb! no longer return &'static str. Code storing the result
    as &str must call .resolve() explicitly. Usage inside cprintln!, 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/or colorb!, then follow the steps:
  1. color! and colorb! no longer return &'static str.
  2. Change calls that use color!, colorb! as an expression of &'static str to use .resolve()
  3. Example:
use farben::prelude::*;

// change this
let previous: &str = color!("[bold red]Hi");

// to be
let new: &str = color!("[bold red]Hi").resolve();
  1. Why? See changes above. The color!, colorb! procedural macros now return a special FarbenStr instead of a &str.

Make great things with Farben.

Cheers, RazkarStudio.

v0.17

18 Apr 01:59

Choose a tag to compare

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

12 Apr 12:46

Choose a tag to compare

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

  • anstyle feature flag - enables interoperability with the anstyle crate.
  • anstyle_conv module in farben-core - provides bidirectional From
    implementations for converting between farben types (Color, NamedColor,
    Style) and anstyle types (anstyle::Color, anstyle::AnsiColor,
    anstyle::Style).
  • anstyle! macro in farben - parses farben markup and converts the result
    into an anstyle::Style. Requires the anstyle feature flag.
  • anstyle crate added as an optional dependency to both farben-core and
    farben.

v0.15.0 - OPTIMUSZ MIZED

12 Apr 10:54

Choose a tag to compare

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
    replaces Reset(None) and TagType::ResetOne(Box<TagType>) replaces Reset(Some(...)).
    Update all match arms that pattern-match on TagType::Reset.
  • Token::Text(String) is now Token::Text(Cow<'static, str>). Construction sites must use
    Cow::Owned(string) for runtime strings or Cow::Borrowed("literal") for static string
    literals. Pattern-matching and push_str usage are unaffected, since Cow<'static, str>
    deref-coerces to &str.

Changed

  • tokenize pre-allocates the token Vec with capacity input.len() / 4, reducing
    reallocations for typical markup strings.
  • parse_part (lexer) consolidates the ansi(...) and rgb(...) prefix checks into a
    single strip_prefix call each, removing a redundant scan of the tag string per call.
  • The style registry now stores Arc<Style> internally. Each lookup clones an Arc
    (one atomic increment) instead of cloning the full Style struct.
  • emphasis_to_ansi bypasses the intermediate Vec<u8> and formats the escape sequence
    directly via format!, saving a heap allocation per emphasis tag.
  • color_to_ansi bypasses the intermediate Vec<u8> for all color types, formatting the
    escape sequence directly. A new private named_sgr const fn maps NamedColor to its
    base SGR code without a runtime lookup table.
  • render pre-allocates the output buffer with capacity tokens.len() * 16.
  • Release profile: lto = "thin", codegen-units = 1, opt-level = 3 added to root
    Cargo.toml, enabling cross-crate inlining in optimized builds.
  • env.rs unsafe blocks now carry // SAFETY: comments documenting the invariants for
    isatty(1) (Unix) and the GetStdHandle query path (Windows).

Added

  • Criterion benchmark suite in farben-core/benches/farben_bench.rs covering: 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 render with color disabled: verify that tag tokens are stripped and only
    Token::Text and Token::Tag(Prefix(...)) content is emitted.
  • Edge case tests for strip_ansi: empty string, bare ESC byte, 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

12 Apr 10:53

Choose a tag to compare

[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-build 0.1.0 - new build script helper crate. Call farben_build::run() from
    build.rs to read farben.frb.toml and generate two artifacts in OUT_DIR:
    • farben_styles.rs - a Rust source file containing an init_styles() function that
      registers all styles and prefixes at runtime. Include it via load_styles!() at startup.
    • farben_registry.lsv - a line-separated values file consumed by farben-macros proc
      macros at compile time, so color!, colorb!, and validate_color! can see user-defined
      style tags. Use farben_build::run_with(&[paths]) to supply custom config file paths
      instead of the default farben.frb.toml.
    • Config format: INI-like [styles] and [prefixes] sections with key = "value" pairs.
      Namespaced sections like [styles.myns] produce keys of the form myns:key.
  • Absolutely zero external dependencies added.

Changed

  • farben-macros bumped to 0.5.0. Every proc macro invocation now calls load_registry()
    at startup, which reads farben_registry.lsv from OUT_DIR and pre-populates the
    compile-time registry. As a result, color!("[myTag]text") now compiles successfully when
    myTag was declared in a .frb.toml config file.
  • farben-core bumped to 0.10.0. No new public API.
  • farben-md bumped to 0.2.0, picking up the farben-core 0.10.0 dependency. No new
    public API.

v0.13.0 - I'm Lost!

04 Apr 11:04

Choose a tag to compare

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 the COLORTERM and TERM environment variables
    to detect terminal color capabilities at runtime. Opt-out-able via lossy default feature.
  • Zero external dependencies added to core library internals.

[0.13.0] - 2026-04-04 - farben

Changed

  • farben-core dependency bumped to 0.9.0, picking up lossy degrading support.
  • opt-out-able lossy default feature, piping to farben-core's own lossy feature.

v0.12.0 - Write With Color

04 Apr 10:19

Choose a tag to compare

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 any Write implementor. Useful for writing to files, String buffers, or custom writers.
    All four support the same markup features as the stdout variants (named colors, RGB, ANSI256, emphasis,
    bleeding via the b variants).

v0.11.0: Nice Errors Man

04 Apr 08:08

Choose a tag to compare

...shut up. Regardless,

Changelog

All notable changes to Farben will be documented here.

[0.8.0] - 2026-04-04 - farben-core

Added

  • RegistryError enum — a separate error type for registry operations (set_prefix, insert_style).
    Split out from LexError because registry errors have no source position (they occur outside markup
    parsing). Has one variant: UnknownStyle(String).
  • LexErrorDisplay<'a> struct — wraps a &LexError and the original &str input 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 LexError variants now carry a position: usize field (byte offset into the markup string).
    Affected variants: UnclosedTag, InvalidTag, UnclosedValue, InvalidArgumentCount,
    InvalidValue, InvalidResetTarget. Previously no variants stored position info.
  • LexError::UnknownStyle removed — registry errors now use RegistryError::UnknownStyle instead.
  • LexError's Display impl now includes position in every message
    (e.g. "invalid tag 'foo' at position 5").

[0.11.0] - 2026-04-04 - farben

Added

  • farben::prelude module - 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 over use farben::*, which also pulls in
    color_runtime and validate_color - items that are pub only to satisfy macro expansion,
    not intended for direct use.

Changed

  • farben-core dependency bumped to 0.8.0, picking up position-aware LexError variants and
    the new LexErrorDisplay diagnostic formatter. try_color error 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

04 Apr 08:06

Choose a tag to compare

Changelog

Farben is constantly shipping. Notable changes will be documented here.

[2026-04-04]

Added

  • ansi_strip!(...) — macro that accepts format!-style arguments, builds the string,
    then strips all CSI ANSI escape sequences from the result. Non-CSI ESC bytes pass
    through unchanged. Returns String.
  • strip_ansi re-exported at the farben crate root from farben-core::strip::strip_ansi,
    making it available via use farben::* and as the expansion target for ansi_strip!.

Changed

  • farben-core dependency bumped to 0.7.0.

[0.7.0] - 2026-04-04 - farben-core

Added

  • env module: runtime detection of whether ANSI color output should be enabled.
    Respects the NO_COLOR and FORCE_COLOR environment variable conventions (in that
    order), then falls back to TTY detection. Result is computed once per process and
    cached via OnceLock.
    • color_enabled(): returns the cached bool for the current process.
    • TTY detection on Unix via isatty(1); on Windows via GetStdHandle +
      GetConsoleMode; false on all other targets.
  • strip module: utilities for removing ANSI escape sequences from strings.
    • strip_ansi(input): strips CSI sequences (ESC [ ... <letter>) from a string
      and returns plain text. Non-CSI ESC bytes 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

20 Mar 10:08

Choose a tag to compare

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 how println!() and print!() behave in std.
    Applies to ceprint!, ceprintln!, mdprint!, mdprintln!, mdeprint!, mdeprintln!,
    and all bleed variants.

Changed

  • src/lib.rs split into focused modules: functions.rs, macros/color.rs,
    macros/format.rs, macros/markdown.rs, macros/eprint.rs, and tests.rs.
    No public API changes.