Skip to content

Instantly share code, notes, and snippets.

@sunjon
Created November 7, 2021 20:27
Show Gist options
  • Save sunjon/ffc141f5e09a72134909b5b84f114a00 to your computer and use it in GitHub Desktop.
Save sunjon/ffc141f5e09a72134909b5b84f114a00 to your computer and use it in GitHub Desktop.
-- OSC 4 Color Parser for Neovim
-- Copyright Senghan Bright 2021
local uv = vim.loop
-- check if COLORTERM is advertised by the terminal emulator
local colorterm = os.getenv("COLORTERM")
if not (colorterm == "truecolor") then
error("Truecolor environment not found. Ensure your terminal enables the 'COLORTERM' environment variable.")
end
if not vim.o.termguicolors then
error("`termguicolors` option is not set. 256 color mode only works for RGB UIs.")
end
-- Ascii decimal value lookup
local char = string.char
local ascii = {
BEL = char(7),
ESC = char(27),
NUM_FOUR = char(52),
BACKSLASH = char(92),
RBRACKET = char(93),
}
local OS_CMD_START = ascii.ESC .. ascii.RBRACKET .. ascii.NUM_FOUR
local OS_CMD_END = ascii.BACKSLASH .. ascii.BEL
--
local function stty_cmd(fd, cmd)
local sys = vim.fn.system
local stty_bin = "stty"
local cmd_str = ("%s --file %s %s"):format(stty_bin, fd, cmd)
return sys(cmd_str)
end
local function parse_rgb_entries(data)
local rgb_pattern = "(%d+;rgb:%x+/%x+/%x+)"
local color_pattern = "%x%x(%x%x)"
local idx, rgb_str
local res = {}
for rgb_entry in data:gmatch(rgb_pattern) do
idx = rgb_entry:match ".-(%d+);"
rgb_str = "#"
for c in rgb_entry:gmatch(color_pattern) do
rgb_str = rgb_str .. c
end
res[idx] = rgb_str
end
return res
end
local function get_colors()
local nvim_pid = vim.fn.getpid()
local ppid = vim.api.nvim_get_proc(nvim_pid).ppid
local fd = ("/proc/%d/fd/0"):format(ppid)
-- save current mode settings and set raw mode
local orig_mode = stty_cmd(fd, "--save")
stty_cmd(fd, "raw -echo")
-- open connection to STTY file
local file_handle = assert(uv.fs_open(fd, "r+", 438))
local TTY_BUF_READ_SIZE = 8192
local chunk_size = 32
local res = {}
local query, data, chunk_results
for j = 0, 255, chunk_size do
-- build query string
query = OS_CMD_START
for idx = j + 0, j + chunk_size do
query = query .. (";%d;?"):format(idx)
end
query = query .. OS_CMD_END
assert(uv.fs_write(file_handle, query))
-- read response
data = assert(uv.fs_read(file_handle, TTY_BUF_READ_SIZE))
chunk_results = parse_rgb_entries(data)
for i, r in pairs(chunk_results) do
res[i + 1] = r
end
end
-- restore original TTY mode
stty_cmd(fd, orig_mode)
return res
end
local terminal_colors = get_colors()
local term_color
for i, color in ipairs(terminal_colors) do
term_color = ("terminal_color_%d"):format(i-1)
vim.g[term_color] = color
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment