Implement OSC codes for changing selection colors
This commit is contained in:
parent
e5799321f8
commit
f0c546208d
5 changed files with 57 additions and 29 deletions
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import re
|
||||
import sys
|
||||
from enum import Enum
|
||||
from collections import namedtuple
|
||||
from ctypes import addressof, memmove, sizeof
|
||||
from threading import Lock
|
||||
|
|
@ -26,6 +27,11 @@
|
|||
|
||||
Cursor = namedtuple('Cursor', 'x y shape blink')
|
||||
|
||||
|
||||
class DynamicColor(Enum):
|
||||
default_fg, default_bg, cursor_color, highlight_fg, highlight_bg = range(1, 6)
|
||||
|
||||
|
||||
if DATA_CELL_SIZE % 3:
|
||||
raise ValueError('Incorrect data cell size, must be a multiple of 3')
|
||||
|
||||
|
|
@ -252,17 +258,13 @@ def __init__(self, screen, opts):
|
|||
self.color_profile.update_ansi_color_table(build_ansi_color_table(opts))
|
||||
self.screen = screen
|
||||
self.opts = opts
|
||||
self.original_bg = opts.background
|
||||
self.original_fg = opts.foreground
|
||||
self.default_bg = color_as_int(self.original_bg)
|
||||
self.default_fg = color_as_int(self.original_fg)
|
||||
self.original_bg = self.default_bg = color_as_int(opts.background)
|
||||
self.original_fg = self.default_fg = color_as_int(opts.foreground)
|
||||
self.dpix, self.dpiy = get_logical_dpi()
|
||||
self.opts = opts
|
||||
self.default_cursor = self.current_cursor = Cursor(0, 0, opts.cursor_shape, opts.cursor_blink_interval > 0)
|
||||
self.opts = opts
|
||||
self.original_bg = opts.background
|
||||
self.original_fg = opts.foreground
|
||||
self.selection_foreground, self.selection_background = map(color_as_int, (opts.selection_foreground, opts.selection_background))
|
||||
self.highlight_fg, self.highlight_bg = map(color_as_int, (opts.selection_foreground, opts.selection_background))
|
||||
self.sprite_map_type = self.main_sprite_map = self.scroll_sprite_map = self.render_buf = None
|
||||
|
||||
def escape(chars):
|
||||
|
|
@ -290,25 +292,30 @@ def resize(self, window_geometry):
|
|||
|
||||
def change_colors(self, changes):
|
||||
dirtied = False
|
||||
|
||||
def item(raw):
|
||||
if raw is None:
|
||||
return True, None
|
||||
val = to_color(raw)
|
||||
if val is None:
|
||||
return False, None
|
||||
return True, color_as_int(val)
|
||||
|
||||
for which, val in changes.items():
|
||||
if which in ('fg', 'bg'):
|
||||
if not val:
|
||||
setattr(self, 'default_' + which, color_as_int(getattr(self, 'original_' + which)))
|
||||
dirtied = True
|
||||
else:
|
||||
val = to_color(val)
|
||||
if val is not None:
|
||||
setattr(self, 'default_' + which, color_as_int(val))
|
||||
dirtied = True
|
||||
elif which == 'cc':
|
||||
if not val:
|
||||
self.screen.cursor.color = 0
|
||||
dirtied = True
|
||||
else:
|
||||
val = to_color(val)
|
||||
if val is not None:
|
||||
self.screen.cursor.color = (color_as_int(val) << 8) | 1
|
||||
dirtied = True
|
||||
valid, val = item(val)
|
||||
if not valid:
|
||||
continue
|
||||
dirtied = True
|
||||
if which is DynamicColor.default_fg:
|
||||
self.default_fg = self.original_fg if val is None else val
|
||||
elif which is DynamicColor.default_bg:
|
||||
self.default_bg = self.original_bg if val is None else val
|
||||
elif which is DynamicColor.cursor_color:
|
||||
self.screen.cursor.color = 0 if val is None else (val << 8) | 1
|
||||
elif which is DynamicColor.highlight_fg:
|
||||
self.screen.highlight_fg = 0 if val is None else (val << 8) | 1
|
||||
elif which is DynamicColor.highlight_bg:
|
||||
self.screen.highlight_bg = 0 if val is None else (val << 8) | 1
|
||||
if dirtied:
|
||||
self.screen.mark_as_dirty()
|
||||
|
||||
|
|
@ -474,7 +481,11 @@ def prepare_for_render(self, sprites):
|
|||
buf = self.selection_buf
|
||||
if self.render_buf_is_dirty or sel != self.last_rendered_selection:
|
||||
memmove(buf, self.render_buf, sizeof(type(buf)))
|
||||
self.screen.apply_selection(addressof(buf), start[0], start[1], end[0], end[1], self.selection_foreground, self.selection_background)
|
||||
fg = self.screen.highlight_fg
|
||||
fg = fg >> 8 if fg & 1 else self.highlight_fg
|
||||
bg = self.screen.highlight_bg
|
||||
bg = bg >> 8 if bg & 1 else self.highlight_bg
|
||||
self.screen.apply_selection(addressof(buf), start[0], start[1], end[0], end[1], fg, bg)
|
||||
if self.render_buf_is_dirty or self.last_rendered_selection != sel:
|
||||
sprites.set_sprite_map(self.buffer_id, buf)
|
||||
self.render_buf_is_dirty = False
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ typedef struct {
|
|||
unsigned int parser_state, parser_text_start, parser_buf_pos;
|
||||
bool parser_has_pending_text;
|
||||
uint8_t read_buf[READ_BUF_SZ];
|
||||
uint32_t highlight_fg, highlight_bg;
|
||||
|
||||
} Screen;
|
||||
PyTypeObject Screen_Type;
|
||||
|
|
|
|||
|
|
@ -296,9 +296,13 @@ dispatch_osc(Screen *screen, PyObject DUMP_UNUSED *dump_callback) {
|
|||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 17:
|
||||
case 19:
|
||||
case 110:
|
||||
case 111:
|
||||
case 112:
|
||||
case 117:
|
||||
case 119:
|
||||
SET_COLOR(set_dynamic_color);
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ new(PyTypeObject *type, PyObject *args, PyObject UNUSED *kwds) {
|
|||
self->columns = columns; self->lines = lines;
|
||||
self->modes = empty_modes;
|
||||
self->margin_top = 0; self->margin_bottom = self->lines - 1;
|
||||
self->highlight_fg = 0; self->highlight_bg = 0;
|
||||
RESET_CHARSETS;
|
||||
self->callbacks = callbacks; Py_INCREF(callbacks);
|
||||
self->cursor = alloc_cursor();
|
||||
|
|
@ -68,6 +69,7 @@ screen_reset(Screen *self) {
|
|||
if (self->linebuf == self->alt_linebuf) screen_toggle_screen_buffer(self);
|
||||
linebuf_clear(self->linebuf, ' ');
|
||||
self->modes = empty_modes;
|
||||
self->highlight_fg = 0; self->highlight_bg = 0;
|
||||
RESET_CHARSETS;
|
||||
self->margin_top = 0; self->margin_bottom = self->lines - 1;
|
||||
screen_normal_keypad_mode(self);
|
||||
|
|
@ -1304,6 +1306,8 @@ static PyMemberDef members[] = {
|
|||
{"columns", T_UINT, offsetof(Screen, columns), READONLY, "columns"},
|
||||
{"margin_top", T_UINT, offsetof(Screen, margin_top), READONLY, "margin_top"},
|
||||
{"margin_bottom", T_UINT, offsetof(Screen, margin_bottom), READONLY, "margin_bottom"},
|
||||
{"highlight_fg", T_ULONG, offsetof(Screen, highlight_fg), 0, "highlight_fg"},
|
||||
{"highlight_bg", T_ULONG, offsetof(Screen, highlight_bg), 0, "highlight_bg"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
from functools import partial
|
||||
from time import monotonic
|
||||
|
||||
from .char_grid import CharGrid
|
||||
from .char_grid import CharGrid, DynamicColor
|
||||
from .constants import wakeup, get_boss, appname, WindowGeometry, is_key_pressed, mouse_button_pressed, cell_size
|
||||
from .fast_data_types import (
|
||||
BRACKETED_PASTE_START, BRACKETED_PASTE_END, Screen, read_bytes_dump,
|
||||
|
|
@ -22,6 +22,15 @@
|
|||
from .terminfo import get_capabilities
|
||||
from .utils import sanitize_title, get_primary_selection, parse_color_set, safe_print
|
||||
|
||||
DYNAMIC_COLOR_CODES = {
|
||||
10: DynamicColor.default_fg,
|
||||
11: DynamicColor.default_bg,
|
||||
12: DynamicColor.cursor_color,
|
||||
17: DynamicColor.highlight_bg,
|
||||
19: DynamicColor.highlight_fg,
|
||||
}
|
||||
DYNAMIC_COLOR_CODES.update({k+100: v for k, v in DYNAMIC_COLOR_CODES.items()})
|
||||
|
||||
|
||||
class Window:
|
||||
|
||||
|
|
@ -149,12 +158,11 @@ def icon_changed(self, new_icon):
|
|||
pass # TODO: Implement this
|
||||
|
||||
def set_dynamic_color(self, code, value):
|
||||
wmap = {10: 'fg', 11: 'bg', 12: 'cc', 110: 'fg', 111: 'bg', 112: 'cc'}
|
||||
if isinstance(value, bytes):
|
||||
value = value.decode('utf-8')
|
||||
color_changes = {}
|
||||
for val in value.split(';'):
|
||||
w = wmap.get(code)
|
||||
w = DYNAMIC_COLOR_CODES.get(code)
|
||||
if w is not None:
|
||||
if code >= 110:
|
||||
val = None
|
||||
|
|
|
|||
Loading…
Reference in a new issue