summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ansi.rs119
-rw-r--r--src/config.rs81
-rw-r--r--src/main.rs2
-rw-r--r--src/renderer/mod.rs37
-rw-r--r--src/term/cell.rs11
-rw-r--r--src/term/mod.rs32
-rw-r--r--tests/ref.rs3
-rw-r--r--tests/ref/indexed_256_colors/alacritty.recording15
-rw-r--r--tests/ref/indexed_256_colors/grid.json1
-rw-r--r--tests/ref/indexed_256_colors/size.json1
-rw-r--r--tests/ref/ll/grid.json2
-rw-r--r--tests/ref/tmux_git_log/grid.json2
-rw-r--r--tests/ref/tmux_htop/grid.json2
-rw-r--r--tests/ref/vim_large_window_scroll/grid.json2
-rw-r--r--tests/ref/vim_simple_edit/grid.json2
15 files changed, 187 insertions, 125 deletions
diff --git a/src/ansi.rs b/src/ansi.rs
index 32c7751d..089bc277 100644
--- a/src/ansi.rs
+++ b/src/ansi.rs
@@ -310,7 +310,7 @@ pub enum TabulationClearMode {
/// The order here matters since the enum should be castable to a `usize` for
/// indexing a color list.
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
-pub enum Color {
+pub enum NamedColor {
/// Black
Black = 0,
/// Red
@@ -344,11 +344,18 @@ pub enum Color {
/// Bright white
BrightWhite,
/// The foreground color
- Foreground,
+ Foreground = 256,
/// The background color
Background,
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
+pub enum Color {
+ Named(NamedColor),
+ Spec(Rgb),
+ Indexed(u8),
+}
+
/// Terminal character attributes
#[derive(Debug, Eq, PartialEq)]
pub enum Attr {
@@ -388,12 +395,8 @@ pub enum Attr {
CancelStrike,
/// Set indexed foreground color
Foreground(Color),
- /// Set specific foreground color
- ForegroundSpec(Rgb),
/// Set indexed background color
Background(Color),
- /// Set specific background color
- BackgroundSpec(Rgb),
}
impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
@@ -575,54 +578,54 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
27 => Attr::CancelReverse,
28 => Attr::CancelHidden,
29 => Attr::CancelStrike,
- 30 => Attr::Foreground(Color::Black),
- 31 => Attr::Foreground(Color::Red),
- 32 => Attr::Foreground(Color::Green),
- 33 => Attr::Foreground(Color::Yellow),
- 34 => Attr::Foreground(Color::Blue),
- 35 => Attr::Foreground(Color::Magenta),
- 36 => Attr::Foreground(Color::Cyan),
- 37 => Attr::Foreground(Color::White),
+ 30 => Attr::Foreground(Color::Named(NamedColor::Black)),
+ 31 => Attr::Foreground(Color::Named(NamedColor::Red)),
+ 32 => Attr::Foreground(Color::Named(NamedColor::Green)),
+ 33 => Attr::Foreground(Color::Named(NamedColor::Yellow)),
+ 34 => Attr::Foreground(Color::Named(NamedColor::Blue)),
+ 35 => Attr::Foreground(Color::Named(NamedColor::Magenta)),
+ 36 => Attr::Foreground(Color::Named(NamedColor::Cyan)),
+ 37 => Attr::Foreground(Color::Named(NamedColor::White)),
38 => {
- if let Some(spec) = parse_color(&args[i..], &mut i) {
- Attr::ForegroundSpec(spec)
+ if let Some(color) = parse_color(&args[i..], &mut i) {
+ Attr::Foreground(color)
} else {
break;
}
},
- 39 => Attr::Foreground(Color::Foreground),
- 40 => Attr::Background(Color::Black),
- 41 => Attr::Background(Color::Red),
- 42 => Attr::Background(Color::Green),
- 43 => Attr::Background(Color::Yellow),
- 44 => Attr::Background(Color::Blue),
- 45 => Attr::Background(Color::Magenta),
- 46 => Attr::Background(Color::Cyan),
- 47 => Attr::Background(Color::White),
+ 39 => Attr::Foreground(Color::Named(NamedColor::Foreground)),
+ 40 => Attr::Background(Color::Named(NamedColor::Black)),
+ 41 => Attr::Background(Color::Named(NamedColor::Red)),
+ 42 => Attr::Background(Color::Named(NamedColor::Green)),
+ 43 => Attr::Background(Color::Named(NamedColor::Yellow)),
+ 44 => Attr::Background(Color::Named(NamedColor::Blue)),
+ 45 => Attr::Background(Color::Named(NamedColor::Magenta)),
+ 46 => Attr::Background(Color::Named(NamedColor::Cyan)),
+ 47 => Attr::Background(Color::Named(NamedColor::White)),
48 => {
- if let Some(spec) = parse_color(&args[i..], &mut i) {
- Attr::BackgroundSpec(spec)
+ if let Some(color) = parse_color(&args[i..], &mut i) {
+ Attr::Background(color)
} else {
break;
}
},
- 49 => Attr::Background(Color::Background),
- 90 => Attr::Foreground(Color::BrightBlack),
- 91 => Attr::Foreground(Color::BrightRed),
- 92 => Attr::Foreground(Color::BrightGreen),
- 93 => Attr::Foreground(Color::BrightYellow),
- 94 => Attr::Foreground(Color::BrightBlue),
- 95 => Attr::Foreground(Color::BrightMagenta),
- 96 => Attr::Foreground(Color::BrightCyan),
- 97 => Attr::Foreground(Color::BrightWhite),
- 100 => Attr::Foreground(Color::BrightBlack),
- 101 => Attr::Foreground(Color::BrightRed),
- 102 => Attr::Foreground(Color::BrightGreen),
- 103 => Attr::Foreground(Color::BrightYellow),
- 104 => Attr::Foreground(Color::BrightBlue),
- 105 => Attr::Foreground(Color::BrightMagenta),
- 106 => Attr::Foreground(Color::BrightCyan),
- 107 => Attr::Foreground(Color::BrightWhite),
+ 49 => Attr::Background(Color::Named(NamedColor::Background)),
+ 90 => Attr::Foreground(Color::Named(NamedColor::BrightBlack)),
+ 91 => Attr::Foreground(Color::Named(NamedColor::BrightRed)),
+ 92 => Attr::Foreground(Color::Named(NamedColor::BrightGreen)),
+ 93 => Attr::Foreground(Color::Named(NamedColor::BrightYellow)),
+ 94 => Attr::Foreground(Color::Named(NamedColor::BrightBlue)),
+ 95 => Attr::Foreground(Color::Named(NamedColor::BrightMagenta)),
+ 96 => Attr::Foreground(Color::Named(NamedColor::BrightCyan)),
+ 97 => Attr::Foreground(Color::Named(NamedColor::BrightWhite)),
+ 100 => Attr::Foreground(Color::Named(NamedColor::BrightBlack)),
+ 101 => Attr::Foreground(Color::Named(NamedColor::BrightRed)),
+ 102 => Attr::Foreground(Color::Named(NamedColor::BrightGreen)),
+ 103 => Attr::Foreground(Color::Named(NamedColor::BrightYellow)),
+ 104 => Attr::Foreground(Color::Named(NamedColor::BrightBlue)),
+ 105 => Attr::Foreground(Color::Named(NamedColor::BrightMagenta)),
+ 106 => Attr::Foreground(Color::Named(NamedColor::BrightCyan)),
+ 107 => Attr::Foreground(Color::Named(NamedColor::BrightWhite)),
_ => unhandled!(),
};
@@ -674,7 +677,7 @@ impl<'a, H: Handler + TermInfo + 'a> vte::Perform for Performer<'a, H> {
/// Parse a color specifier from list of attributes
-fn parse_color(attrs: &[i64], i: &mut usize) -> Option<Rgb> {
+fn parse_color(attrs: &[i64], i: &mut usize) -> Option<Color> {
if attrs.len() < 2 {
return None;
}
@@ -699,11 +702,29 @@ fn parse_color(attrs: &[i64], i: &mut usize) -> Option<Rgb> {
return None;
}
- Some(Rgb {
+ Some(Color::Spec(Rgb {
r: r as u8,
g: g as u8,
b: b as u8
- })
+ }))
+ },
+ 5 => {
+ if attrs.len() < 3 {
+ err_println!("Expected color index; got {:?}", attrs);
+ None
+ } else {
+ *i = *i + 2;
+ let idx = attrs[*i];
+ match idx {
+ 0 ... 255 => {
+ Some(Color::Indexed(idx as u8))
+ },
+ _ => {
+ err_println!("Invalid color index: {}", idx);
+ None
+ }
+ }
+ }
},
_ => {
err_println!("Unexpected color attr: {}", attrs[*i+1]);
@@ -863,7 +884,7 @@ pub mod C1 {
#[cfg(test)]
mod tests {
use index::{Line, Column};
- use super::{Processor, Handler, Attr, TermInfo};
+ use super::{Processor, Handler, Attr, TermInfo, Color};
use ::Rgb;
#[derive(Default)]
@@ -923,7 +944,7 @@ mod tests {
b: 255
};
- assert_eq!(handler.attr, Some(Attr::ForegroundSpec(spec)));
+ assert_eq!(handler.attr, Some(Attr::Foreground(Color::Spec(spec))));
}
/// No exactly a test; useful for debugging
diff --git a/src/config.rs b/src/config.rs
index 8ab6e662..60887720 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -665,34 +665,59 @@ impl Config {
///
/// The ordering returned here is expected by the terminal. Colors are simply indexed in this
/// array for performance.
- pub fn color_list(&self) -> [Rgb; 18] {
- let colors = &self.colors;
-
- [
- // Normals
- colors.normal.black,
- colors.normal.red,
- colors.normal.green,
- colors.normal.yellow,
- colors.normal.blue,
- colors.normal.magenta,
- colors.normal.cyan,
- colors.normal.white,
-
- // Brights
- colors.bright.black,
- colors.bright.red,
- colors.bright.green,
- colors.bright.yellow,
- colors.bright.blue,
- colors.bright.magenta,
- colors.bright.cyan,
- colors.bright.white,
-
- // Foreground and background
- colors.primary.foreground,
- colors.primary.background,
- ]
+ pub fn color_list(&self) -> Vec<Rgb> {
+ let mut colors = Vec::with_capacity(258);
+
+ // Normals
+ colors.push(self.colors.normal.black);
+ colors.push(self.colors.normal.red);
+ colors.push(self.colors.normal.green);
+ colors.push(self.colors.normal.yellow);
+ colors.push(self.colors.normal.blue);
+ colors.push(self.colors.normal.magenta);
+ colors.push(self.colors.normal.cyan);
+ colors.push(self.colors.normal.white);
+
+ // Brights
+ colors.push(self.colors.bright.black);
+ colors.push(self.colors.bright.red);
+ colors.push(self.colors.bright.green);
+ colors.push(self.colors.bright.yellow);
+ colors.push(self.colors.bright.blue);
+ colors.push(self.colors.bright.magenta);
+ colors.push(self.colors.bright.cyan);
+ colors.push(self.colors.bright.white);
+
+ // Build colors
+ for r in 0..6 {
+ for g in 0..6 {
+ for b in 0..6 {
+ colors.push(Rgb {
+ r: if r == 0 { 0 } else { r * 40 + 55 },
+ b: if b == 0 { 0 } else { b * 40 + 55 },
+ g: if g == 0 { 0 } else { g * 40 + 55 },
+ });
+ }
+ }
+ }
+
+ // Build grays
+ for i in 0..24 {
+ let value = i * 10 + 8;
+ colors.push(Rgb {
+ r: value,
+ g: value,
+ b: value
+ });
+ }
+
+ debug_assert!(colors.len() == 256);
+
+ // Foreground and background
+ colors.push(self.colors.primary.foreground);
+ colors.push(self.colors.primary.background);
+
+ colors
}
pub fn key_bindings(&self) -> &[KeyBinding] {
diff --git a/src/main.rs b/src/main.rs
index 04b269e3..f25c2111 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -371,7 +371,7 @@ impl Display {
// Draw render timer
if self.render_timer {
let timing = format!("{:.3} usec", self.meter.average());
- let color = alacritty::term::cell::Color::Rgb(Rgb { r: 0xd5, g: 0x4e, b: 0x53 });
+ let color = alacritty::ansi::Color::Spec(Rgb { r: 0xd5, g: 0x4e, b: 0x53 });
self.renderer.with_api(terminal.size_info(), |mut api| {
api.render_string(&timing[..], glyph_cache, &color);
});
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index 5f3fbfc7..2073be30 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -26,6 +26,8 @@ use gl;
use notify::{Watcher as WatcherApi, RecommendedWatcher as Watcher, op};
use index::{Line, Column};
+use ansi::{Color, NamedColor};
+
use config::Config;
use term::{self, cell, IndexedCell, Cell};
@@ -241,7 +243,7 @@ pub struct QuadRenderer {
atlas: Vec<Atlas>,
active_tex: GLuint,
batch: Batch,
- colors: [Rgb; 18],
+ colors: Vec<Rgb>,
draw_bold_text_with_bright_colors: bool,
rx: mpsc::Receiver<Msg>,
}
@@ -252,7 +254,7 @@ pub struct RenderApi<'a> {
batch: &'a mut Batch,
atlas: &'a mut Vec<Atlas>,
program: &'a mut ShaderProgram,
- colors: &'a [Rgb; 18],
+ colors: &'a [Rgb],
}
#[derive(Debug)]
@@ -271,7 +273,7 @@ pub struct PackedVertex {
pub struct Batch {
tex: GLuint,
instances: Vec<InstanceData>,
- colors: [Rgb; 18],
+ colors: Vec<Rgb>,
draw_bold_text_with_bright_colors: bool,
}
@@ -292,22 +294,35 @@ impl Batch {
}
let fg = match cell.fg {
- ::term::cell::Color::Rgb(rgb) => rgb,
- ::term::cell::Color::Ansi(ansi) => {
+ Color::Spec(rgb) => rgb,
+ Color::Named(ansi) => {
if self.draw_bold_text_with_bright_colors
&& cell.bold()
- && ansi < ::ansi::Color::BrightBlack
+ && ansi < NamedColor::BrightBlack
{
self.colors[ansi as usize + 8]
} else {
self.colors[ansi as usize]
}
+ },
+ Color::Indexed(idx) => {
+ let idx = if self.draw_bold_text_with_bright_colors
+ && cell.bold()
+ && idx < 8
+ {
+ idx + 8
+ } else {
+ idx
+ };
+
+ self.colors[idx as usize]
}
};
let bg = match cell.bg {
- ::term::cell::Color::Rgb(rgb) => rgb,
- ::term::cell::Color::Ansi(ansi) => self.colors[ansi as usize],
+ Color::Spec(rgb) => rgb,
+ Color::Named(ansi) => self.colors[ansi as usize],
+ Color::Indexed(idx) => self.colors[idx as usize],
};
self.instances.push(InstanceData {
@@ -620,7 +635,7 @@ impl QuadRenderer {
impl<'a> RenderApi<'a> {
pub fn clear(&self) {
- let color = self.colors[::ansi::Color::Background as usize];
+ let color = self.colors[NamedColor::Background as usize];
unsafe {
gl::ClearColor(
color.r as f32 / 255.0,
@@ -666,7 +681,7 @@ impl<'a> RenderApi<'a> {
&mut self,
string: &str,
glyph_cache: &mut GlyphCache,
- color: &::term::cell::Color,
+ color: &Color,
) {
let line = Line(23);
let col = Column(0);
@@ -679,7 +694,7 @@ impl<'a> RenderApi<'a> {
inner: Cell {
c: c,
bg: *color,
- fg: cell::Color::Rgb(Rgb { r: 0, g: 0, b: 0}),
+ fg: Color::Spec(Rgb { r: 0, g: 0, b: 0}),
flags: cell::Flags::empty(),
}
})
diff --git a/src/term/cell.rs b/src/term/cell.rs
index 506fde0e..df648294 100644
--- a/src/term/cell.rs
+++ b/src/term/cell.rs
@@ -15,8 +15,7 @@
use std::mem;
-use ansi;
-use Rgb;
+use ansi::{NamedColor, Color};
bitflags! {
#[derive(Serialize, Deserialize)]
@@ -28,12 +27,6 @@ bitflags! {
}
}
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
-pub enum Color {
- Rgb(Rgb),
- Ansi(ansi::Color),
-}
-
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct Cell {
pub c: char,
@@ -59,7 +52,7 @@ impl Cell {
#[inline]
pub fn is_empty(&self) -> bool {
self.c == ' ' &&
- self.bg == Color::Ansi(ansi::Color::Background) &&
+ self.bg == Color::Named(NamedColor::Background) &&
!self.flags.contains(INVERSE)
}
diff --git a/src/term/mod.rs b/src/term/mod.rs
index acbb70ac..9ed19c81 100644
--- a/src/term/mod.rs
+++ b/src/term/mod.rs
@@ -20,7 +20,7 @@ use std::cmp;
use ansi::{self, Attr, Handler};
use grid::{Grid, ClearRegion};
use index::{Cursor, Column, Line};
-use ansi::Color;
+use ansi::{Color, NamedColor};
pub mod cell;
pub use self::cell::Cell;
@@ -250,8 +250,8 @@ impl Term {
pub fn new(size: SizeInfo) -> Term {
let template = Cell::new(
' ',
- cell::Color::Ansi(Color::Foreground),
- cell::Color::Ansi(Color::Background)
+ Color::Named(NamedColor::Foreground),
+ Color::Named(NamedColor::Background)
);
let num_cols = size.cols();
@@ -800,21 +800,11 @@ impl ansi::Handler for Term {
fn terminal_attribute(&mut self, attr: Attr) {
debug_println!("Set Attribute: {:?}", attr);
match attr {
- Attr::Foreground(named_color) => {
- self.template_cell.fg = cell::Color::Ansi(named_color);
- },
- Attr::Background(named_color) => {
- self.template_cell.bg = cell::Color::Ansi(named_color);
- },
- Attr::ForegroundSpec(rgb) => {
- self.template_cell.fg = cell::Color::Rgb(rgb);
- },
- Attr::BackgroundSpec(rgb) => {
- self.template_cell.bg = cell::Color::Rgb(rgb);
- },
+ Attr::Foreground(color) => self.template_cell.fg = color,
+ Attr::Background(color) => self.template_cell.bg = color,
Attr::Reset => {
- self.template_cell.fg = cell::Color::Ansi(Color::Foreground);
- self.template_cell.bg = cell::Color::Ansi(Color::Background);
+ self.template_cell.fg = Color::Named(NamedColor::Foreground);
+ self.template_cell.bg = Color::Named(NamedColor::Background);
self.template_cell.flags = cell::Flags::empty();
},
Attr::Reverse => self.template_cell.flags.insert(cell::INVERSE),
@@ -888,10 +878,10 @@ mod tests {
use super::limit;
- use ansi::{Color};
+ use ansi::{Color, NamedColor};
use grid::Grid;
use index::{Line, Column};
- use term::{cell, Cell};
+ use term::{Cell};
/// Check that the grid can be serialized back and forth losslessly
///
@@ -901,8 +891,8 @@ mod tests {
fn grid_serde() {
let template = Cell::new(
' ',
- cell::Color::Ansi(Color::Foreground),
- cell::Color::Ansi(Color::Background)
+ Color::Named(NamedColor::Foreground),
+ Color::Named(NamedColor::Background)
);
let grid = Grid::new(Line(24), Column(80), &template);
diff --git a/tests/ref.rs b/tests/ref.rs
index a92da05f..2859dba1 100644
--- a/tests/ref.rs
+++ b/tests/ref.rs
@@ -79,6 +79,7 @@ mod reference {
vim_simple_edit,
tmux_htop,
tmux_git_log,
- vim_large_window_scroll
+ vim_large_window_scroll,
+ indexed_256_colors
}
}
diff --git a/tests/ref/indexed_256_colors/alacritty.recording b/tests/ref/indexed_256_colors/alacritty.recording
new file mode 100644
index 00000000..6f2fb459
--- /dev/null
+++ b/tests/ref/indexed_256_colors/alacritty.recording
@@ -0,0 +1,15 @@
+% jwilm@kurast.local ➜  ~/code/alacritty  [?1h=[?2004h.././ccoolloorrss..p./colors.pl[?1l>[?2004l
+]4;16;rgb:00/00/00\]4;17;rgb:00/00/5f\]4;18;rgb:00/00/87\]4;19;rgb:00/00/af\]4;20;rgb:00/00/d7\]4;21;rgb:00/00/ff\]4;22;rgb:00/5f/00\]4;23;rgb:00/5f/5f\]4;24;rgb:00/5f/87\]4;25;rgb:00/5f/af\]4;26;rgb:00/5f/d7\]4;27;rgb:00/5f/ff\]4;28;rgb:00/87/00\]4;29;rgb:00/87/5f\]4;30;rgb:00/87/87\]4;31;rgb:00/87/af\]4;32;rgb:00/87/d7\]4;33;rgb:00/87/ff\]4;34;rgb:00/af/00\]4;35;rgb:00/af/5f\]4;36;rgb:00/af/87\]4;37;rgb:00/af/af\]4;38;rgb:00/af/d7\]4;39;rgb:00/af/ff\]4;40;rgb:00/d7/00\]4;41;rgb:00/d7/5f\]4;42;rgb:00/d7/87\]4;43;rgb:00/d7/af\]4;44;rgb:00/d7/d7\]4;45;rgb:00/d7/ff\]4;46;rgb:00/ff/00\]4;47;rgb:00/ff/5f\]4;48;rgb:00/ff/87\]4;49;rgb:00/ff/af\]4;50;rgb:00/ff/d7\]4;51;rgb:00/ff/ff\]4;52;rgb:5f/00/00\]4;53;rgb:5f/00/5f\]4;54;rgb:5f/00/87\]4;55;rgb:5f/00/af\]4;56;rgb:5f/00/d7\]4;57;rgb:5f/00/ff\]4;58;rgb:5f/5f/00\]4;59;rgb:5f/5f/5f\]4;60;rgb:5f/5f/87\]4;61;rgb:5f/5f/af\]4;62;rgb:5f/5f/d7\]4;63;rgb:5f/5f/ff\]4;64;rgb:5f/87/00\]4;65;rgb:5f/87/5f\]4;66;rgb:5f/87/87\]4;67;rgb:5f/87/af\]4;68;rgb:5f/87/d7\]4;69;rgb:5f/87/ff\]4;70;rgb:5f/af/00\]4;71;rgb:5f/af/5f\]4;72;rgb:5f/af/87\]4;73;rgb:5f/af/af\]4;74;rgb:5f/af/d7\]4;75;rgb:5f/af/ff\]4;76;rgb:5f/d7/00\]4;77;rgb:5f/d7/5f\]4;78;rgb:5f/d7/87\]4;79;rgb:5f/d7/af\]4;80;rgb:5f/d7/d7\]4;81;rgb:5f/d7/ff\]4;82;rgb:5f/ff/00\]4;83;rgb:5f/ff/5f\]4;84;rgb:5f/ff/87\]4;85;rgb:5f/ff/af\]4;86;rgb:5f/ff/d7\]4;87;rgb:5f/ff/ff\]4;88;rgb:87/00/00\]4;89;rgb:87/00/5f\]4;90;rgb:87/00/87\]4;91;rgb:87/00/af\]4;92;rgb:87/00/d7\]4;93;rgb:87/00/ff\]4;94;rgb:87/5f/00\]4;95;rgb:87/5f/5f\]4;96;rgb:87/5f/87\]4;97;rgb:87/5f/af\]4;98;rgb:87/5f/d7\]4;99;rgb:87/5f/ff\]4;100;rgb:87/87/00\]4;101;rgb:87/87/5f\]4;102;rgb:87/87/87\]4;103;rgb:87/87/af\]4;104;rgb:87/87/d7\]4;105;rgb:87/87/ff\]4;106;rgb:87/af/00\]4;107;rgb:87/af/5f\]4;108;rgb:87/af/87\]4;109;rgb:87/af/af\]4;110;rgb:87/af/d7\]4;111;rgb:87/af/ff\]4;112;rgb:87/d7/00\]4;113;rgb:87/d7/5f\]4;114;rgb:87/d7/87\]4;115;rgb:87/d7/af\]4;116;rgb:87/d7/d7\]4;117;rgb:87/d7/ff\]4;118;rgb:87/ff/00\]4;119;rgb:87/ff/5f\]4;120;rgb:87/ff/87\]4;121;rgb:87/ff/af\]4;122;rgb:87/ff/d7\]4;123;rgb:87/ff/ff\]4;124;rgb:af/00/00\]4;125;rgb:af/00/5f\]4;126;rgb:af/00/87\]4;127;rgb:af/00/af\]4;128;rgb:af/00/d7\]4;129;rgb:af/00/ff\]4;130;rgb:af/5f/00\]4;131;rgb:af/5f/5f\]4;132;rgb:af/5f/87\]4;133;rgb:af/5f/af\]4;134;rgb:af/5f/d7\]4;135;rgb:af/5f/ff\]4;136;rgb:af/87/00\]4;137;rgb:af/87/5f\]4;138;rgb:af/87/87\]4;139;rgb:af/87/af\]4;140;rgb:af/87/d7\]4;141;rgb:af/87/ff\]4;142;rgb:af/af/00\]4;143;rgb:af/af/5f\]4;144;rgb:af/af/87\]4;145;rgb:af/af/af\]4;146;rgb:af/af/d7\]4;147;rgb:af/af/ff\]4;148;rgb:af/d7/00\]4;149;rgb:af/d7/5f\]4;150;rgb:af/d7/87\]4;151;rgb:af/d7/af\]4;152;rgb:af/d7/d7\]4;153;rgb:af/d7/ff\]4;154;rgb:af/ff/00\]4;155;rgb:af/ff/5f\]4;156;rgb:af/ff/87\]4;157;rgb:af/ff/af\]4;158;rgb:af/ff/d7\]4;159;rgb:af/ff/ff\]4;160;rgb:d7/00/00\]4;161;rgb:d7/00/5f\]4;162;rgb:d7/00/87\]4;163;rgb:d7/00/af\]4;164;rgb:d7/00/d7\]4;165;rgb:d7/00/ff\]4;166;rgb:d7/5f/00\]4;167;rgb:d7/5f/5f\]4;168;rgb:d7/5f/87\]4;169;rgb:d7/5f/af\]4;170;rgb:d7/5f/d7\]4;171;rgb:d7/5f/ff\]4;172;rgb:d7/87/00\]4;173;rgb:d7/87/5f\]4;174;rgb:d7/87/87\]4;175;rgb:d7/87/af\]4;176;rgb:d7/87/d7\]4;177;rgb:d7/87/ff\]4;178;rgb:d7/af/00\]4;179;rgb:d7/af/5f\]4;180;rgb:d7/af/87\]4;181;rgb:d7/af/af\]4;182;rgb:d7/af/d7\]4;183;rgb:d7/af/ff\]4;184;rgb:d7/d7/00\]4;185;rgb:d7/d7/5f\]4;186;rgb:d7/d7/87\]4;187;rgb:d7/d7/af\]4;188;rgb:d7/d7/d7\]4;189;rgb:d7/d7/ff\]4;190;rgb:d7/ff/00\]4;191;rgb:d7/ff/5f\]4;192;rgb:d7/ff/87\]4;193;rgb:d7/ff/af\]4;194;rgb:d7/ff/d7\]4;195;rgb:d7/ff/ff\]4;196;rgb:ff/00/00\]4;197;rgb:ff/00/5f\]4;198;rgb:ff/00/87\]4;199;rgb:ff/00/af\]4;200;rgb:ff/00/d7\]4;201;rgb:ff/00/ff\]4;202;rgb:ff/5f/00\]4;203;rgb:ff/5f/5f\]4;204;rgb:ff/5f/87\]4;205;rgb:ff/5f/af\]4;206;rgb:ff/5f/d7\]4;207;rgb:ff/5f/ff\]4;208;rgb:ff/87/00\]4;209;rgb:ff/87/5f\]4;210;rgb:ff/87/87\]4;211;rgb:ff/87/af\]4;212;rgb:ff/87/d7\]4;213;rgb:ff/87/ff\]4;214;rgb:ff/af/00\]4;215;rgb:ff/af/5f\]4;216;rgb:ff/af/87\]4;217;rgb:ff/af/af\]4;218;rgb:ff/af/d7\]4;219;rgb:ff/af/ff\]4;220;rgb:ff/d7/00\]4;221;rgb:ff/d7/5f\]4;222;rgb:ff/d7/87\]4;223;rgb:ff/d7/af\]4;224;rgb:ff/d7/d7\]4;225;rgb:ff/d7/ff\]4;226;rgb:ff/ff/00\]4;227;rgb:ff/ff/5f\]4;228;rgb:ff/ff/87\]4;229;rgb:ff/ff/af\]4;230;rgb:ff/ff/d7\]4;231;rgb:ff/ff/ff\]4;232;rgb:08/08/08\]4;233;rgb:12/12/12\]4;234;rgb:1c/1c/1c\]4;235;rgb:26/26/26\]4;236;rgb:30/30/30\]4;237;rgb:3a/3a/3a\]4;238;rgb:44/44/44\]4;239;rgb:4e/4e/4e\]4;240;rgb:58/58/58\]4;241;rgb:62/62/62\]4;242;rgb:6c/6c/6c\]4;243;rgb:76/76/76\]4;244;rgb:80/80/80\]4;245;rgb:8a/8a/8a\]4;246;rgb:94/94/94\]4;247;rgb:9e/9e/9e\]4;248;rgb:a8/a8/a8\]4;249;rgb:b2/b2/b2\]4;250;rgb:bc/bc/bc\]4;251;rgb:c6/c6/c6\]4;252;rgb:d0/d0/d0\]4;253;rgb:da/da/da\]4;254;rgb:e4/e4/e4\]4;255;rgb:ee/ee/ee\System colors:
+        
+        
+
+Color cube, 6x6x6:
+                                         
+                                         
+                                         
+                                         
+                                         
+                                         
+Grayscale ramp:
+                        
+% jwilm@kurast.local ➜  ~/code/alacritty  [?1h=[?2004h \ No newline at end of file
diff --git a/tests/ref/indexed_256_colors/grid.json b/tests/ref/indexed_256_colors/grid.json
new file mode 100644
index 00000000..d03957d8
--- /dev/null
+++ b/tests/ref/indexed_256_colors/grid.json
@@ -0,0 +1 @@
+{"raw":[[{"c":"j","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"w","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"i","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"l","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"m","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"@","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"k","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"u","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"r","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"a","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"s","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"t","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":".","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"l","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"o","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"c","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"a","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"l","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"➜","fg":{"Named":"Green"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":" ","fg":{"Named":"Green"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":" ","fg":{"Named":"Green"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"~","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"/","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"c","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"o","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"d","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"e","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"/","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"a","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"l","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"a","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"c","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"r","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"i","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"t","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"t","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":"y","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":" ","fg":{"Named":"Cyan"},"bg":{"Named":"Background"},"flags":{"bits":2}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":".","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"/","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"c","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"o","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"l","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"o","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"r","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"s","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":".","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"p","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"l","fg":{"Named":"Magenta"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}}],[{"c":"S","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"y","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"s","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"t","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"e","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"m","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":" ","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"c","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"o","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"l","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"o","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"r","fg":{"Named":"Foreground"},"bg":{"Named":"Background"},"flags":{"bits":0}},{"c":"s","fg":{"Named":"Foreground"},"bg":{"Nam