diff options
-rw-r--r-- | runtime/doc/deprecated.txt | 2 | ||||
-rw-r--r-- | runtime/doc/news.txt | 4 | ||||
-rw-r--r-- | runtime/doc/ui.txt | 1 | ||||
-rw-r--r-- | runtime/lua/vim/_defaults.lua | 130 | ||||
-rw-r--r-- | src/nvim/api/ui.c | 10 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 6 | ||||
-rw-r--r-- | src/nvim/option.c | 17 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 114 | ||||
-rw-r--r-- | src/nvim/tui/input.h | 1 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 9 | ||||
-rw-r--r-- | src/nvim/ui.c | 5 | ||||
-rw-r--r-- | src/nvim/ui.h | 3 | ||||
-rw-r--r-- | src/nvim/ui_client.c | 5 | ||||
-rw-r--r-- | src/nvim/ui_client.h | 4 | ||||
-rw-r--r-- | test/functional/api/ui_spec.lua | 2 | ||||
-rw-r--r-- | test/functional/terminal/tui_spec.lua | 6 | ||||
-rw-r--r-- | test/functional/ui/options_spec.lua | 16 | ||||
-rw-r--r-- | test/unit/tui_spec.lua | 162 |
18 files changed, 155 insertions, 342 deletions
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 7f7c498880..0a07f06c75 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -202,6 +202,8 @@ UI EXTENSIONS - `["wildmenu_show", items]` - `["wildmenu_select", selected]` - `["wildmenu_hide"]` +- *term_background* Unused. The terminal background color is now detected + by the Nvim core directly instead of the TUI. VARIABLES - *b:terminal_job_pid* PID of the top-level process in a |:terminal|. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 9d531b8efc..ee48bddc4d 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -340,4 +340,8 @@ release. • vim.treesitter.languagetree functions: - |LanguageTree:for_each_child()| Use |LanguageTree:children()| (non-recursive) instead. +• The "term_background" UI option |ui-ext-options| is deprecated and no longer + populated. Background color detection is now performed in Lua by the Nvim + core, not the TUI. + vim:tw=78:ts=8:sw=2:et:ft=help:norl: diff --git a/runtime/doc/ui.txt b/runtime/doc/ui.txt index 9cf0e59854..ab99b0446f 100644 --- a/runtime/doc/ui.txt +++ b/runtime/doc/ui.txt @@ -52,7 +52,6 @@ with these (optional) keys: - `ext_termcolors` Use external default colors. - `term_name` Sets the name of the terminal 'term'. - `term_colors` Sets the number of supported colors 't_Co'. -- `term_background` Sets the default value of 'background'. - `stdin_fd` Read buffer 1 from this fd as if it were stdin |--|. Only from |--embed| UI on startup. |ui-startup-stdin| - `stdin_tty` Tells if `stdin` is a `tty` or not. diff --git a/runtime/lua/vim/_defaults.lua b/runtime/lua/vim/_defaults.lua index c1b50e6950..0d7b4f1884 100644 --- a/runtime/lua/vim/_defaults.lua +++ b/runtime/lua/vim/_defaults.lua @@ -164,3 +164,133 @@ do 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 diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 3d013435f7..e6d9035b0d 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -120,7 +120,6 @@ void remote_ui_disconnect(uint64_t channel_id) // Destroy `ui`. XFREE_CLEAR(ui->term_name); - XFREE_CLEAR(ui->term_background); xfree(ui); } @@ -348,15 +347,6 @@ static void ui_set_option(UI *ui, bool init, String name, Object value, Error *e 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")) { VALIDATE_T("stdin_fd", kObjectTypeInteger, value.type, { return; diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 716fe5e481..aed96a539a 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -366,6 +366,12 @@ static void nlua_schedule_event(void **argv) static int nlua_schedule(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL { + // If Nvim is exiting don't schedule tasks to run in the future. Any refs + // allocated here will not be cleaned up otherwise + if (exiting) { + return 0; + } + if (lua_type(lstate, 1) != LUA_TFUNCTION) { lua_pushliteral(lstate, "vim.schedule: expected function"); return lua_error(lstate); diff --git a/src/nvim/option.c b/src/nvim/option.c index 23d5960579..d3a8e2ce73 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3183,23 +3183,6 @@ bool set_tty_option(const char *name, char *value) 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 /// /// @param[in] arg Option name. diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 36d6566c7d..7dce8473d5 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -124,7 +124,6 @@ void tinput_init(TermInput *input, Loop *loop) input->loop = loop; input->paste = 0; input->in_fd = STDIN_FILENO; - input->waiting_for_bg_response = 0; input->extkeys_type = kExtkeysNone; input->ttimeout = (bool)p_ttimeout; input->ttimeoutlen = p_ttm; @@ -579,113 +578,6 @@ static HandleState handle_bracketed_paste(TermInput *input) 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) { 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) { HandleState is_paste = kNotApplicable; - HandleState is_bc = kNotApplicable; do { if (!force && (handle_focus_event(input) - || (is_paste = handle_bracketed_paste(input)) != kNotApplicable - || (is_bc = handle_background_color(input)) != kNotApplicable)) { - if (is_paste == kIncomplete || is_bc == kIncomplete) { + || (is_paste = handle_bracketed_paste(input)) != kNotApplicable)) { + if (is_paste == kIncomplete) { // Wait for the next input, leaving it in the raw buffer due to an // incomplete sequence. return; diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 8b4d1ba74b..01514269be 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -24,7 +24,6 @@ typedef struct term_input { // Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk int8_t paste; bool ttimeout; - int8_t waiting_for_bg_response; int8_t waiting_for_csiu_response; ExtkeysType extkeys_type; OptInt ttimeoutlen; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 177ef0c3cf..8aab4d836c 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -133,7 +133,6 @@ struct TUIData { int reset_scroll_region; int set_cursor_style, reset_cursor_style; int save_title, restore_title; - int get_bg; int set_underline_style; int set_underline_color; 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.set_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.enable_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_keypad_xmit); 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 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 \ "\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 // ? 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 diff --git a/src/nvim/ui.c b/src/nvim/ui.c index dc38c061b0..3e5bfba315 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -623,7 +623,10 @@ Array ui_array(void) // TUI fields. (`stdin_fd` is intentionally omitted.) PUT(info, "term_name", CSTR_TO_OBJ(ui->term_name)); - PUT(info, "term_background", CSTR_TO_OBJ(ui->term_background)); + + // term_background is deprecated. Populate with an empty string + PUT(info, "term_background", CSTR_TO_OBJ("")); + PUT(info, "term_colors", INTEGER_OBJ(ui->term_colors)); PUT(info, "stdin_tty", BOOLEAN_OBJ(ui->stdin_tty)); PUT(info, "stdout_tty", BOOLEAN_OBJ(ui->stdout_tty)); diff --git a/src/nvim/ui.h b/src/nvim/ui.h index d399802c99..3feb0bf603 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -104,7 +104,8 @@ struct ui_t { // TUI fields. char *term_name; - char *term_background; + char *term_background; ///< Deprecated. No longer needed since background color detection happens + ///< in Lua. To be removed in a future release. int term_colors; bool stdin_tty; bool stdout_tty; diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index dac690822b..2f91257a5d 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -84,10 +84,7 @@ void ui_client_attach(int width, int height, char *term) if (term) { PUT_C(opts, "term_name", CSTR_AS_OBJ(term)); } - if (ui_client_bg_response != kNone) { - bool is_dark = (ui_client_bg_response == kTrue); - PUT_C(opts, "term_background", CSTR_AS_OBJ(is_dark ? "dark" : "light")); - } + PUT_C(opts, "term_colors", INTEGER_OBJ(t_colors)); if (!ui_client_is_remote) { PUT_C(opts, "stdin_tty", BOOLEAN_OBJ(stdin_isatty)); diff --git a/src/nvim/ui_client.h b/src/nvim/ui_client.h index fbee942cdf..db1ab463f8 100644 --- a/src/nvim/ui_client.h +++ b/src/nvim/ui_client.h @@ -31,10 +31,6 @@ EXTERN int ui_client_exit_status INIT( = 0); /// Whether ui client has sent nvim_ui_attach yet EXTERN bool ui_client_attached INIT( = false); -/// Whether ui client has gotten a response about the bg color of the terminal, -/// kTrue=dark, kFalse=light, kNone=no response yet -EXTERN TriState ui_client_bg_response INIT( = kNone); - /// The ui client should forward its stdin to the nvim process /// by convention, this uses fd=3 (next free number after stdio) EXTERN bool ui_client_forward_stdin INIT( = false); diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index a668d47448..6efb6726fe 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -36,8 +36,6 @@ describe('nvim_ui_attach()', function() pcall_err(meths.ui_attach, 80, 24, { term_name=true })) eq("Invalid 'term_colors': expected Integer, got Boolean", pcall_err(meths.ui_attach, 80, 24, { term_colors=true })) - eq("Invalid 'term_background': expected String, got Boolean", - pcall_err(meths.ui_attach, 80, 24, { term_background=true })) eq("Invalid 'stdin_fd': expected Integer, got String", pcall_err(meths.ui_attach, 80, 24, { stdin_fd='foo' })) eq("Invalid 'stdin_tty': expected Boolean, got String", diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua index 682eb48a27..960870fb46 100644 --- a/test/functional/terminal/tui_spec.lua +++ b/test/functional/terminal/tui_spec.lua @@ -2557,7 +2557,7 @@ describe('TUI bg color', function() | {3:-- TERMINAL --} | ]]) - feed_data('\027]11;rgb:ffff/ffff/ffff\007') + feed_data('\027]11;rgb:ffff/ffff/ffff\027\\') screen:expect{any='did OptionSet, yay!'} feed_data(':echo "new_bg=".&background\n') @@ -2610,7 +2610,7 @@ describe('TUI bg color', function() ]]) -- Send a background response with the Pt portion split. feed_data('\027]11;rgba:ffff/fff') - feed_data('f/ffff/8000\007') + feed_data('f/ffff/8000\027\\') screen:expect{any='did OptionSet, yay!'} feed_data(':echo "new_bg=".&background\n') @@ -2643,7 +2643,7 @@ describe('TUI bg color', function() | {3:-- TERMINAL --} | ]]) - feed_data('\027]11;rgba:ffff/foo/ffff/8000\007') + feed_data('\027]11;rgba:ffff/foo/ffff/8000\027\\') screen:expect_unchanged() feed_data(':echo "new_bg=".&background\n') diff --git a/test/functional/ui/options_spec.lua b/test/functional/ui/options_spec.lua index f3817856f7..6af1820430 100644 --- a/test/functional/ui/options_spec.lua +++ b/test/functional/ui/options_spec.lua @@ -210,22 +210,6 @@ describe('UI can set terminal option', function() screen = Screen.new(20,5) end) - it('term_background', function() - eq('dark', eval '&background') - - screen:attach {term_background='light'} - eq('light', eval '&background') - end) - - it("term_background but not if 'background' already set by user", function() - eq('dark', eval '&background') - command 'set background=dark' - - screen:attach {term_background='light'} - - eq('dark', eval '&background') - end) - it('term_name', function() eq('nvim', eval '&term') diff --git a/test/unit/tui_spec.lua b/test/unit/tui_spec.lua deleted file mode 100644 index 192e35a485..0000000000 --- a/test/unit/tui_spec.lua +++ /dev/null @@ -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) |