This commit is contained in:
Andrea Blankenstijn 2022-07-09 00:12:39 +02:00
parent 78bfe2b325
commit da338e6104
17 changed files with 110 additions and 285 deletions

7
.gitignore vendored
View File

@ -1,7 +1,8 @@
/*
!/install.lua
!/lua/
!/tests/
!/History.md
!/LICENSE
!/README.md
!/install.lua
!/lua/
!/meta
!/tests/

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "nvim-api-annotations"]
path = meta/nvim
url = git@git.disroot.org:soratobuneko/fork-lua-dev.nvim.git

View File

@ -14,6 +14,11 @@
"/usr/share/nvim/runtime/lua",
"/usr/share/nvim/runtime/lua/vim",
"/usr/share/nvim/runtime/lua/vim/lsp",
"~/.local/share/nvim/site/pack/packer/start/packer.nvim/lua"
]
"~/.local/share/nvim/site/pack/?/start/?/lua",
"~/.local/share/nvim/site/pack/?/opt/?/lua"
],
"Lua.workspace.maxPreload": 1000,
"Lua.workspace.preloadFileSize": 300,
"Lua.completion.callSnippet": "Both",
"Lua.telemetry.enable": false
}

View File

@ -6,9 +6,14 @@ local hsv2 = {}
---Init HSV2
---@generic config_t: table
---@param config config_t
local function on_event()
end
function hsv2:init(config)
self._store = require("hsv2.utils.store"):new()
---@class hsv2.global_store: hsv2.object_t.
self._store = require("hsv2.prototypes.object"):new()
---@class hsv2.global_store: hsv2.object_t
self._store = {
config = require("hsv2.prototypes.config"):new(),
enums = require("hsv2.enums"):new(),
@ -17,6 +22,8 @@ function hsv2:init(config)
}
self._store.uevent:init(self._store)
self._store.config:init(self._store)
self._store.log:init(self._store)
self._store.config:set(config)

View File

@ -7,14 +7,14 @@ local enums = {}
local const_tbl = require("hsv2.utils.const")
---@alias hsv2.uevent_t
---| "config_changed"
---| "key_remap"
---| "config-changed"
---| "key-doremap"
---@class hsv2.uevent.types
---@field config_changed string triggered on configuration change
---@field key_remap string key mapping should be redone
enums.uevent = {
config_changed = "HSV2ConfigChanged",
key_remap = "HSV2KeyRemap",
["config-changed"] = "HSV2ConfigChanged",
["key-doremap"] = "HSV2KeyRemap",
}
enums.uevents = const_tbl(enums.uevents)

View File

@ -1,7 +1,7 @@
-- vi: et ts=4 sw=4:
-- hsv-2
---@module "hsv2.utils.log"
---@class hsv2.log: hsv2.object_t
---@class hsv2.log: hsv2.with_store_t
local log = {}
local L = {}
@ -23,11 +23,12 @@ function log:init(store)
end
---Log message at given log level
---@param msg echo_str[]|string
---@param msg echo_str[]
---@param level? hsv2.log_level_t
function log:write(msg, level)
msg = type(msg) == "string" and { { msg } } or msg
local io = require("hsv2.utils.io")
level = level or "notice"
if L.level_cmp(self, level, log._config.level) <= 0 then
local msg_with_prefix = vim.list_extend(L.msg_prefix(level), msg)
io.echo(msg_with_prefix, true)
@ -48,7 +49,7 @@ end
---Takes a log level name or priority and return the level name if it exists or
---defaults to "notice".
---@param level? hsv2.log_level_t|integer
---@param level hsv2.log_level_t|integer
---@return hsv2.log_level_t level `"notice"`: if not a valid log level - `"debug"` for "all" - `level` if param is a valid one
---@nodiscard
function L.level_get(self, level)
@ -74,11 +75,11 @@ function L.level_get(self, level)
end
---Get log message prefix string
---@param level? hsv2.log_level_t
---@param level hsv2.log_level_t
---@return echo_str[] prefix
---@nodiscard
function L.msg_prefix(level)
level = L.level_get(level)
function L.msg_prefix(self, level)
level = L.level_get(self, level)
local prefix = {
{ "HSV2:", "Title" },
{ level },
@ -105,4 +106,7 @@ function L.get_conf_change_cb(self)
end
end
return require("hsv2.prototypes.object"):new(log)
require("hsv2.utils.multi_inherit")(log,
require("hsv2.prototypes.with_store"))
return log

View File

@ -14,10 +14,9 @@ end
function config:set(conf, dont_exec_aucmds)
vim.tbl_deep_extend("force", self._config, conf)
if not dont_exec_aucmds then
vim.api.nvim_exec_autocmds("User", {
pattern = require("hsv2.events").config_changed,
group = "hsv2",
})
---@type hsv2.uevent_utils_t
local uev = self:store("uevent")
uev:trigger("config_changed")
end
end
@ -27,5 +26,7 @@ function config:init(store)
self:_set_store(store)
end
return require("hsv2.utils.multi_inherit")(config,
require("hsv2.utils.multi_inherit")(config,
require("hsv2.prototypes.with_store"))
return config

View File

@ -4,7 +4,7 @@
---@class hsv2.with_store_t
local with_store = {}
---@generic store: hsv2.store_t
---@generic store: hsv2.object_t
---@param store? store
---@return store|nil
function with_store:_set_store(store)
@ -23,14 +23,15 @@ function with_store:store_add(value, key)
error("cannot overwrite store[" .. key .. "]", 2)
end
---@generic store: hsv2.store_t
---@generic store: hsv2.object_t
---@generic item: hsv2.object_t
---@param ... string table key path
---@return hsv2.object_t
---@return item
function with_store:store(...)
if #... == 0 then
if ... == nil then
return self._store
end
return vim.tbl_get(self:_set_store(), ...)
return vim.tbl_get(self:store(), ...)
end
return with_store

View File

@ -1,13 +0,0 @@
-- vi: et ts=4 sw=4:
-- hsv-2
---@module "hsv2.utils"
local M = {
asserts = require("hsv2.utils.asserts"),
generics = require("hsv2.utils.generics"),
io = require("hsv2.utils.io"),
paths = require("hsv2.utils.paths"),
str = require("hsv2.utils.str"),
tables = require("hsv2.utils.tables"),
}
return M

View File

@ -6,7 +6,7 @@ local M = {}
---Assert a given value is one of given types.
---@param value any The value to check.
---@param expected types|type Type name or list of type names.
---@param expected type|type[] Type name or list of type names.
---@param name string Value name for error message.
---@param opt? boolean Set the value as optional (allow nil).
---@return type value_type Value type.

View File

@ -19,13 +19,13 @@ end
---Clone a function with its upvalues
---@param fn function
---@return function
---@return function?
---@nodiscard
function L.clone_function(fn)
local dumped = string.dump(fn)
local cloned = loadstring(dumped)
local i = 1
while true do
while cloned and true do
local name = debug.getupvalue(fn, i)
if not name then
break

View File

@ -6,8 +6,9 @@ local priv = {}
---@generic D: table
---@param class C
---@param ... D[]
---@return C|D
local function compose_class(class, ...)
local args = ...
local args = { ... }
class = class or {}
setmetatable(class, {
@ -22,6 +23,8 @@ local function compose_class(class, ...)
setmetatable(t, class)
return t
end
return class
end
function priv.search_parents(key, parents)

View File

@ -1,37 +1,39 @@
-- vi: et sw=4 ts=4:
-- hsv2
---@module "hsv2.utils.paths"
local M = {}
local paths = {}
local str = require("hsv2.utils.str")
local asserts = require("hsv2.utils.asserts")
---@alias path_raw string|number
---@alias path path_raw[]
---@alias path table<integer, path_raw>
---Parse an index number, dot separated keys into a list of keys.
---@param raw_path? path|path_raw Path component, or dot separated key names to parse.
---@return path? path Returns the path list of keys or nil if none.
---@param raw_path? path_raw Path component, or dot separated key names to parse.
---@return path? path Returns the path list of keys or nil if none.
---@nodiscard
function M.parse(raw_path)
local path_type = asserts.type(raw_path, {
function paths.parse(raw_path)
asserts.type(raw_path, {
"string",
"number",
"table",
}, "path", true)
local path = path_type == "string" and str.split(raw_path, "%.")
or path_type == "number" and { raw_path }
or path_type == "table" and raw_path or {}
local path = type(raw_path) == "string" and str.split(raw_path, "%.")
or type(raw_path) == "number" and { raw_path }
or type(raw_path) == "table" and raw_path or {}
return next(path) and path or nil
end
---Returns string representation of a path.
---@param path path|path_raw Path to convert to string
---@param path path Path to convert to string
---@param prefix? string
---@param dont_parse_str? boolean if false (default) parse and unparse prefix
---@return string
---@nodiscard
function M.to_string(path, str, dont_parse_str)
function paths.to_string(path, prefix, dont_parse_str)
asserts.type(path, {
"string",
"number",
@ -39,16 +41,14 @@ function M.to_string(path, str, dont_parse_str)
}, "path")
asserts.type(str, "string", "str", true)
path = M.parse(path)
local parsed_path = paths.parse(path)
local str = prefix or ""
local parsed_str = M.parse(str)
str = parsed_str and (dont_parse_str
and (str or "")
or M.to_string(parsed_str, nil, true)) or ""
str = not dont_parse_str and paths.to_string(assert(paths.parse(str))) or str
if not path then return str end
for _, v in ipairs(path) do
for _, v in ipairs(parsed_path) do
str = str .. (str ~= "" and "." or "")
str = str .. v
end
@ -61,9 +61,9 @@ end
---@param path2 path
---@return boolean|number comp `true`: paths are equals - `1`: 1st contains 2nd - `-1`: 2nd contains 1st - `false` paths are not related
---@nodiscard
function M.compare(path1, path2)
path1 = M.parse(path1) or {}
path2 = M.parse(path2) or {}
function paths.compare(path1, path2)
path1 = paths.parse(path1) or {}
path2 = paths.parse(path2) or {}
for i, key in ipairs(path1) do
if path2[i] ~= key then
return i > 1 and -1
@ -73,4 +73,4 @@ function M.compare(path1, path2)
return #path2 > #path1 and 1 or true
end
return M
return paths

View File

@ -1,96 +1,20 @@
-- vi: et sw=4 ts=4:
-- hsv2
---@module "hsv2.utils.tables"
local M = {}
---@class hsv2.table_t: hsv2.object_t
local table_ext = {}
local L = {}
---Deep copy a table.
---@param t1 table
---@return table t2 Copy of t1
---@nodiscard
function M.copy(t1)
local asserts = require("hsv2.utils.asserts")
asserts.type(t1, "table", "t1")
local t2 = {}
M.rmap(t1, function(_, path, _, value)
L.set(t2, path, value)
end)
return t2
end
---Set default values when there's no current ones.
---@param t1 table
---@param path? path
---@param defaults table
---@return table t1
function M.fill_defaults(t1, path, defaults)
M.rmap(defaults, function(_, rmap_path, _, default)
local current, status = L.get(t1, rmap_path)
if (current == nil or not status) and default ~= nil then
L.set(t1, rmap_path, default)
end
end, path)
return t1
end
---Get value from a table with optional default one.
---@param t1 table Table to access.
---@param path? path|path_raw Table path to access.
---@param defaults? any
---@param table_root? boolean
---@return any value? Retuns the value at given path if table_root is false. t1 otherwise
---@nodiscard
function M.get(t1, path, defaults, table_root)
local a = require("hsv2.utils.asserts")
a.type(t1, "table", "t1")
a.type(table_root, "boolean", "table_root", true)
local paths = require("hsv2.utils.paths")
path = paths.parse(path)
if type(defaults) == "table" and next(defaults) then
M.fill_defaults(t1, path, defaults)
end
if not path then
return t1, true
end
local current_value, status, msg = L.get(t1, path)
local default_value = defaults
if type(defaults) == "table" then
default_value = L.get(defaults, path)
end
if not status and defaults == nil then
return table_root and t1 or nil, true, msg
elseif current_value == nil then
L.set(t1, path, default_value)
current_value = default_value
msg = default_value ~= nil and "default value used"
or not status and msg
or nil
end
return table_root and t1 or current_value, true, msg
end
---For (".", true) returns true.
---For ("foo.bar.baz", { 1 }) returns { foo = { bar = { baz = { 1 } }} }.
---@param path path|path_raw
---@param path? path
---@param value any
---@return table|any
---@nodiscard
function M.nest_value(path, value)
function table_ext.nest_value(path, value)
path = require("hsv2.utils.paths").parse(path)
if not path then return value end
local t1 = {}
L.set(t1, path, value)
return t1
return L.set({}, path, value)
end
---Check if t1 has a given key
@ -98,14 +22,11 @@ end
---@param key string
---@return boolean
---@nodiscard
function M.one_of_keys(key, t1)
assert(type(t1) == "table")
for k in pairs(t1) do
if key == k then
return true
end
end
return false
function table_ext.one_of_keys(key, t1)
local res = vim.tbl_map(function(k)
return k == key or nil
end, vim.tbl_keys(t1))
return res and next(res) ~= nil or false
end
---Check if value is one of values
@ -113,123 +34,11 @@ end
---@param expected any[] A lists of possible values.
---@return boolean
---@nodiscard
function M.one_of_values(value, expected)
for _, v in pairs(expected) do
if value == v then
return true
end
end
return false
function table_ext.one_of_values(value, expected)
local res = vim.tbl_map(function(k)
return k == value or nil
end, vim.tbl_values(expected))
return res and next(res) ~= nil or false
end
---@TODO: give a look to vim.tbl_map
---Apply a function to each keys of a table, optionaly below a given path.
---@alias tables_rmap_cb fun(t1: table, path: path, parent: table, value: any, ...: any)
---@param t1 table
---@param callback tables_rmap_cb
---@param path path?
---@param ...? any extra parameters passed to callback
function M.rmap(t1, callback, path, ...)
local asserts = require("hsv2.utils.asserts")
asserts.type(t1, "table", "t1")
asserts.type(callback, "function", "callback")
asserts.type(path, "table", "path", true)
path = path or {}
local parent = L.get(t1, { unpack(path, 1, #path - 1) })
local value, status = L.get(t1, path)
if type(parent) ~= "table" or not status then
return nil, false, "invalid path"
end
if type(value) == "table" then
local child_key_idx = #path + 1
for k in pairs(value) do
local subpath = { unpack(path) }
subpath[child_key_idx] = k
M.rmap(t1, callback, subpath, ...)
end
else
callback(t1, path, parent, value, ...)
end
return t1, true
end
---Set value in a table at a given path.
---@param t1 table Table to write to.
---@param path path Path.
---@param value any? Value to set.
---@return table t1
function M.set(t1, path, value, return_value_parent)
local asserts = require("hsv2.utils.asserts")
asserts.type(t1, "table", "t1")
asserts.type(path, { "table", "number", "string" }, "path")
path = require("hsv2.utils.paths").parse(path)
assert(next(path), "path cannot be empty")
local current, status, msg = L.get(t1, path)
if not status and current ~= nil then
return nil, false, msg
end
L.set(t1, path, value)
return not return_value_parent and t1 or L.get(t1, { unpack(path, 1, #path - 1) })
end
---TODO
---@param t1 table
---@param schema table
---@return boolean
function M.validate(t1, schema)
return true
end
---Access a value in a table with a list of successive keys to use.
---@param t1 table
---@param path path
---@return any value?
---@nodiscard
function L.get(t1, path)
require("hsv2.utils.asserts").type(t1, "table", "t1")
if not path then
return t1
end
local value = t1
for i, key in ipairs(path) do
if type(value) ~= "table" then
return nil, false, "path component '" .. tostring(path[i - 1])
.. "' is not a table.", i - 1
end
value = value[key]
end
return value, true
end
---Set a value in a table.
---@param t1 table
---@param path path
---@param value any
---@return table t1
function L.set(t1, path, value)
local asserts = require("hsv2.utils.asserts")
asserts.type(t1, "table", "t1")
asserts.type(path, "table", "path")
assert(next(path))
local node = t1
for i, key in ipairs(path) do
if i == #path then
node[key] = value
elseif type(node[key]) ~= "table" then
node[key] = {}
end
node = node[key]
end
return t1
end
return M, L
return table_ext

View File

@ -68,18 +68,21 @@ function uevent:get_callback(uev, cb, group)
end
---@generic uev_t: hsv2.uevent_t
---@param uevent uev_t|uev_t[]
---@param uev uev_t|uev_t[]
---@param buffer? integer buffer ID
---@param group? string|integer
---|> "hsv2"
---@param modeline? boolean default: `true`
function uevent:trigger(uevent, buffer, group, modeline)
function uevent:trigger(uev, buffer, group, modeline)
group = group and ("hsv2-" .. group) or "hsv2"
local gid = vim.api.nvim_create_augroup(group, {
clear = false,
})
vim.api.nvim_exec_autocmds("User", {
buffer = buffer,
group = group,
group = gid,
modeline = modeline,
pattern = L.valid_uev(self, uevent),
pattern = L.valid_uev(self, uev),
})
end
@ -88,9 +91,13 @@ end
---@param uevents uev_t|uev_t[]
---@return boolean|uev_t|uev_t[]
function L.valid_uev(self, uevents)
---@type string[]
local valid_uevents = vim.tbl_keys(self:store("enums", "uevents"))
local function valid(uev)
return vim.tbl_contains(vim.tbl_keys(self:store_get()),
"enums", "uevents", uev)
for _, valid_uev in ipairs(valid_uevents) do
if valid_uev:match(uev) then return true end
end
return false
end
for _, uev in ipairs(vim.tbl_islist(uevents) and uevents or { uevents }) do
@ -102,7 +109,7 @@ function L.valid_uev(self, uevents)
return uevents
end
require("hsv2.utils.multi_inherit")(uevent,
uevent = require("hsv2.utils.multi_inherit")(uevent,
require("hsv2.prototypes.with_store"))
return uevent

1
meta/nvim Submodule

@ -0,0 +1 @@
Subproject commit b4c2ed7d1588b9ea2536058ddab2f8c29178b718

View File

@ -9,9 +9,5 @@ function _G.test(test, reload, ...)
end
end
end
local tests = require("tests")
local status, results = pcall(tests[test], ...)
if not status then
vim.api.nvim_echo({{results, "Error"}}, true, {})
end
require("tests")[test](...)
end