[PR #559] feat(core): add indexed color (0-255) and OSC palette control #1399

Open
opened 2026-03-14 09:34:41 +03:00 by kerem · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/anomalyco/opentui/pull/559
Author: @bresilla
Created: 1/20/2026
Status: 🔄 Open

Base: mainHead: feat/indexed-colors


📝 Commits (8)

  • e14abda feat: Add 256-color palette and metadata to RGBA
  • ec7cf26 feat: Add RGB_META field to RGBA type
  • 4cacd74 feat: enable indexed colors and RGB_META in RGBA struct
  • 225ef4f feat: adjust test for the new [5]th float
  • 01758a1 fix: Add meta field to ExternalCursorState
  • 73eebd8 feat: Add support for indexed colors in RGBA in TS side
  • b8f6e6c test: add ANSI 256 color showcase example
  • d98b815 fix: Use 16-color ANSI escape codes for indexed colors 0-15 in renderer

📊 Changes

30 files changed (+869 additions, -448 deletions)

View changed files

📝 packages/core/src/buffer.ts (+4 -4)
packages/core/src/examples/terminal_ansi.ts (+197 -0)
📝 packages/core/src/lib/RGBA.test.ts (+9 -2)
📝 packages/core/src/lib/RGBA.ts (+74 -4)
📝 packages/core/src/post/filters.ts (+28 -28)
📝 packages/core/src/renderables/Text.selection-buffer.test.ts (+4 -4)
📝 packages/core/src/renderables/Text.test.ts (+6 -6)
📝 packages/core/src/renderables/TextTable.test.ts (+2 -2)
📝 packages/core/src/renderables/__tests__/LineNumberRenderable.test.ts (+10 -10)
📝 packages/core/src/renderables/__tests__/Textarea.scroll.test.ts (+1 -1)
📝 packages/core/src/renderables/__tests__/Textarea.selection.test.ts (+17 -17)
📝 packages/core/src/testing/test-recorder.test.ts (+2 -2)
📝 packages/core/src/zig-structs.ts (+2 -1)
📝 packages/core/src/zig.ts (+1 -1)
📝 packages/core/src/zig/ansi.zig (+124 -2)
📝 packages/core/src/zig/bench/buffer-draw-text-buffer_bench.zig (+15 -15)
📝 packages/core/src/zig/bench/styled-text_bench.zig (+18 -18)
📝 packages/core/src/zig/buffer.zig (+39 -32)
📝 packages/core/src/zig/lib.zig (+2 -0)
📝 packages/core/src/zig/renderer.zig (+38 -23)

...and 10 more files

📄 Description

Summary

Adds full support for terminal indexed colors (0-255) and OSC-based terminal palette control, enabling the use of the standard 256-color palette and dynamic color modification via ANSI/OSC escape sequences.

Makes this possible (with tools like pywal et al):
ezgif-54dccc5a972ae0ee

Changes

TypeScript (RGBA.ts)

  • Added COLOR_TYPE_RGB, COLOR_TYPE_INDEXED, COLOR_TYPE_DEFAULT constants
  • Extended RGBA class with colorType, index properties
  • Added RGBA.fromIndex(index), RGBA.defaultForeground(), RGBA.defaultBackground() static methods
  • Added isIndexed(), isDefault(), isRgb() instance methods
  • Added indexToApproximateRgb() function with standard 256-color palette mapping
  • Extended ColorInput type to accept string | RGBA | IndexedColor | number
  • Updated parseColor() to handle "ansi:N" format, numeric indices, and {index: N} objects

TypeScript (terminal-palette.ts) - OSC Palette Control

  • Added setPaletteColor(index, hex) - dynamically set any of the 256 palette colors (OSC 4)
  • Added setForeground(hex) - set terminal default foreground color (OSC 10)
  • Added setBackground(hex) - set terminal default background color (OSC 11)
  • Added setCursorColor(hex) - set cursor color (OSC 12)
  • Added resetPaletteColor(index) - reset palette color to terminal default (OSC 104)
  • Added resetForeground() - reset foreground to default (OSC 110)
  • Added resetBackground() - reset background to default (OSC 111)
  • Added resetCursorColor() - reset cursor color to default (OSC 112)

Zig (ansi.zig)

  • Added ColorType enum: rgb, indexed, default
  • Added Color struct combining RGBA with type and index
  • Added indexToApproximateRgba(), fgIndexedColorOutput(), bgIndexedColorOutput()
  • Added fgDefaultOutput(), bgDefaultOutput() for default color reset

Zig (buffer.zig)

  • Extended Cell struct with fg_color_type, bg_color_type, fg_index, bg_index
  • Added corresponding arrays to OptimizedBuffer
  • Updated all buffer operations to handle color types

Zig (renderer.zig)

  • Updated color output to check cell color type
  • Outputs \x1b[38;5;Nm / \x1b[48;5;Nm for indexed colors
  • Outputs \x1b[39m / \x1b[49m for default colors
  • Falls back to RGB for rgb color type

Usage Examples

Indexed Colors

import { parseColor, RGBA } from "@opentui/core"

// Various ways to specify indexed colors
parseColor("ansi:196")      // String format (bright red)
parseColor(46)              // Numeric (green)
parseColor({ index: 226 })  // Object (yellow)
RGBA.fromIndex(21)          // Direct method (blue)

// Check color type
const color = parseColor("ansi:196")
color.isIndexed()  // true
color.index        // 196

OSC Palette Control

// Dynamically modify terminal colors
paletteDetector.setPaletteColor(1, "#ff5555")  // Change color 1 to custom red
paletteDetector.setBackground("#1a1a2e")       // Set terminal background
paletteDetector.setForeground("#eaeaea")       // Set terminal foreground
paletteDetector.setCursorColor("#ff79c6")      // Set cursor color

// Reset to terminal defaults
paletteDetector.resetPaletteColor(1)           // Reset color 1
paletteDetector.resetBackground()              // Reset background
paletteDetector.resetForeground()              // Reset foreground

Testing

  • All 3057 existing tests pass
  • Build completes successfully

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/anomalyco/opentui/pull/559 **Author:** [@bresilla](https://github.com/bresilla) **Created:** 1/20/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat/indexed-colors` --- ### 📝 Commits (8) - [`e14abda`](https://github.com/anomalyco/opentui/commit/e14abdadc636b105663ecb34eb015344cec44435) feat: Add 256-color palette and metadata to RGBA - [`ec7cf26`](https://github.com/anomalyco/opentui/commit/ec7cf2606199be7fa2e1bf988d560972a28b529a) feat: Add RGB_META field to RGBA type - [`4cacd74`](https://github.com/anomalyco/opentui/commit/4cacd74d5d7534e410934874fea68a37ac71101a) feat: enable indexed colors and RGB_META in RGBA struct - [`225ef4f`](https://github.com/anomalyco/opentui/commit/225ef4f4fe64f5dd844d8d3e5988cc210a63b954) feat: adjust test for the new [5]th float - [`01758a1`](https://github.com/anomalyco/opentui/commit/01758a18636a575d899bf5503f28d6206aff9f41) fix: Add `meta` field to `ExternalCursorState` - [`73eebd8`](https://github.com/anomalyco/opentui/commit/73eebd8743ea5d942c7432b64840a478bc07ff73) feat: Add support for indexed colors in RGBA in TS side - [`b8f6e6c`](https://github.com/anomalyco/opentui/commit/b8f6e6c709aeff50ab5c365949a63ffd77af41e7) test: add ANSI 256 color showcase example - [`d98b815`](https://github.com/anomalyco/opentui/commit/d98b815c2cd453ab732f44191af6f696b10f42a9) fix: Use 16-color ANSI escape codes for indexed colors 0-15 in renderer ### 📊 Changes **30 files changed** (+869 additions, -448 deletions) <details> <summary>View changed files</summary> 📝 `packages/core/src/buffer.ts` (+4 -4) ➕ `packages/core/src/examples/terminal_ansi.ts` (+197 -0) 📝 `packages/core/src/lib/RGBA.test.ts` (+9 -2) 📝 `packages/core/src/lib/RGBA.ts` (+74 -4) 📝 `packages/core/src/post/filters.ts` (+28 -28) 📝 `packages/core/src/renderables/Text.selection-buffer.test.ts` (+4 -4) 📝 `packages/core/src/renderables/Text.test.ts` (+6 -6) 📝 `packages/core/src/renderables/TextTable.test.ts` (+2 -2) 📝 `packages/core/src/renderables/__tests__/LineNumberRenderable.test.ts` (+10 -10) 📝 `packages/core/src/renderables/__tests__/Textarea.scroll.test.ts` (+1 -1) 📝 `packages/core/src/renderables/__tests__/Textarea.selection.test.ts` (+17 -17) 📝 `packages/core/src/testing/test-recorder.test.ts` (+2 -2) 📝 `packages/core/src/zig-structs.ts` (+2 -1) 📝 `packages/core/src/zig.ts` (+1 -1) 📝 `packages/core/src/zig/ansi.zig` (+124 -2) 📝 `packages/core/src/zig/bench/buffer-draw-text-buffer_bench.zig` (+15 -15) 📝 `packages/core/src/zig/bench/styled-text_bench.zig` (+18 -18) 📝 `packages/core/src/zig/buffer.zig` (+39 -32) 📝 `packages/core/src/zig/lib.zig` (+2 -0) 📝 `packages/core/src/zig/renderer.zig` (+38 -23) _...and 10 more files_ </details> ### 📄 Description ## Summary Adds full support for terminal indexed colors (0-255) and OSC-based terminal palette control, enabling the use of the standard 256-color palette and dynamic color modification via ANSI/OSC escape sequences. Makes this possible (with tools like pywal et al): ![ezgif-54dccc5a972ae0ee](https://github.com/user-attachments/assets/1a554499-b04f-40ec-91bf-a5b3fbaaedaf) ## Changes ### TypeScript (RGBA.ts) - Added `COLOR_TYPE_RGB`, `COLOR_TYPE_INDEXED`, `COLOR_TYPE_DEFAULT` constants - Extended `RGBA` class with `colorType`, `index` properties - Added `RGBA.fromIndex(index)`, `RGBA.defaultForeground()`, `RGBA.defaultBackground()` static methods - Added `isIndexed()`, `isDefault()`, `isRgb()` instance methods - Added `indexToApproximateRgb()` function with standard 256-color palette mapping - Extended `ColorInput` type to accept `string | RGBA | IndexedColor | number` - Updated `parseColor()` to handle `"ansi:N"` format, numeric indices, and `{index: N}` objects ### TypeScript (terminal-palette.ts) - OSC Palette Control - Added `setPaletteColor(index, hex)` - dynamically set any of the 256 palette colors (OSC 4) - Added `setForeground(hex)` - set terminal default foreground color (OSC 10) - Added `setBackground(hex)` - set terminal default background color (OSC 11) - Added `setCursorColor(hex)` - set cursor color (OSC 12) - Added `resetPaletteColor(index)` - reset palette color to terminal default (OSC 104) - Added `resetForeground()` - reset foreground to default (OSC 110) - Added `resetBackground()` - reset background to default (OSC 111) - Added `resetCursorColor()` - reset cursor color to default (OSC 112) ### Zig (ansi.zig) - Added `ColorType` enum: `rgb`, `indexed`, `default` - Added `Color` struct combining RGBA with type and index - Added `indexToApproximateRgba()`, `fgIndexedColorOutput()`, `bgIndexedColorOutput()` - Added `fgDefaultOutput()`, `bgDefaultOutput()` for default color reset ### Zig (buffer.zig) - Extended `Cell` struct with `fg_color_type`, `bg_color_type`, `fg_index`, `bg_index` - Added corresponding arrays to `OptimizedBuffer` - Updated all buffer operations to handle color types ### Zig (renderer.zig) - Updated color output to check cell color type - Outputs `\x1b[38;5;Nm` / `\x1b[48;5;Nm` for indexed colors - Outputs `\x1b[39m` / `\x1b[49m` for default colors - Falls back to RGB for rgb color type ## Usage Examples ### Indexed Colors ```typescript import { parseColor, RGBA } from "@opentui/core" // Various ways to specify indexed colors parseColor("ansi:196") // String format (bright red) parseColor(46) // Numeric (green) parseColor({ index: 226 }) // Object (yellow) RGBA.fromIndex(21) // Direct method (blue) // Check color type const color = parseColor("ansi:196") color.isIndexed() // true color.index // 196 ``` ### OSC Palette Control ```typescript // Dynamically modify terminal colors paletteDetector.setPaletteColor(1, "#ff5555") // Change color 1 to custom red paletteDetector.setBackground("#1a1a2e") // Set terminal background paletteDetector.setForeground("#eaeaea") // Set terminal foreground paletteDetector.setCursorColor("#ff79c6") // Set cursor color // Reset to terminal defaults paletteDetector.resetPaletteColor(1) // Reset color 1 paletteDetector.resetBackground() // Reset background paletteDetector.resetForeground() // Reset foreground ``` ## Testing - All 3057 existing tests pass - Build completes successfully --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/opentui#1399
No description provided.