diff options
author | Josh Triplett <josh@joshtriplett.org> | 2016-07-12 22:52:10 -0700 |
---|---|---|
committer | Josh Triplett <josh@joshtriplett.org> | 2016-07-24 01:56:33 -0700 |
commit | 298608f88c463705cfd6ee47035c049dbb1d9fa0 (patch) | |
tree | 6c4fe7bafc57b400daf019a2dd24aa218815c66e | |
parent | ef72303a1ff862fde6d9399941c091c0a0692cce (diff) | |
download | rneovim-298608f88c463705cfd6ee47035c049dbb1d9fa0.tar.gz rneovim-298608f88c463705cfd6ee47035c049dbb1d9fa0.tar.bz2 rneovim-298608f88c463705cfd6ee47035c049dbb1d9fa0.zip |
Automatically detect terminal background and set bg=dark or bg=light
xterm-compatible terminals support reporting their configured colors
back to the application. Use this to obtain the current background
color, compute its luminance to classify it as light or dark, and set
'bg' accordingly. Also set the default for 'bg', so that `:set bg&`
will revert to that detected default.
-rw-r--r-- | src/nvim/option.c | 2 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 65 | ||||
-rw-r--r-- | src/nvim/tui/tui.c | 6 |
3 files changed, 71 insertions, 2 deletions
diff --git a/src/nvim/option.c b/src/nvim/option.c index 81f57522b3..5333c0291d 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -874,7 +874,7 @@ set_options_default ( /// @param name The name of the option /// @param val The value of the option /// @param allocated If true, do not copy default as it was already allocated. -static void set_string_default(const char *name, char *val, bool allocated) +void set_string_default(const char *name, char *val, bool allocated) FUNC_ATTR_NONNULL_ALL { int opt_idx = findoption((char_u *)name); diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index be256f3ebc..c41107d4d3 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -4,8 +4,10 @@ #include "nvim/api/vim.h" #include "nvim/api/private/helpers.h" #include "nvim/ascii.h" +#include "nvim/charset.h" #include "nvim/main.h" #include "nvim/misc2.h" +#include "nvim/option.h" #include "nvim/os/os.h" #include "nvim/os/input.h" #include "nvim/event/rstream.h" @@ -320,6 +322,66 @@ static bool handle_forced_escape(TermInput *input) return false; } +static void set_bg_deferred(void **argv) +{ + char *bgvalue = argv[0]; + set_string_default("bg", bgvalue, false); + if (!option_was_set((char_u *)"bg")) { + set_option_value((char_u *)"bg", 0, (char_u *)bgvalue, 0); + } +} + +static bool handle_background_color(TermInput *input) +{ + size_t count = 0; + size_t component = 0; + uint16_t rgb[] = { 0, 0, 0 }; + uint16_t rgb_max[] = { 0, 0, 0 }; + bool eat_backslash = false; + bool done = false; + bool bad = false; + if (rbuffer_size(input->read_stream.buffer) >= 9 + && !rbuffer_cmp(input->read_stream.buffer, "\x1b]11;rgb:", 9)) { + rbuffer_consumed(input->read_stream.buffer, 9); + RBUFFER_EACH(input->read_stream.buffer, c, i) { + count = i + 1; + 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 == '/') { + if (component < 3) { + component++; + } + } 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; + } + } + rbuffer_consumed(input->read_stream.buffer, count); + if (done && !bad && rgb_max[0] && rgb_max[1] && rgb_max[2]) { + 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 + char *bgvalue = luminance < 0.5 ? "dark" : "light"; + loop_schedule(&main_loop, event_create(1, set_bg_deferred, 1, bgvalue)); + } + return true; + } + return false; +} + static void restart_reading(void **argv); static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, @@ -351,7 +413,8 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, do { if (handle_focus_event(input) || handle_bracketed_paste(input) - || handle_forced_escape(input)) { + || handle_forced_escape(input) + || handle_background_color(input)) { continue; } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index d220df508a..c4efa69c4c 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -68,6 +68,7 @@ typedef struct { int enter_insert_mode, enter_replace_mode, exit_insert_mode; int set_rgb_foreground, set_rgb_background; int enable_focus_reporting, disable_focus_reporting; + int get_bg; } unibi_ext; } TUIData; @@ -125,6 +126,7 @@ static void terminfo_start(UI *ui) data->unibi_ext.exit_insert_mode = -1; data->unibi_ext.enable_focus_reporting = -1; data->unibi_ext.disable_focus_reporting = -1; + data->unibi_ext.get_bg = -1; data->out_fd = 1; data->out_isatty = os_isatty(data->out_fd); // setup unibilium @@ -140,6 +142,8 @@ static void terminfo_start(UI *ui) // Enter alternate screen and clear unibi_out(ui, unibi_enter_ca_mode); unibi_out(ui, unibi_clear_screen); + // Ask the terminal to send us the background color + unibi_out(ui, data->unibi_ext.get_bg); // Enable bracketed paste unibi_out(ui, data->unibi_ext.enable_bracketed_paste); // Enable focus reporting @@ -829,6 +833,8 @@ static void fix_terminfo(TUIData *data) data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, NULL, "\x1b[?1004l"); + data->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, NULL, "\x1b]11;?\x07"); + #define XTERM_SETAF \ "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m" #define XTERM_SETAB \ |