Skip to content

Commit

Permalink
feat: experiment
Browse files Browse the repository at this point in the history
  • Loading branch information
TwIStOy committed Mar 9, 2024
1 parent a112700 commit 4332aa4
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 0 deletions.
10 changes: 10 additions & 0 deletions lua/dotvim/experiments/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---@class dotvim.experiments
local M = {}

---@type dotvim.experiments.types
M.types = require("dotvim.experiments.types")

---@type dotvim.experiments.option
M.option = require("dotvim.experiments.option")

return M
45 changes: 45 additions & 0 deletions lua/dotvim/experiments/option.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---@class dotvim.experiments.option
local M = {}

---@class dotvim.experiments.option.MakeOptionArgs
---@field name string
---@field val_type dotvim.experiments.types.Type
---@field default any
---@field description? string
---@field example? string
---@field merge? fun(prev: any, incoming: any): any
---@field apply? fun(value: any): any

---@class dotvim.experiments.option.Option: dotvim.experiments.option.MakeOptionArgs
local Option = {}

---@param prev any
---@param incoming any
---@return any
function Option:update(prev, incoming)
M.check_option(self, incoming)
local new_val
if self.merge == nil then
new_val = self.val_type.merge(prev, incoming)
else
new_val = self.merge(prev, incoming)
end
if self.apply ~= nil then
return self.apply(new_val)
else
return new_val
end
end

---@param opts dotvim.experiments.option.MakeOptionArgs
function M.make_option(opts)
return setmetatable(opts, { __index = Option })
end

function M.check_option(option, value)
if not option.val_type.checker(value) then
error(string.format("Invalid value for option %s: %s", option.name, value))
end
end

return M
106 changes: 106 additions & 0 deletions lua/dotvim/experiments/types.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
---@class dotvim.experiments.types
local M = {}

---@class dotvim.experiments.types.Type
---@field name string
---@field checker fun(value: any): boolean Check if the value is of this type
---@field merge fun(prev: any, incoming: any): any Merge the value with the default value
local Type = {}

---@param opts dotvim.experiments.types.Type
function Type.new(opts)
return setmetatable(opts, { __index = Type })
end

-------------------------------------
-- Simple types
-------------------------------------
M.str = Type.new {
name = "string",
checker = function(value)
return type(value) == "string"
end,
merge = function(prev, incoming)
return vim.F.if_nil(incoming, prev)
end,
}

M.num = Type.new {
name = "number",
checker = function(value)
return type(value) == "number"
end,
merge = function(prev, incoming)
return vim.F.if_nil(incoming, prev)
end,
}

M.bool = Type.new {
name = "boolean",
checker = function(value)
return type(value) == "boolean"
end,
merge = function(prev, incoming)
return vim.F.if_nil(incoming, prev)
end,
}

M.anything = Type.new {
name = "anything",
checker = function()
return true
end,
merge = function(prev, incoming)
return vim.F.if_nil(incoming, prev)
end,
}

-------------------------------------
-- Complex types
-------------------------------------
---@param type dotvim.experiments.types.Type
function M.list_of(type)
return Type.new {
name = "list_of_" .. type.name,
checker = function(value)
if type(value) ~= "table" or not vim.tbl_islist(value) then
return false
end
for _, v in ipairs(value) do
if not type.checker(v) then
return false
end
end
return true
end,
merge = function(prev, incoming)
local ret = {}
vim.list_extend(ret, prev)
vim.list_extend(ret, incoming)
return ret
end,
}
end

---@param type dotvim.experiments.types.Type
function M.dict_of(type)
return Type.new {
name = "dict_of_" .. type.name,
checker = function(value)
if type(value) ~= "table" then
return false
end
for _, v in pairs(value) do
if not type.checker(v) then
return false
end
end
return true
end,
merge = function(prev, incoming)
return vim.tbl_deep_extend("force", prev, incoming)
end,
}
end

return M
3 changes: 3 additions & 0 deletions lua/dotvim/utils/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ M.ansi = require("dotvim.utils.ansi")
---@type dotvim.utils.tbl
M.tbl = require("dotvim.utils.tbl")

---@type dotvim.utils.value
M.value = require("dotvim.utils.value")

return M
15 changes: 15 additions & 0 deletions lua/dotvim/utils/value.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---@class dotvim.utils.value
local M = {}

---@generic T
---@param value T|fun(...): T
---@param ... any
---@return T
function M.normalize_value(value, ...)
if type(value) == "function" then
return value(...)
end
return value
end

return M

0 comments on commit 4332aa4

Please sign in to comment.