aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Triplett <josh@joshtriplett.org>2016-07-12 22:52:10 -0700
committerJosh Triplett <josh@joshtriplett.org>2016-07-24 01:56:33 -0700
commit298608f88c463705cfd6ee47035c049dbb1d9fa0 (patch)
tree6c4fe7bafc57b400daf019a2dd24aa218815c66e
parentef72303a1ff862fde6d9399941c091c0a0692cce (diff)
downloadrneovim-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.c2
-rw-r--r--src/nvim/tui/input.c65
-rw-r--r--src/nvim/tui/tui.c6
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 \