# rang tries to skip attributes that might produce garbage

> rang is an Unlicense header-only C++ library that colours iostream output on Unix and Windows, including old Windows consoles via native console APIs. Its compatibility tables are the real documentation, listing which styles work where.

**agauniyal/rang** — A Minimal, Header only Modern c++ library for terminal goodies 💄✨

- Repository: https://github.com/agauniyal/rang
- Website: https://agauniyal.github.io/rang/
- Stars: 1,595 · Forks: 154
- Language: C++
- License: Unlicense
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/agauniyal-rang

## One header, zero third-party dependencies, two system headers

rang is a single header-only library, so installation is putting rang.hpp in your include folder directly into the project source tree, or somewhere reachable from your project.

The dependency statement is unusually clean and worth repeating because it is not always true of header-only libraries. rang depends only on the C++ standard library, the unistd.h system header on Unix, and the windows.h and io.h system headers on Windows-based systems. There are no third-party dependencies in the sense of a package you have to fetch.

The minimum is visible in the example rather than in an install note:

```c++
#include "rang.hpp"

using namespace std;
using namespace rang;

int main()
{
    cout << "Plain old text"
         << style::bold << "Rang styled text!!"
         << style::reset << endl;
}
```

The API shape is the point. There is no render function taking a string and returning a coloured string. You stream attributes directly into cout between your text, the same way you would stream a number. The attributes are objects that write themselves, so they compose with any expression in the stream, including a loop that prints many lines without repeating the escape codes.

Those attributes work through cout, clog and cerr alike, since the library attaches to iostream objects rather than to a file descriptor you have to configure separately.

## TTY detection and the two override switches

The library handles terminal detection internally, so you are not expected to check whether the application's output might be redirected to a file. That single decision removes the most common source of junk in a CLI tool, where escape codes end up in a log file because nobody checked.

The default behaviour can be overridden with one call:

```cpp
void rang::setControlMode(rang::control);
```

The three values are control::Auto, which automatically detects whether the terminal supports colour and is the default; control::Off, which turns colours off completely; and control::Force, which forces colours even if the terminal does not support them or output is redirected to a non-terminal.

Force exists for the case where you know better than the detection, such as piping into a pager that will interpret the codes. Off exists for tests that assert on output text.

On Windows there is a second switch, setWinTermMode, taking winTerm::Auto, winTerm::Native and winTerm::Ansi. Auto checks for newer Windows and picks Ansi, otherwise falls back to Native, and is the default. Native is supported in all versions of Windows but supports fewer attributes. Ansi is supported in newer versions of Windows and supports a rich variety of attributes.

So the same code has two independent decisions to make: whether to emit colour at all, and on Windows, which console API to emit it through.

## The compatibility tables are the honest part of the API

rang publishes two-column tables for every attribute, marked yes, no or maybe for Linux, Windows and others on one side and Old Win on the other.

The text style table is where the design decision shows. Bold works everywhere including Old Win. Reversed works everywhere. Conceal is marked maybe on Linux, Windows and others and yes on Old Win, which is a strange inversion and probably reflects what each console API actually does. Dim, italic, underline and crossed work on modern systems but not on Old Win. Blink and reverse-blink are marked no on both columns, meaning they are exposed as constants but never produce anything.

Colours are the simple case. Every listed foreground, background, bright foreground and bright background colour is marked yes in both columns, plus style::reset, fg::reset and bg::reset.

So the colour set is portable everywhere and the style set is not. If your tool relies on underline to mark input fields, that line of your program behaves differently on an old Windows console, where it will simply do nothing.

The stated reason for the gaps is incompatibilities between OS versions, and that rang will try to skip attributes which might produce garbage, instead of pushing random ANSI escape codes on your streams. The design choice is to produce less rather than to produce broken output.

## Conan, CMake, Meson and the Conan reference you have to update

Three build paths exist and they differ in what you have to keep current.

The manual path needs no build system change: copy the header in.

The Conan path is documented as two steps. First add a reference to the requires section of your project's conanfile.txt:

```
[requires]
rang/3.1.0@rang/stable
```

Then run conan's install command:

```
conan install
```

That reference names version 3.1.0, which is not the current release. The recent releases are v3.3 on 2026-05-16, v3.2 on 2021-07-30 and v3.1.0 on 2018-02-14. So the README's Conan example points at a 2018 version while the repository has since shipped 3.2 and 3.3. Anyone taking that snippet literally pins themselves to an old release, which may or may not be intentional for stability and is at minimum undocumented.

The repository itself supports the other two build systems: CMakeLists.txt with a cmake/ directory, and meson.build. A conanfile.py at the root serves the Conan recipe, test_package/ holds the Conan test package, and test/ holds the project's own tests. Formatting is handled by .clang-format and .editorconfig, and CI runs through a GitHub Actions workflow with a Codecov badge, so the test suite is real rather than aspirational.

## Two problems the README answers directly

The troubleshooting section is short and covers exactly the two failures a new user hits.

The first is garbage output or a terminal that is not detected. The advice is to check the value of the TERM environment variable, then open an issue mentioning that value along with the terminal name. The reason this needs to be asked in the issue rather than handled in code is that terminal capability lives in TERM, so a library reading it has to be told by the user what they actually have.

The second is redirecting the rdbuf of cout, cerr or clog. The README states that rang does not interfere if you redirect those streams elsewhere and leaves the decision to the library user, and points to a specific pull request conversation plus example code hosted as a gist. So the position is deliberate: rang attaches to the iostream objects, and if you take over their underlying buffer, the point at which rang would have written is no longer under its control.

Neither answer is a workaround for a bug. They are statements about where the library draws its boundary, which is the right way to handle both.

One more thing the README declines to do is support terminals that are not ANSI. For that it points to Termdb, a separate project by the same author, which supports virtually all terminals and their capabilities. That is a clean division: rang stays one header, and full terminal coverage is a different dependency.

## Where a colour library or raw escape codes fit better

The alternatives divide by how much you want to build.

A fuller terminal UI library gives you colour and also boxes, cursor movement, progress bars and input handling, at the cost of dependencies and a build step. If your program already draws a table or a prompt, that library may be less total work than assembling the pieces yourself, and it is likely to handle the Windows console cases more carefully than rang does.

Raw ANSI escape codes, written by hand, are the zero-dependency extreme. They work where ANSI is supported and cost nothing, but they need compatibility handling on old Windows consoles and may expose literal escape characters when output is redirected. rang is precisely the packaged version of that layer, so the question is whether you want to write it or include a header.

Termdb is the third option and sits between: the same author points to it for terminals rang declines to handle. Choosing rang for its compactness and Termdb for coverage is a coherent pairing if you accept two headers rather than one.

The licence decision is unusually permissive here. rang is released under the Unlicense, which is public domain dedication, so there is no attribution requirement, no copyleft and no patent grant to consider. For a library you intend to keep inside a proprietary product, that is about as simple as licensing gets.

## Conclusion

rang fits a C++ command line tool that needs coloured output without a package manager entry, a build system change or a single transitive dependency. It does not fit a Windows tool that needs italic, underline, dim or crossed styles on legacy consoles, since those are marked unsupported there, and it does not cover non-ANSI terminals at all. First step is to drop include/rang.hpp into your project and run the README example unmodified, then check the compatibility table before relying on any style beyond bold and reversed.

## FAQ

### How do I install the rang header-only library?

Put rang.hpp in the include folder directly into the project source tree, or somewhere reachable from your project. Alternatively add rang/3.1.0@rang/stable to the requires section of conanfile.txt and run conan install, though that reference names an older release than the current v3.3.

### Does rang need any third-party dependencies?

No. The README states it depends only on the C++ standard library, the unistd.h system header on Unix, and windows.h and io.h on Windows-based systems.

### How do I disable colours or force them on?

Call rang::setControlMode with control::Off to turn colours off, or control::Force to emit them even on a terminal that does not support them or when output is redirected. The default control::Auto detects terminal support internally.

### Which text styles work on old Windows consoles?

According to the compatibility table, bold, reversed, conceal and reset work on Old Win, while dim, italic, underline and crossed do not. Blink and reverse blink are unsupported on both modern systems and Old Win.

### What should I do if my terminal shows garbage output?

Check the value of your TERM environment variable, then open an issue mentioning that value along with your terminal name. For terminals that are not ANSI, the README points to Termdb instead.

## Sources

- [agauniyal/rang on GitHub](https://github.com/agauniyal/rang)
- [License: Unlicense](https://github.com/agauniyal/rang/blob/master/LICENSE)
- [Project website](https://agauniyal.github.io/rang/)
- [README](https://github.com/agauniyal/rang/blob/master/README.md)
- [Releases](https://github.com/agauniyal/rang/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/agauniyal-rang
