Last active
November 5, 2021 20:16
-
-
Save sunjon/b88e28e964fbae5273e11976b4714383 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env luajit | |
local TOTAL_COLORS = 256 | |
local char = string.char | |
local io_read = io.read | |
local byte = string.byte | |
local INDEX_MAX_DIGITS = #(tostring(TOTAL_COLORS)) + 1 | |
-- Ascii decimal value lookup | |
local ascii = { | |
BEL = 7, | |
ESC = 27, | |
NUM_FOUR = 52, | |
SEMICOLON = 59, | |
QUESTIONMARK = 63, | |
BACKSLASH = 92, | |
RBRACKET = 93, | |
} | |
-- control sequences | |
local RGB_START = { ascii.ESC, ascii.RBRACKET, ascii.NUM_FOUR, ascii.SEMICOLON } | |
local RGB_END = { ascii.ESC, ascii.BACKSLASH } | |
local OS_CMD_START = char(ascii.ESC) .. char(ascii.RBRACKET) .. char(ascii.NUM_FOUR) | |
local OS_CMD_END = char(ascii.BACKSLASH) .. char(ascii.BEL) | |
-- | |
local util = {} | |
util.to_string = function(byte_array) | |
local s = "" | |
for i = 1, #byte_array do | |
s = s .. char(byte_array[i]) | |
end | |
return s | |
end | |
-- shallow check if two tables are identical | |
util.match = function(a, b) | |
if #a ~= #b then | |
return nil | |
end | |
for i = 1, #a do | |
if a[i] ~= b[i] then | |
return false | |
end | |
end | |
return true | |
end | |
-- consumes n bytes from the IO stream | |
util.chomp = function(n) -- TODO: stop using string | |
local bytes = assert({ byte(io_read(n), 1, n) }, "read_error") | |
if bytes[n] then | |
return bytes | |
else | |
return nil | |
end | |
end | |
-- Terminal | |
local terminal = {} | |
terminal.setrawmode = function() | |
return os.execute "stty raw -echo 2> /dev/null" | |
end | |
terminal.savemode = function() | |
local handle = assert(io.popen("stty -g", "r")) | |
local mode = assert(handle:read "*all") | |
local success, e, msg = handle:close() | |
-- print(inspect(mode)) | |
return success and mode or nil, e, msg -- TODO: handle all errors like this | |
end | |
terminal.restoremode = function(mode) | |
return os.execute("stty " .. mode) | |
end | |
-- | |
-- Args come in as a single 'index1;rgb1 ... ;indexN;rgbN' string. | |
-- | |
local function get_color_entry(index) | |
local b = util | |
if not b.match(b.chomp(4), RGB_START) then | |
error "NO HEADER FOUND" | |
return nil | |
end | |
local color_id = {} | |
local c = nil | |
for i = 1, INDEX_MAX_DIGITS + 1 do | |
c = b.chomp(1)[1] | |
if c == ascii.SEMICOLON then | |
break | |
else | |
color_id[i] = c | |
end | |
end | |
if color_id == {} then | |
error("Error: Index not found at " .. index .. "/" .. TOTAL_COLORS) | |
return nil | |
end | |
-- get the bytes containing the RGB values | |
local hex_color | |
local chunk_bytes = b.chomp(20) | |
-- check for the end marker | |
if b.match({ chunk_bytes[19], chunk_bytes[20] }, RGB_END) then | |
local rgb_values = { | |
-- parse RGB from chunk: 'rgb:xxRR/xxGG/xxBB' | |
chunk_bytes[7], | |
chunk_bytes[8], | |
chunk_bytes[12], | |
chunk_bytes[13], | |
chunk_bytes[17], | |
chunk_bytes[18], | |
} | |
-- id = tonumber(b.to_string(color_id)) | |
hex_color = "#" .. b.to_string(rgb_values) | |
else | |
error("DEBUG: " .. b.to_string(chunk_bytes)) | |
end | |
return hex_color | |
end | |
-- send escape sequence to query palette | |
local function osc_query_palette() | |
-- build the query string | |
local query = OS_CMD_START | |
for idx = 0, TOTAL_COLORS do | |
query = query .. char(ascii.SEMICOLON) .. idx .. char(ascii.SEMICOLON) .. char(ascii.QUESTIONMARK) | |
end | |
query = query .. OS_CMD_END | |
-- print('DEBUG: '..query) | |
-- write arguments to stdout, then flush. | |
io.write(query) | |
io.flush() | |
end | |
local function get_term_colors() | |
local mode, _ = terminal.savemode() | |
terminal.setrawmode() | |
osc_query_palette() | |
local results = {} | |
for i = 1, TOTAL_COLORS do | |
results[i] = get_color_entry(i) | |
end | |
-- local results = get_term_colors() | |
terminal.restoremode(mode) | |
print(#results) | |
-- | |
for i, hex_color in ipairs(results) do | |
print(string.format("[%s] - %s", i - 1, hex_color)) | |
end | |
end | |
get_term_colors() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment