aboutsummaryrefslogtreecommitdiff
path: root/lua/colorizer
diff options
context:
space:
mode:
Diffstat (limited to 'lua/colorizer')
-rw-r--r--lua/colorizer/nvim.lua193
-rw-r--r--lua/colorizer/trie.lua242
2 files changed, 435 insertions, 0 deletions
diff --git a/lua/colorizer/nvim.lua b/lua/colorizer/nvim.lua
new file mode 100644
index 0000000..c51d2ca
--- /dev/null
+++ b/lua/colorizer/nvim.lua
@@ -0,0 +1,193 @@
+--- Module of magic functions for nvim
+-- @module nvim
+
+-- Equivalent to `echo vim.inspect(...)`
+local function nvim_print(...)
+ if select("#", ...) == 1 then
+ vim.api.nvim_out_write(vim.inspect((...)))
+ else
+ vim.api.nvim_out_write(vim.inspect {...})
+ end
+ vim.api.nvim_out_write("\n")
+end
+
+--- Equivalent to `echo` EX command
+local function nvim_echo(...)
+ for i = 1, select("#", ...) do
+ local part = select(i, ...)
+ vim.api.nvim_out_write(tostring(part))
+ -- vim.api.nvim_out_write("\n")
+ vim.api.nvim_out_write(" ")
+ end
+ vim.api.nvim_out_write("\n")
+end
+
+local window_options = {
+ arab = true; arabic = true; breakindent = true; breakindentopt = true;
+ bri = true; briopt = true; cc = true; cocu = true;
+ cole = true; colorcolumn = true; concealcursor = true; conceallevel = true;
+ crb = true; cuc = true; cul = true; cursorbind = true;
+ cursorcolumn = true; cursorline = true; diff = true; fcs = true;
+ fdc = true; fde = true; fdi = true; fdl = true;
+ fdm = true; fdn = true; fdt = true; fen = true;
+ fillchars = true; fml = true; fmr = true; foldcolumn = true;
+ foldenable = true; foldexpr = true; foldignore = true; foldlevel = true;
+ foldmarker = true; foldmethod = true; foldminlines = true; foldnestmax = true;
+ foldtext = true; lbr = true; lcs = true; linebreak = true;
+ list = true; listchars = true; nu = true; number = true;
+ numberwidth = true; nuw = true; previewwindow = true; pvw = true;
+ relativenumber = true; rightleft = true; rightleftcmd = true; rl = true;
+ rlc = true; rnu = true; scb = true; scl = true;
+ scr = true; scroll = true; scrollbind = true; signcolumn = true;
+ spell = true; statusline = true; stl = true; wfh = true;
+ wfw = true; winbl = true; winblend = true; winfixheight = true;
+ winfixwidth = true; winhighlight = true; winhl = true; wrap = true;
+}
+
+-- `nvim.$method(...)` redirects to `nvim.api.nvim_$method(...)`
+-- `nvim.fn.$method(...)` redirects to `vim.api.nvim_call_function($method, {...})`
+-- TODO `nvim.ex.$command(...)` is approximately `:$command {...}.join(" ")`
+-- `nvim.print(...)` is approximately `echo vim.inspect(...)`
+-- `nvim.echo(...)` is approximately `echo table.concat({...}, '\n')`
+-- Both methods cache the inital lookup in the metatable, but there is a small overhead regardless.
+return setmetatable({
+ print = nvim_print;
+ echo = nvim_echo;
+ fn = setmetatable({}, {
+ __index = function(self, k)
+ local mt = getmetatable(self)
+ local x = mt[k]
+ if x ~= nil then
+ return x
+ end
+ local f = function(...) return vim.api.nvim_call_function(k, {...}) end
+ mt[k] = f
+ return f
+ end
+ });
+ buf = setmetatable({
+ }, {
+ __index = function(self, k)
+ local mt = getmetatable(self)
+ local x = mt[k]
+ if x ~= nil then return x end
+ local f
+ if k == 'line' then
+ f = function()
+ local pos = vim.api.nvim_win_get_cursor(0)
+ return vim.api.nvim_buf_get_lines(0, pos[1]-1, pos[1], 'line')[1]
+ end
+ elseif k == 'nr' then
+ f = vim.api.nvim_get_current_buf
+ end
+ mt[k] = f
+ return f
+ end
+ });
+ ex = setmetatable({}, {
+ __index = function(self, k)
+ local mt = getmetatable(self)
+ local x = mt[k]
+ if x ~= nil then
+ return x
+ end
+ local command = k:gsub("_$", "!")
+ local f = function(...)
+ return vim.api.nvim_command(table.concat(vim.tbl_flatten {command, ...}, " "))
+ end
+ mt[k] = f
+ return f
+ end
+ });
+ g = setmetatable({}, {
+ __index = function(_, k)
+ return vim.api.nvim_get_var(k)
+ end;
+ __newindex = function(_, k, v)
+ if v == nil then
+ return vim.api.nvim_del_var(k)
+ else
+ return vim.api.nvim_set_var(k, v)
+ end
+ end;
+ });
+ v = setmetatable({}, {
+ __index = function(_, k)
+ return vim.api.nvim_get_vvar(k)
+ end;
+ __newindex = function(_, k, v)
+ return vim.api.nvim_set_vvar(k, v)
+ end
+ });
+ b = setmetatable({}, {
+ __index = function(_, k)
+ return vim.api.nvim_buf_get_var(0, k)
+ end;
+ __newindex = function(_, k, v)
+ if v == nil then
+ return vim.api.nvim_buf_del_var(0, k)
+ else
+ return vim.api.nvim_buf_set_var(0, k, v)
+ end
+ end
+ });
+ w = setmetatable({}, {
+ __index = function(_, k)
+ return vim.api.nvim_win_get_var(0, k)
+ end;
+ __newindex = function(_, k, v)
+ if v == nil then
+ return vim.api.nvim_win_del_var(0, k)
+ else
+ return vim.api.nvim_win_set_var(0, k, v)
+ end
+ end
+ });
+ o = setmetatable({}, {
+ __index = function(_, k)
+ return vim.api.nvim_get_option(k)
+ end;
+ __newindex = function(_, k, v)
+ return vim.api.nvim_set_option(k, v)
+ end
+ });
+ -- TODO add warning if you try to use a window option here?
+ bo = setmetatable({}, {
+ __index = function(_, k)
+ return vim.api.nvim_buf_get_option(0, k)
+ end;
+ __newindex = function(_, k, v)
+ return vim.api.nvim_buf_set_option(0, k, v)
+ end
+ });
+ wo = setmetatable({}, {
+ __index = function(_, k)
+ return vim.api.nvim_win_get_option(0, k)
+ end;
+ __newindex = function(_, k, v)
+ -- passing v == nil will clear the value, just like above.
+ return vim.api.nvim_win_set_option(0, k, v)
+ end
+ });
+ env = setmetatable({}, {
+ __index = function(_, k)
+ return vim.api.nvim_call_function('getenv', {k})
+ end;
+ __newindex = function(_, k, v)
+ return vim.api.nvim_call_function('setenv', {k, v})
+ end
+ });
+}, {
+ __index = function(self, k)
+ local mt = getmetatable(self)
+ local x = mt[k]
+ if x ~= nil then
+ return x
+ end
+ local f = vim.api['nvim_'..k]
+ mt[k] = f
+ return f
+ end
+})
+
+
diff --git a/lua/colorizer/trie.lua b/lua/colorizer/trie.lua
new file mode 100644
index 0000000..21794ef
--- /dev/null
+++ b/lua/colorizer/trie.lua
@@ -0,0 +1,242 @@
+--- Trie implementation in luajit
+-- Copyright © 2019 Ashkan Kiani
+
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+-- GNU General Public License for more details.
+
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see <http://www.gnu.org/licenses/>.
+local ffi = require 'ffi'
+
+ffi.cdef [[
+struct Trie {
+ bool is_leaf;
+ struct Trie* character[62];
+};
+void *malloc(size_t size);
+void free(void *ptr);
+]]
+
+local Trie_t = ffi.typeof('struct Trie')
+local Trie_ptr_t = ffi.typeof('$ *', Trie_t)
+local Trie_size = ffi.sizeof(Trie_t)
+
+local function trie_create()
+ local ptr = ffi.C.malloc(Trie_size)
+ ffi.fill(ptr, Trie_size)
+ return ffi.cast(Trie_ptr_t, ptr)
+end
+
+local function trie_destroy(trie)
+ if trie == nil then
+ return
+ end
+ for i = 0, 61 do
+ local child = trie.character[i]
+ if child ~= nil then
+ trie_destroy(child)
+ end
+ end
+ ffi.C.free(trie)
+end
+
+local INDEX_LOOKUP_TABLE = ffi.new 'uint8_t[256]'
+local CHAR_LOOKUP_TABLE = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
+do
+ local b = string.byte
+ for i = 0, 255 do
+ if i >= b'0' and i <= b'9' then
+ INDEX_LOOKUP_TABLE[i] = i - b'0'
+ elseif i >= b'A' and i <= b'Z' then
+ INDEX_LOOKUP_TABLE[i] = i - b'A' + 10
+ elseif i >= b'a' and i <= b'z' then
+ INDEX_LOOKUP_TABLE[i] = i - b'a' + 10 + 26
+ else
+ INDEX_LOOKUP_TABLE[i] = 255
+ end
+ end
+end
+
+local function trie_insert(trie, value)
+ if trie == nil then return false end
+ local node = trie
+ for i = 1, #value do
+ local index = INDEX_LOOKUP_TABLE[value:byte(i)]
+ if index == 255 then
+ return false
+ end
+ if node.character[index] == nil then
+ node.character[index] = trie_create()
+ end
+ node = node.character[index]
+ end
+ node.is_leaf = true
+ return node, trie
+end
+
+local function trie_search(trie, value, start)
+ if trie == nil then return false end
+ local node = trie
+ for i = (start or 1), #value do
+ local index = INDEX_LOOKUP_TABLE[value:byte(i)]
+ if index == 255 then
+ return
+ end
+ local child = node.character[index]
+ if child == nil then
+ return false
+ end
+ node = child
+ end
+ return node.is_leaf
+end
+
+local function trie_longest_prefix(trie, value, start)
+ if trie == nil then return false end
+ -- insensitive = insensitive and 0x20 or 0
+ start = start or 1
+ local node = trie
+ local last_i = nil
+ for i = start, #value do
+ local index = INDEX_LOOKUP_TABLE[value:byte(i)]
+-- local index = INDEX_LOOKUP_TABLE[bor(insensitive, value:byte(i))]
+ if index == 255 then
+ break
+ end
+ local child = node.character[index]
+ if child == nil then
+ break
+ end
+ if child.is_leaf then
+ last_i = i
+ end
+ node = child
+ end
+ if last_i then
+ -- Avoid a copy if the whole string is a match.
+ if start == 1 and last_i == #value then
+ return value
+ else
+ return value:sub(start, last_i)
+ end
+ end
+end
+
+local function trie_extend(trie, t)
+ assert(type(t) == 'table')
+ for _, v in ipairs(t) do
+ trie_insert(trie, v)
+ end
+end
+
+--- Printing utilities
+
+local function index_to_char(index)
+ if index < 0 or index > 61 then return end
+ return CHAR_LOOKUP_TABLE:sub(index+1, index+1)
+end
+
+local function trie_as_table(trie)
+ if trie == nil then
+ return nil
+ end
+ local children = {}
+ for i = 0, 61 do
+ local child = trie.character[i]
+ if child ~= nil then
+ local child_table = trie_as_table(child)
+ child_table.c = index_to_char(i)
+ table.insert(children, child_table)
+ end
+ end
+ return {
+ is_leaf = trie.is_leaf;
+ children = children;
+ }
+end
+
+local function print_trie_table(s)
+ local mark
+ if not s then
+ return {'nil'}
+ end
+ if s.c then
+ if s.is_leaf then
+ mark = s.c.."*"
+ else
+ mark = s.c.."─"
+ end
+ else
+ mark = "├─"
+ end
+ if #s.children == 0 then
+ return {mark}
+ end
+ local lines = {}
+ for _, child in ipairs(s.children) do
+ local child_lines = print_trie_table(child, thicc)
+ for _, child_line in ipairs(child_lines) do
+ table.insert(lines, child_line)
+ end
+ end
+ local child_count = 0
+ for i, line in ipairs(lines) do
+ local line_parts = {}
+ if line:match("^%w") then
+ child_count = child_count + 1
+ if i == 1 then
+ line_parts = {mark}
+ elseif i == #lines or child_count == #s.children then
+ line_parts = {"└─"}
+ else
+ line_parts = {"├─"}
+ end
+ else
+ if i == 1 then
+ line_parts = {mark}
+ elseif #s.children > 1 and child_count ~= #s.children then
+ line_parts = {"│ "}
+ else
+ line_parts = {" "}
+ end
+ end
+ table.insert(line_parts, line)
+ lines[i] = table.concat(line_parts)
+ end
+ return lines
+end
+
+local function trie_to_string(trie)
+ if trie == nil then
+ return 'nil'
+ end
+ local as_table = trie_as_table(trie)
+ return table.concat(print_trie_table(as_table), '\n')
+end
+
+local Trie_mt = {
+ __new = function(_, init)
+ local trie = trie_create()
+ if type(init) == 'table' then
+ trie_extend(trie, init)
+ end
+ return trie
+ end;
+ __index = {
+ insert = trie_insert;
+ search = trie_search;
+ longest_prefix = trie_longest_prefix;
+ extend = trie_extend;
+ };
+ __tostring = trie_to_string;
+ __gc = trie_destroy;
+}
+
+return ffi.metatype('struct Trie', Trie_mt)