mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
refactor: move background color detection into Lua
This commit is contained in:
parent
48bcc7b971
commit
ab102f188e
@ -164,3 +164,133 @@ do
|
|||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Guess value of 'background' based on terminal color.
|
||||||
|
---
|
||||||
|
--- We write Operating System Command (OSC) 11 to the terminal to request the
|
||||||
|
--- terminal's background color. We then wait for a response. If the response
|
||||||
|
--- matches `rgba:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits, then
|
||||||
|
--- compute the luminance[1] of the RGB color and classify it as light/dark
|
||||||
|
--- accordingly. Note that the color components may have anywhere from one to
|
||||||
|
--- four hex digits, and require scaling accordingly as values out of 4, 8, 12,
|
||||||
|
--- or 16 bits. Also note the A(lpha) component is optional, and is parsed but
|
||||||
|
--- ignored in the calculations.
|
||||||
|
---
|
||||||
|
--- [1] https://en.wikipedia.org/wiki/Luma_%28video%29
|
||||||
|
do
|
||||||
|
--- Parse a string of hex characters as a color.
|
||||||
|
---
|
||||||
|
--- The string can contain 1 to 4 hex characters. The returned value is
|
||||||
|
--- between 0.0 and 1.0 (inclusive) representing the intensity of the color.
|
||||||
|
---
|
||||||
|
--- For instance, if only a single hex char "a" is used, then this function
|
||||||
|
--- returns 0.625 (10 / 16), while a value of "aa" would return 0.664 (170 /
|
||||||
|
--- 256).
|
||||||
|
---
|
||||||
|
--- @param c string Color as a string of hex chars
|
||||||
|
--- @return number? Intensity of the color
|
||||||
|
local function parsecolor(c)
|
||||||
|
local len = #c
|
||||||
|
assert(len > 0 and len <= 4, 'Invalid hex color string')
|
||||||
|
if not c:match('^0x') then
|
||||||
|
c = string.format('0x%s', c)
|
||||||
|
end
|
||||||
|
|
||||||
|
local max = tonumber(string.format('0x%s', string.rep('f', len)))
|
||||||
|
return tonumber(c) / max
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Parse an OSC 11 response
|
||||||
|
---
|
||||||
|
--- Either of the two formats below are accepted:
|
||||||
|
---
|
||||||
|
--- OSC 11 ; rgb:<red>/<green>/<blue>
|
||||||
|
---
|
||||||
|
--- or
|
||||||
|
---
|
||||||
|
--- OSC 11 ; rgba:<red>/<green>/<blue>/<alpha>
|
||||||
|
---
|
||||||
|
--- where
|
||||||
|
---
|
||||||
|
--- <red>, <green>, <blue>, <alpha> := h | hh | hhh | hhhh
|
||||||
|
---
|
||||||
|
--- The alpha component is ignored, if present.
|
||||||
|
---
|
||||||
|
--- @param resp string OSC 11 response
|
||||||
|
--- @return string? Red component
|
||||||
|
--- @return string? Green component
|
||||||
|
--- @return string? Blue component
|
||||||
|
local function parseosc11(resp)
|
||||||
|
local r, g, b
|
||||||
|
r, g, b = resp:match('^\027%]11;rgb:(%x+)/(%x+)/(%x+)$')
|
||||||
|
if not r and not g and not b then
|
||||||
|
local a
|
||||||
|
r, g, b, a = resp:match('^\027%]11;rgba:(%x+)/(%x+)/(%x+)/(%x+)$')
|
||||||
|
if not a or #a > 4 then
|
||||||
|
return nil, nil, nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if r and g and b and #r <= 4 and #g <= 4 and #b <= 4 then
|
||||||
|
return r, g, b
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, nil, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local tty = false
|
||||||
|
for _, ui in ipairs(vim.api.nvim_list_uis()) do
|
||||||
|
if ui.chan == 1 and ui.stdout_tty then
|
||||||
|
tty = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if tty then
|
||||||
|
local timer = assert(vim.uv.new_timer())
|
||||||
|
|
||||||
|
local id = vim.api.nvim_create_autocmd('TermResponse', {
|
||||||
|
nested = true,
|
||||||
|
callback = function(args)
|
||||||
|
if vim.api.nvim_get_option_info2('background', {}).was_set then
|
||||||
|
-- Don't do anything if 'background' is already set
|
||||||
|
timer:stop()
|
||||||
|
timer:close()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local resp = args.data ---@type string
|
||||||
|
local r, g, b = parseosc11(resp)
|
||||||
|
if r and g and b then
|
||||||
|
local rr = parsecolor(r)
|
||||||
|
local gg = parsecolor(g)
|
||||||
|
local bb = parsecolor(b)
|
||||||
|
|
||||||
|
if rr and gg and bb then
|
||||||
|
local luminance = (0.299 * rr) + (0.587 * gg) + (0.114 * bb)
|
||||||
|
local bg = luminance < 0.5 and 'dark' or 'light'
|
||||||
|
if bg ~= vim.o.background then
|
||||||
|
vim.o.background = bg
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
timer:stop()
|
||||||
|
timer:close()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
io.stdout:write('\027]11;?\027\\')
|
||||||
|
|
||||||
|
timer:start(1000, 0, function()
|
||||||
|
-- No response received. Delete the autocommand
|
||||||
|
vim.schedule(function()
|
||||||
|
-- Suppress error if autocommand has already been deleted
|
||||||
|
pcall(vim.api.nvim_del_autocmd, id)
|
||||||
|
end)
|
||||||
|
timer:close()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@ -348,15 +348,6 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strequal(name.data, "term_background")) {
|
|
||||||
VALIDATE_T("term_background", kObjectTypeString, value.type, {
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
set_tty_background(value.data.string.data);
|
|
||||||
ui->term_background = string_to_cstr(value.data.string);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strequal(name.data, "stdin_fd")) {
|
if (strequal(name.data, "stdin_fd")) {
|
||||||
VALIDATE_T("stdin_fd", kObjectTypeInteger, value.type, {
|
VALIDATE_T("stdin_fd", kObjectTypeInteger, value.type, {
|
||||||
return;
|
return;
|
||||||
|
@ -3183,23 +3183,6 @@ bool set_tty_option(const char *name, char *value)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_tty_background(const char *value)
|
|
||||||
{
|
|
||||||
if (option_was_set("bg") || strequal(p_bg, value)) {
|
|
||||||
// background is already set... ignore
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (starting) {
|
|
||||||
// Wait until after startup, so OptionSet is triggered.
|
|
||||||
do_cmdline_cmd((value[0] == 'l')
|
|
||||||
? "autocmd VimEnter * ++once ++nested :lua if not vim.api.nvim_get_option_info2('bg', {}).was_set then vim.o.bg = 'light' end"
|
|
||||||
: "autocmd VimEnter * ++once ++nested :lua if not vim.api.nvim_get_option_info2('bg', {}).was_set then vim.o.bg = 'dark' end");
|
|
||||||
} else {
|
|
||||||
set_option_value_give_err("bg", CSTR_AS_OPTVAL((char *)value), 0);
|
|
||||||
reset_option_was_set("bg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Find index for an option
|
/// Find index for an option
|
||||||
///
|
///
|
||||||
/// @param[in] arg Option name.
|
/// @param[in] arg Option name.
|
||||||
|
@ -124,7 +124,6 @@ void tinput_init(TermInput *input, Loop *loop)
|
|||||||
input->loop = loop;
|
input->loop = loop;
|
||||||
input->paste = 0;
|
input->paste = 0;
|
||||||
input->in_fd = STDIN_FILENO;
|
input->in_fd = STDIN_FILENO;
|
||||||
input->waiting_for_bg_response = 0;
|
|
||||||
input->extkeys_type = kExtkeysNone;
|
input->extkeys_type = kExtkeysNone;
|
||||||
input->ttimeout = (bool)p_ttimeout;
|
input->ttimeout = (bool)p_ttimeout;
|
||||||
input->ttimeoutlen = p_ttm;
|
input->ttimeoutlen = p_ttm;
|
||||||
@ -579,113 +578,6 @@ static HandleState handle_bracketed_paste(TermInput *input)
|
|||||||
return kNotApplicable;
|
return kNotApplicable;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_bg(char *bgvalue)
|
|
||||||
{
|
|
||||||
if (ui_client_attached) {
|
|
||||||
MAXSIZE_TEMP_ARRAY(args, 2);
|
|
||||||
ADD_C(args, CSTR_AS_OBJ("term_background"));
|
|
||||||
ADD_C(args, CSTR_AS_OBJ(bgvalue));
|
|
||||||
rpc_send_event(ui_client_channel_id, "nvim_ui_set_option", args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// During startup, tui.c requests the background color (see `ext.get_bg`).
|
|
||||||
//
|
|
||||||
// Here in input.c, we watch for the terminal response `\e]11;COLOR\a`. If
|
|
||||||
// COLOR matches `rgb:RRRR/GGGG/BBBB/AAAA` where R, G, B, and A are hex digits,
|
|
||||||
// then compute the luminance[1] of the RGB color and classify it as light/dark
|
|
||||||
// accordingly. Note that the color components may have anywhere from one to
|
|
||||||
// four hex digits, and require scaling accordingly as values out of 4, 8, 12,
|
|
||||||
// or 16 bits. Also note the A(lpha) component is optional, and is parsed but
|
|
||||||
// ignored in the calculations.
|
|
||||||
//
|
|
||||||
// [1] https://en.wikipedia.org/wiki/Luma_%28video%29
|
|
||||||
HandleState handle_background_color(TermInput *input)
|
|
||||||
{
|
|
||||||
if (input->waiting_for_bg_response <= 0) {
|
|
||||||
return kNotApplicable;
|
|
||||||
}
|
|
||||||
size_t count = 0;
|
|
||||||
size_t component = 0;
|
|
||||||
size_t header_size = 0;
|
|
||||||
size_t num_components = 0;
|
|
||||||
size_t buf_size = rbuffer_size(input->read_stream.buffer);
|
|
||||||
uint16_t rgb[] = { 0, 0, 0 };
|
|
||||||
uint16_t rgb_max[] = { 0, 0, 0 };
|
|
||||||
bool eat_backslash = false;
|
|
||||||
bool done = false;
|
|
||||||
bool bad = false;
|
|
||||||
if (buf_size >= 9
|
|
||||||
&& !rbuffer_cmp(input->read_stream.buffer, "\x1b]11;rgb:", 9)) {
|
|
||||||
header_size = 9;
|
|
||||||
num_components = 3;
|
|
||||||
} else if (buf_size >= 10
|
|
||||||
&& !rbuffer_cmp(input->read_stream.buffer, "\x1b]11;rgba:", 10)) {
|
|
||||||
header_size = 10;
|
|
||||||
num_components = 4;
|
|
||||||
} else if (buf_size < 10
|
|
||||||
&& !rbuffer_cmp(input->read_stream.buffer,
|
|
||||||
"\x1b]11;rgba", buf_size)) {
|
|
||||||
// An incomplete sequence was found, waiting for the next input.
|
|
||||||
return kIncomplete;
|
|
||||||
} else {
|
|
||||||
input->waiting_for_bg_response--;
|
|
||||||
if (input->waiting_for_bg_response == 0) {
|
|
||||||
DLOG("did not get a response for terminal background query");
|
|
||||||
}
|
|
||||||
return kNotApplicable;
|
|
||||||
}
|
|
||||||
RBUFFER_EACH(input->read_stream.buffer, c, i) {
|
|
||||||
count = i + 1;
|
|
||||||
// Skip the header.
|
|
||||||
if (i < header_size) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (eat_backslash) {
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
} else if (c == '\x07') {
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
} else if (c == '\x1b') {
|
|
||||||
eat_backslash = true;
|
|
||||||
} else if (bad) {
|
|
||||||
// ignore
|
|
||||||
} else if ((c == '/') && (++component < num_components)) {
|
|
||||||
// work done in condition
|
|
||||||
} else if (ascii_isxdigit(c)) {
|
|
||||||
if (component < 3 && rgb_max[component] != 0xffff) {
|
|
||||||
rgb_max[component] = (uint16_t)((rgb_max[component] << 4) | 0xf);
|
|
||||||
rgb[component] = (uint16_t)((rgb[component] << 4) | hex2nr(c));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bad = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (done && !bad && rgb_max[0] && rgb_max[1] && rgb_max[2]) {
|
|
||||||
rbuffer_consumed(input->read_stream.buffer, count);
|
|
||||||
double r = (double)rgb[0] / (double)rgb_max[0];
|
|
||||||
double g = (double)rgb[1] / (double)rgb_max[1];
|
|
||||||
double b = (double)rgb[2] / (double)rgb_max[2];
|
|
||||||
double luminance = (0.299 * r) + (0.587 * g) + (0.114 * b); // CCIR 601
|
|
||||||
bool is_dark = luminance < 0.5;
|
|
||||||
char *bgvalue = is_dark ? "dark" : "light";
|
|
||||||
DLOG("bg response: %s", bgvalue);
|
|
||||||
ui_client_bg_response = is_dark ? kTrue : kFalse;
|
|
||||||
set_bg(bgvalue);
|
|
||||||
input->waiting_for_bg_response = 0;
|
|
||||||
} else if (!done && !bad) {
|
|
||||||
// An incomplete sequence was found, waiting for the next input.
|
|
||||||
return kIncomplete;
|
|
||||||
} else {
|
|
||||||
input->waiting_for_bg_response = 0;
|
|
||||||
rbuffer_consumed(input->read_stream.buffer, count);
|
|
||||||
DLOG("failed to parse bg response");
|
|
||||||
return kNotApplicable;
|
|
||||||
}
|
|
||||||
return kComplete;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_osc_event(TermInput *input, const TermKeyKey *key)
|
static void handle_osc_event(TermInput *input, const TermKeyKey *key)
|
||||||
{
|
{
|
||||||
assert(input);
|
assert(input);
|
||||||
@ -712,14 +604,12 @@ static void handle_osc_event(TermInput *input, const TermKeyKey *key)
|
|||||||
static void handle_raw_buffer(TermInput *input, bool force)
|
static void handle_raw_buffer(TermInput *input, bool force)
|
||||||
{
|
{
|
||||||
HandleState is_paste = kNotApplicable;
|
HandleState is_paste = kNotApplicable;
|
||||||
HandleState is_bc = kNotApplicable;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!force
|
if (!force
|
||||||
&& (handle_focus_event(input)
|
&& (handle_focus_event(input)
|
||||||
|| (is_paste = handle_bracketed_paste(input)) != kNotApplicable
|
|| (is_paste = handle_bracketed_paste(input)) != kNotApplicable)) {
|
||||||
|| (is_bc = handle_background_color(input)) != kNotApplicable)) {
|
if (is_paste == kIncomplete) {
|
||||||
if (is_paste == kIncomplete || is_bc == kIncomplete) {
|
|
||||||
// Wait for the next input, leaving it in the raw buffer due to an
|
// Wait for the next input, leaving it in the raw buffer due to an
|
||||||
// incomplete sequence.
|
// incomplete sequence.
|
||||||
return;
|
return;
|
||||||
|
@ -24,7 +24,6 @@ typedef struct term_input {
|
|||||||
// Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk
|
// Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk
|
||||||
int8_t paste;
|
int8_t paste;
|
||||||
bool ttimeout;
|
bool ttimeout;
|
||||||
int8_t waiting_for_bg_response;
|
|
||||||
int8_t waiting_for_csiu_response;
|
int8_t waiting_for_csiu_response;
|
||||||
ExtkeysType extkeys_type;
|
ExtkeysType extkeys_type;
|
||||||
OptInt ttimeoutlen;
|
OptInt ttimeoutlen;
|
||||||
|
@ -133,7 +133,6 @@ struct TUIData {
|
|||||||
int reset_scroll_region;
|
int reset_scroll_region;
|
||||||
int set_cursor_style, reset_cursor_style;
|
int set_cursor_style, reset_cursor_style;
|
||||||
int save_title, restore_title;
|
int save_title, restore_title;
|
||||||
int get_bg;
|
|
||||||
int set_underline_style;
|
int set_underline_style;
|
||||||
int set_underline_color;
|
int set_underline_color;
|
||||||
int enable_extended_keys, disable_extended_keys;
|
int enable_extended_keys, disable_extended_keys;
|
||||||
@ -250,7 +249,6 @@ static void terminfo_start(TUIData *tui)
|
|||||||
tui->unibi_ext.reset_scroll_region = -1;
|
tui->unibi_ext.reset_scroll_region = -1;
|
||||||
tui->unibi_ext.set_cursor_style = -1;
|
tui->unibi_ext.set_cursor_style = -1;
|
||||||
tui->unibi_ext.reset_cursor_style = -1;
|
tui->unibi_ext.reset_cursor_style = -1;
|
||||||
tui->unibi_ext.get_bg = -1;
|
|
||||||
tui->unibi_ext.set_underline_color = -1;
|
tui->unibi_ext.set_underline_color = -1;
|
||||||
tui->unibi_ext.enable_extended_keys = -1;
|
tui->unibi_ext.enable_extended_keys = -1;
|
||||||
tui->unibi_ext.disable_extended_keys = -1;
|
tui->unibi_ext.disable_extended_keys = -1;
|
||||||
@ -327,9 +325,7 @@ static void terminfo_start(TUIData *tui)
|
|||||||
unibi_out(tui, unibi_enter_ca_mode);
|
unibi_out(tui, unibi_enter_ca_mode);
|
||||||
unibi_out(tui, unibi_keypad_xmit);
|
unibi_out(tui, unibi_keypad_xmit);
|
||||||
unibi_out(tui, unibi_clear_screen);
|
unibi_out(tui, unibi_clear_screen);
|
||||||
// Ask the terminal to send us the background color.
|
|
||||||
tui->input.waiting_for_bg_response = 5;
|
|
||||||
unibi_out_ext(tui, tui->unibi_ext.get_bg);
|
|
||||||
// Enable bracketed paste
|
// Enable bracketed paste
|
||||||
unibi_out_ext(tui, tui->unibi_ext.enable_bracketed_paste);
|
unibi_out_ext(tui, tui->unibi_ext.enable_bracketed_paste);
|
||||||
|
|
||||||
@ -1882,9 +1878,6 @@ static void patch_terminfo_bugs(TUIData *tui, const char *term, const char *colo
|
|||||||
#define XTERM_SETAB_16 \
|
#define XTERM_SETAB_16 \
|
||||||
"\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m"
|
"\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m"
|
||||||
|
|
||||||
tui->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg",
|
|
||||||
"\x1b]11;?\x07");
|
|
||||||
|
|
||||||
// Query the terminal to see if it supports CSI u key encoding by writing CSI
|
// Query the terminal to see if it supports CSI u key encoding by writing CSI
|
||||||
// ? u followed by a request for the primary device attributes (CSI c)
|
// ? u followed by a request for the primary device attributes (CSI c)
|
||||||
// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#detection-of-support-for-this-protocol
|
// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#detection-of-support-for-this-protocol
|
||||||
|
@ -1,162 +0,0 @@
|
|||||||
local helpers = require("test.unit.helpers")(after_each)
|
|
||||||
local cimport = helpers.cimport
|
|
||||||
local eq = helpers.eq
|
|
||||||
local ffi = helpers.ffi
|
|
||||||
local itp = helpers.gen_itp(it)
|
|
||||||
local to_cstr = helpers.to_cstr
|
|
||||||
|
|
||||||
local cinput = cimport("./src/nvim/tui/input.h")
|
|
||||||
local rbuffer = cimport("./test/unit/fixtures/rbuffer.h")
|
|
||||||
local globals = cimport("./src/nvim/globals.h")
|
|
||||||
local multiqueue = cimport("./test/unit/fixtures/multiqueue.h")
|
|
||||||
local ui_client = cimport("./src/nvim/ui_client.h")
|
|
||||||
|
|
||||||
itp('handle_background_color', function()
|
|
||||||
local handle_background_color = cinput.handle_background_color
|
|
||||||
local term_input = ffi.new('TermInput', {})
|
|
||||||
local events = globals.main_loop.thread_events
|
|
||||||
local kIncomplete = cinput.kIncomplete
|
|
||||||
local kNotApplicable = cinput.kNotApplicable
|
|
||||||
local kComplete = cinput.kComplete
|
|
||||||
|
|
||||||
-- Short-circuit when not waiting for response.
|
|
||||||
term_input.waiting_for_bg_response = 0
|
|
||||||
eq(kNotApplicable, handle_background_color(term_input))
|
|
||||||
|
|
||||||
local capacity = 100
|
|
||||||
local rbuf = ffi.gc(rbuffer.rbuffer_new(capacity), rbuffer.rbuffer_free)
|
|
||||||
term_input.read_stream.buffer = rbuf
|
|
||||||
|
|
||||||
local function assert_bg(colorspace, color, bg)
|
|
||||||
local term_response = '\027]11;'..colorspace..':'..color..'\007'
|
|
||||||
rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
|
|
||||||
|
|
||||||
term_input.waiting_for_bg_response = 1
|
|
||||||
eq(kComplete, handle_background_color(term_input))
|
|
||||||
eq(0, term_input.waiting_for_bg_response)
|
|
||||||
eq(0, multiqueue.multiqueue_size(events))
|
|
||||||
eq(bg, ({[0]="light", [1] = "dark", [-1] = "none"})
|
|
||||||
[tonumber(ui_client.ui_client_bg_response)])
|
|
||||||
|
|
||||||
-- Buffer has been consumed.
|
|
||||||
eq(0, rbuf.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
assert_bg('rgb', '0000/0000/0000', 'dark')
|
|
||||||
assert_bg('rgb', 'ffff/ffff/ffff', 'light')
|
|
||||||
assert_bg('rgb', '000/000/000', 'dark')
|
|
||||||
assert_bg('rgb', 'fff/fff/fff', 'light')
|
|
||||||
assert_bg('rgb', '00/00/00', 'dark')
|
|
||||||
assert_bg('rgb', 'ff/ff/ff', 'light')
|
|
||||||
assert_bg('rgb', '0/0/0', 'dark')
|
|
||||||
assert_bg('rgb', 'f/f/f', 'light')
|
|
||||||
|
|
||||||
assert_bg('rgb', 'f/0/0', 'dark')
|
|
||||||
assert_bg('rgb', '0/f/0', 'light')
|
|
||||||
assert_bg('rgb', '0/0/f', 'dark')
|
|
||||||
|
|
||||||
assert_bg('rgb', '1/1/1', 'dark')
|
|
||||||
assert_bg('rgb', '2/2/2', 'dark')
|
|
||||||
assert_bg('rgb', '3/3/3', 'dark')
|
|
||||||
assert_bg('rgb', '4/4/4', 'dark')
|
|
||||||
assert_bg('rgb', '5/5/5', 'dark')
|
|
||||||
assert_bg('rgb', '6/6/6', 'dark')
|
|
||||||
assert_bg('rgb', '7/7/7', 'dark')
|
|
||||||
assert_bg('rgb', '8/8/8', 'light')
|
|
||||||
assert_bg('rgb', '9/9/9', 'light')
|
|
||||||
assert_bg('rgb', 'a/a/a', 'light')
|
|
||||||
assert_bg('rgb', 'b/b/b', 'light')
|
|
||||||
assert_bg('rgb', 'c/c/c', 'light')
|
|
||||||
assert_bg('rgb', 'd/d/d', 'light')
|
|
||||||
assert_bg('rgb', 'e/e/e', 'light')
|
|
||||||
|
|
||||||
assert_bg('rgb', '0/e/0', 'light')
|
|
||||||
assert_bg('rgb', '0/d/0', 'light')
|
|
||||||
assert_bg('rgb', '0/c/0', 'dark')
|
|
||||||
assert_bg('rgb', '0/b/0', 'dark')
|
|
||||||
|
|
||||||
assert_bg('rgb', 'f/0/f', 'dark')
|
|
||||||
assert_bg('rgb', 'f/1/f', 'dark')
|
|
||||||
assert_bg('rgb', 'f/2/f', 'dark')
|
|
||||||
assert_bg('rgb', 'f/3/f', 'light')
|
|
||||||
assert_bg('rgb', 'f/4/f', 'light')
|
|
||||||
|
|
||||||
assert_bg('rgba', '0000/0000/0000/0000', 'dark')
|
|
||||||
assert_bg('rgba', '0000/0000/0000/ffff', 'dark')
|
|
||||||
assert_bg('rgba', 'ffff/ffff/ffff/0000', 'light')
|
|
||||||
assert_bg('rgba', 'ffff/ffff/ffff/ffff', 'light')
|
|
||||||
assert_bg('rgba', '000/000/000/000', 'dark')
|
|
||||||
assert_bg('rgba', '000/000/000/fff', 'dark')
|
|
||||||
assert_bg('rgba', 'fff/fff/fff/000', 'light')
|
|
||||||
assert_bg('rgba', 'fff/fff/fff/fff', 'light')
|
|
||||||
assert_bg('rgba', '00/00/00/00', 'dark')
|
|
||||||
assert_bg('rgba', '00/00/00/ff', 'dark')
|
|
||||||
assert_bg('rgba', 'ff/ff/ff/00', 'light')
|
|
||||||
assert_bg('rgba', 'ff/ff/ff/ff', 'light')
|
|
||||||
assert_bg('rgba', '0/0/0/0', 'dark')
|
|
||||||
assert_bg('rgba', '0/0/0/f', 'dark')
|
|
||||||
assert_bg('rgba', 'f/f/f/0', 'light')
|
|
||||||
assert_bg('rgba', 'f/f/f/f', 'light')
|
|
||||||
|
|
||||||
|
|
||||||
-- Incomplete sequence: necessarily correct behavior.
|
|
||||||
local term_response = '\027]11;rgba:f/f/f/f' -- missing '\007
|
|
||||||
rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
|
|
||||||
|
|
||||||
term_input.waiting_for_bg_response = 1
|
|
||||||
eq(kIncomplete, handle_background_color(term_input))
|
|
||||||
eq(1, term_input.waiting_for_bg_response)
|
|
||||||
eq(#term_response, rbuf.size)
|
|
||||||
|
|
||||||
term_response = '\007'
|
|
||||||
rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
|
|
||||||
eq(kComplete, handle_background_color(term_input))
|
|
||||||
eq(0, term_input.waiting_for_bg_response)
|
|
||||||
|
|
||||||
eq(0, tonumber(ui_client.ui_client_bg_response))
|
|
||||||
eq(0, multiqueue.multiqueue_size(events))
|
|
||||||
eq(0, rbuf.size)
|
|
||||||
|
|
||||||
term_response = '\027]11;rg'
|
|
||||||
rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
|
|
||||||
|
|
||||||
term_input.waiting_for_bg_response = 1
|
|
||||||
eq(kIncomplete, handle_background_color(term_input))
|
|
||||||
eq(1, term_input.waiting_for_bg_response)
|
|
||||||
eq(#term_response, rbuf.size)
|
|
||||||
|
|
||||||
term_response = 'ba:f/f/f/f\007'
|
|
||||||
rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
|
|
||||||
eq(kComplete, handle_background_color(term_input))
|
|
||||||
eq(0, term_input.waiting_for_bg_response)
|
|
||||||
|
|
||||||
eq(0, tonumber(ui_client.ui_client_bg_response))
|
|
||||||
eq(0, multiqueue.multiqueue_size(events))
|
|
||||||
eq(0, rbuf.size)
|
|
||||||
|
|
||||||
|
|
||||||
-- Does nothing when not at start of buffer.
|
|
||||||
term_response = '123\027]11;rgba:f/f/f/f\007456'
|
|
||||||
rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
|
|
||||||
|
|
||||||
term_input.waiting_for_bg_response = 3
|
|
||||||
eq(kNotApplicable, handle_background_color(term_input))
|
|
||||||
eq(2, term_input.waiting_for_bg_response)
|
|
||||||
|
|
||||||
eq(0, multiqueue.multiqueue_size(events))
|
|
||||||
eq(#term_response, rbuf.size)
|
|
||||||
rbuffer.rbuffer_consumed(rbuf, #term_response)
|
|
||||||
|
|
||||||
|
|
||||||
-- Keeps trailing buffer.
|
|
||||||
term_response = '\027]11;rgba:f/f/f/f\007456'
|
|
||||||
rbuffer.rbuffer_write(rbuf, to_cstr(term_response), #term_response)
|
|
||||||
|
|
||||||
term_input.waiting_for_bg_response = 1
|
|
||||||
eq(kComplete, handle_background_color(term_input))
|
|
||||||
eq(0, term_input.waiting_for_bg_response)
|
|
||||||
|
|
||||||
eq(0, multiqueue.multiqueue_size(events))
|
|
||||||
eq(3, rbuf.size)
|
|
||||||
rbuffer.rbuffer_consumed(rbuf, rbuf.size)
|
|
||||||
end)
|
|
Loading…
Reference in New Issue
Block a user