Skip to content

Commit

Permalink
Have the save/restore colors escape codes also save restore the ANSI …
Browse files Browse the repository at this point in the history
…color table
  • Loading branch information
kovidgoyal committed Dec 21, 2020
1 parent c3c5a54 commit e97f1a4
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 32 deletions.
21 changes: 11 additions & 10 deletions docs/protocol-extensions.rst
Expand Up @@ -180,23 +180,24 @@ rectangular region of the screen from (3, 4) to (10, 11), you use::
<ESC>[2*x<ESC>[4;3;11;10;44$r<ESC>[*x


Saving and restoring the default foreground/background/selection/cursor colors
Saving and restoring colors
---------------------------------------------------------------------------------

It is often useful for a full screen application with its own color themes
to set the default foreground, background, selection and cursor colors. This
allows for various performance optimizations when drawing the screen. The
problem is that if the user previously used the escape codes to change these
colors herself, then running the full screen application will lose her
changes even after it exits. To avoid this, kitty introduces a new pair of
*OSC* escape codes to push and pop the current color values from a stack::
It is often useful for a full screen application with its own color themes to
set the default foreground, background, selection and cursor colors and the
ANSI color table. This allows for various performance optimizations when
drawing the screen. The problem is that if the user previously used the escape
codes to change these colors herself, then running the full screen application
will lose her changes even after it exits. To avoid this, kitty introduces a
new pair of *OSC* escape codes to push and pop the current color values from a
stack::

<ESC>]30001<ESC>\ # push onto stack
<ESC>]30101<ESC>\ # pop from stack

These escape codes save/restore the so called *dynamic colors*, default
These escape codes save/restore the colors, default
background, default foreground, selection background, selection foreground and
cursor color.
cursor color and the 256 colors of the ANSI color table.


Pasting to clipboard
Expand Down
57 changes: 47 additions & 10 deletions kitty/colors.c
Expand Up @@ -318,19 +318,56 @@ copy_color_table_to_buffer(ColorProfile *self, color_type *buf, int offset, size
self->dirty = false;
}

void
colorprofile_push_dynamic_colors(ColorProfile *self) {
if (self->dynamic_color_stack_idx >= arraysz(self->dynamic_color_stack)) {
memmove(self->dynamic_color_stack, self->dynamic_color_stack + 1, sizeof(self->dynamic_color_stack) - sizeof(self->dynamic_color_stack[0]));
self->dynamic_color_stack_idx = arraysz(self->dynamic_color_stack) - 1;
static void
push_onto_color_stack_at(ColorProfile *self, unsigned int i) {
self->color_stack[i].dynamic_colors = self->overridden;
self->color_stack[i].valid = true;
memcpy(self->color_stack[i].color_table, self->color_table, sizeof(self->color_stack->color_table));
}

static void
copy_from_color_stack_at(ColorProfile *self, unsigned int i) {
self->overridden = self->color_stack[i].dynamic_colors;
memcpy(self->color_table, self->color_stack[i].color_table, sizeof(self->color_table));
}

bool
colorprofile_push_colors(ColorProfile *self, unsigned int idx) {
if (idx == 0) {
for (unsigned i = 0; i < arraysz(self->color_stack); i++) {
if (!self->color_stack[i].valid) {
push_onto_color_stack_at(self, i);
return true;
}
}
memmove(self->color_stack, self->color_stack + 1, sizeof(self->color_stack) - sizeof(self->color_stack[0]));
push_onto_color_stack_at(self, arraysz(self->color_stack) - 1);
return true;
}
if (idx < arraysz(self->color_stack)) {
push_onto_color_stack_at(self, idx);
return true;
}
self->dynamic_color_stack[self->dynamic_color_stack_idx++] = self->overridden;
return false;
}

void
colorprofile_pop_dynamic_colors(ColorProfile *self) {
if (!self->dynamic_color_stack_idx) return;
self->overridden = self->dynamic_color_stack[--(self->dynamic_color_stack_idx)];
bool
colorprofile_pop_colors(ColorProfile *self, unsigned int idx) {
if (idx == 0) {
for (unsigned i = arraysz(self->color_stack) - 1; i-- > 0; ) {
if (self->color_stack[i].valid) {
copy_from_color_stack_at(self, i);
self->color_stack[i].valid = false;
return true;
}
}
return false;
}
if (idx < arraysz(self->color_stack)) {
copy_from_color_stack_at(self, idx);
return true;
}
return false;
}

static PyObject*
Expand Down
14 changes: 10 additions & 4 deletions kitty/data-types.h
Expand Up @@ -237,14 +237,20 @@ typedef struct {
color_type default_fg, default_bg, cursor_color, cursor_text_color, cursor_text_uses_bg, highlight_fg, highlight_bg;
} DynamicColor;


typedef struct {
DynamicColor dynamic_colors;
uint32_t color_table[256];
bool valid;
} ColorStackEntry;

typedef struct {
PyObject_HEAD

bool dirty;
uint32_t color_table[256];
uint32_t orig_color_table[256];
DynamicColor dynamic_color_stack[10];
size_t dynamic_color_stack_idx;
ColorStackEntry color_stack[16];
DynamicColor configured, overridden;
color_type mark_foregrounds[MARK_MASK+1], mark_backgrounds[MARK_MASK+1];
} ColorProfile;
Expand Down Expand Up @@ -304,8 +310,8 @@ bool set_iutf8(int, bool);
color_type colorprofile_to_color(ColorProfile *self, color_type entry, color_type defval);
float cursor_text_as_bg(ColorProfile *self);
void copy_color_table_to_buffer(ColorProfile *self, color_type *address, int offset, size_t stride);
void colorprofile_push_dynamic_colors(ColorProfile*);
void colorprofile_pop_dynamic_colors(ColorProfile*);
bool colorprofile_push_colors(ColorProfile*, unsigned int);
bool colorprofile_pop_colors(ColorProfile*, unsigned int);

void set_mouse_cursor(MouseShape);
void enter_event(void);
Expand Down
4 changes: 2 additions & 2 deletions kitty/parser.c
Expand Up @@ -414,11 +414,11 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
END_DISPATCH
case 30001:
REPORT_COMMAND(screen_push_dynamic_colors);
screen_push_dynamic_colors(screen);
screen_push_colors(screen, 0);
break;
case 30101:
REPORT_COMMAND(screen_pop_dynamic_colors);
screen_pop_dynamic_colors(screen);
screen_pop_colors(screen, 0);
break;
default:
REPORT_ERROR("Unknown OSC code: %u", code);
Expand Down
8 changes: 4 additions & 4 deletions kitty/screen.c
Expand Up @@ -1594,13 +1594,13 @@ screen_handle_cmd(Screen *self, PyObject *cmd) {
}

void
screen_push_dynamic_colors(Screen *self) {
colorprofile_push_dynamic_colors(self->color_profile);
screen_push_colors(Screen *self, unsigned int idx) {
colorprofile_push_colors(self->color_profile, idx);
}

void
screen_pop_dynamic_colors(Screen *self) {
colorprofile_pop_dynamic_colors(self->color_profile);
screen_pop_colors(Screen *self, unsigned int idx) {
colorprofile_pop_colors(self->color_profile, idx);
}

void
Expand Down
4 changes: 2 additions & 2 deletions kitty/screen.h
Expand Up @@ -179,8 +179,8 @@ void screen_erase_characters(Screen *self, unsigned int count);
void screen_set_margins(Screen *self, unsigned int top, unsigned int bottom);
void screen_change_charset(Screen *, uint32_t to);
void screen_handle_cmd(Screen *, PyObject *cmd);
void screen_push_dynamic_colors(Screen *);
void screen_pop_dynamic_colors(Screen *);
void screen_push_colors(Screen *, unsigned int);
void screen_pop_colors(Screen *, unsigned int);
void screen_handle_print(Screen *, PyObject *cmd);
void screen_designate_charset(Screen *, uint32_t which, uint32_t as);
void screen_use_latin1(Screen *, bool);
Expand Down

0 comments on commit e97f1a4

Please sign in to comment.