From c94992e3086da2a261457ad66ae60cd6a94a0152 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 29 Nov 2021 23:19:29 +0100 Subject: [PATCH] Initial commit --- init.lua | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 init.lua diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..236577c --- /dev/null +++ b/init.lua @@ -0,0 +1,241 @@ +local posix = { + termio = require("posix.termio"), + poll = require("posix.poll"), + unistd = require("posix.unistd"), +} + +local cutie = { + esc = string.char(27) .. "[", + terminal_size = nil, + buffer = "", + input = EventTarget() +} + +-- colors + +local function color_from_hue(hue) + local h = hue / 60 + local x = (1 - math.abs(h % 2 - 1)) + + local i = math.floor(h) + + if i == 0 then + return {1, x, 0} + elseif i == 1 then + return {x, 1, 0} + elseif i == 2 then + return {0, 1, x} + elseif i == 3 then + return {0, x, 1} + elseif i == 4 then + return {x, 0, 1} + else + return {1, 0, x} + end +end + +function cutie.to_color(color) + local t = type(color) + + if t == "number" then + return color_from_hue(color) + elseif t == "string" then + local color = color:gsub("#", "") + + return { + tonumber(color:sub(1, 2), 16) / 255, + tonumber(color:sub(3, 4), 16) / 255, + tonumber(color:sub(5, 6), 16) / 255, + } + else + return color + end +end + +function make_color(color, bg) + color = cutie.to_color(color) + + return cutie.esc + .. (bg and "48" or "38") .. ";2" + .. ";" .. math.clamp(math.floor(color[1] * 255), 0, 255) + .. ";" .. math.clamp(math.floor(color[2] * 255), 0, 255) + .. ";" .. math.clamp(math.floor(color[3] * 255), 0, 255) + .. "m" +end + +function cutie.color(color) + return make_color(color, false) +end + +function cutie.background_color(color) + return make_color(color, true) +end + +function cutie.set_color(color) + cutie.render(cutie.color(color)) +end + +function cutie.set_background(color) + cutie.render(cutie.background_color(color)) +end + +-- simple effects + +cutie.bold = cutie.esc .. "1m" +cutie.no_effects = cutie.esc .. "0m" + +function cutie.set_bold() + cutie.render(cutie.bold) +end + +function cutie.clear_effects() + cutie.render(cutie.no_effects) +end + +function cutie.move_cursor(x, y) + cutie.render_escape(math.floor(y) .. ";" .. math.floor(x) .. "H") +end + +function cutie.set_alternate_buffer(enabled) + cutie.render_escape("?1049" .. (enabled and "h" or "l")) +end + +function cutie.set_cursor_shown(enabled) + cutie.render_escape("?25" .. (enabled and "h" or "l")) +end + +-- input + +function cutie.set_canon_input(enabled) + local termios = posix.termio.tcgetattr(0) + + if enabled then + termios.lflag = bit32.bor(termios.lflag, + posix.termio.ICANON, + posix.termio.ECHO + ) + else + termios.lflag = bit32.band(termios.lflag, bit32.bnot(bit32.bor( + posix.termio.ICANON, + posix.termio.ECHO + ))) + end + + posix.termio.tcsetattr(0, posix.termio.TCSANOW, termios) +end + +function cutie.set_input_buffer(enabled) + lua_async.poll_functions[cutie.poll_input] = enabled or nil + + cutie.input.buffer = enabled and "" or nil + cutie.input.history = enabled and {} or nil + cutie.input.cursor = nil +end + +local function getchar() + return posix.unistd.read(0, 1) +end + +function cutie.poll_input() + local pfd = {[0] = {events = {IN = true}}} + posix.poll.poll(pfd, 0) + + if pfd[0].revents and pfd[0].revents.IN then + local char = getchar() + + if char == "\n" then + if input ~= "" then + cutie.input:dispatchEvent(Event("input", {input = cutie.input.buffer})) + table.insert(cutie.input.history, cutie.input.buffer) + cutie.input.buffer = "" + cutie.input.cursor = nil + end + elseif char == cutie.esc:sub(1, 1) then + local char2 = getchar() + + if char2 == cutie.esc:sub(2, 2) then + local char3 = getchar() + + if char3 == "A" or char3 == "B" then + cutie.input.cursor = (cutie.input.cursor or #cutie.input.history + 1) + (char3 == "A" and -1 or 1) + + if cutie.input.cursor > #cutie.input.history then + cutie.input.cursor = #cutie.input.history + 1 + end + + if cutie.input.cursor < 1 then + cutie.input.cursor = 1 + end + + cutie.input.buffer = cutie.input.history[cutie.input.cursor] or "" + end + end + elseif char == string.char(127) then + cutie.input.buffer = cutie.input.buffer:sub(1, #cutie.input.buffer - 1) + else + cutie.input.buffer = cutie.input.buffer .. char + end + end +end + +-- rendering + +function cutie.clear_screen() + cutie.render_escape("2J") +end + +function cutie.empty_screen() + cutie.move_cursor(1, 1) + + local size = cutie.get_terminal_size() + local str = (string.rep(" ", size[1]) .. "\n"):rep(size[2]) + str = str:sub(1, #str - 1) + + cutie.render(str) +end + +function cutie.render(text) + cutie.buffer = cutie.buffer .. text +end + +function cutie.render_escape(text) + cutie.render(cutie.esc .. text) +end + +function cutie.render_at(array, x, y) + for i, line in ipairs(array) do + cutie.move_cursor(x + 1, y + i) + cutie.render(line) + end +end + +function cutie.get_dimensions(array) + local width = 0 + + for _, line in pairs(array) do + width = math.max(width, #line) + end + + return {width, #array} +end + +function cutie.flush_buffer() + io.write(cutie.buffer) + io.stdout:flush() + cutie.buffer = "" +end + +-- terminal size + +function cutie.handle_resize() + local pf = io.popen("echo -ne \"cols\\nlines\" | tput -S", "r") + local size = pf:read("*all"):split("\n") + pf:close() + cutie.terminal_size = size +end + +function cutie.get_terminal_size() + return cutie.terminal_size +end + +return cutie -- 2.44.0