From 3e19acc41405d799eaf431ace6d6caa909955eaa Mon Sep 17 00:00:00 2001 From: Ashkan Kiani Date: Tue, 22 Oct 2019 21:27:01 -0700 Subject: Move dependencies to their own directory. (#21) --- lua/colorizer/nvim.lua | 193 +++++++++++++++++++++++++++++++++++++++ lua/colorizer/trie.lua | 242 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 435 insertions(+) create mode 100644 lua/colorizer/nvim.lua create mode 100644 lua/colorizer/trie.lua (limited to 'lua/colorizer') 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 . +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) -- cgit v1.2.3-70-g09d2