dotfiles/symlinks/config/nvim/lua/init/globals/opt.lua

264 lines
5.4 KiB
Lua

--[[ To use a more declarative syntax, you could do something like this:
local function set_opts(opts_table)
for k, v in pairs(opts_table) do
vim.opt[k] = v
end
end
set_opts {
mouse = 'n',
fillchars = { eob = "~" },
}
--]]
--[[ Global option names
For those wondering how to get the values at the top level,
you could use Lua's `setfenv` function to set the environment
equal to the vim.opt dict
cc @mccanch
setfenv(function()
mouse = 'n'
end, vim.opt)()
--]]
local if_nil = function(a, b)
if a == nil then
return b
end
return a
end
local singular_values = {
['boolean'] = true,
['number'] = true,
['nil'] = true,
}
local set_key_value = function(t, key_value_str)
assert(string.find(key_value_str, ":"), "Must have a :" .. tostring(key_value_str))
local key, value = unpack(vim.split(key_value_str, ":"))
key = vim.trim(key)
value = vim.trim(value)
t[key] = value
end
local convert_vimoption_to_lua = function(option, val)
-- Short circuit if we've already converted!
if type(val) == 'table' then
return val
end
if singular_values[type(val)] then
return val
end
if type(val) == "string" then
-- TODO: Bad hax I think
if string.find(val, ":") then
local result = {}
local items = vim.split(val, ",")
for _, item in ipairs(items) do
set_key_value(result, item)
end
return result
else
return vim.split(val, ",")
end
end
end
-- local concat_keys = function(t, sep)
-- return table.concat(vim.tbl_keys(t), sep)
-- end
local concat_key_values = function(t, sep, divider)
local final = {}
for k, v in pairs(t) do
table.insert(final, string.format('%s%s%s', k, divider, v))
end
table.sort(final)
return table.concat(final, sep)
end
local remove_duplicate_values = function(t)
local result = {}
for _, v in ipairs(t) do
result[v] = true
end
return vim.tbl_keys(result)
end
local remove_value = function(t, val)
if vim.tbl_islist(t) then
local remove_index = nil
for i, v in ipairs(t) do
if v == val then
remove_index = i
end
end
if remove_index then
table.remove(t, remove_index)
end
else
t[val] = nil
end
return t
end
local add_value = function(current, new)
if singular_values[type(current)] then
error(
"This is not possible to do. Please do something different: "
.. tostring(current)
.. " // "
.. tostring(new)
)
end
if type(new) == 'string' then
if vim.tbl_islist(current) then
table.insert(current, new)
else
set_key_value(current, new)
end
return current
elseif type(new) == 'table' then
if vim.tbl_islist(current) then
assert(vim.tbl_islist(new))
vim.list_extend(current, new)
else
assert(not vim.tbl_islist(new), vim.inspect(new) .. vim.inspect(current))
current = vim.tbl_extend("force", current, new)
end
return current
else
error("Unknown type")
end
end
local convert_lua_to_vimoption = function(t)
if vim.tbl_islist(t) then
t = remove_duplicate_values(t)
table.sort(t)
return table.concat(t, ',')
else
return concat_key_values(t, ',', ':')
end
end
local clean_value = function(v)
if singular_values[type(v)] then
return v
end
local result = v:gsub('^,', '')
return result
end
local opt_mt
opt_mt = {
__index = function(t, k)
if k == '_value' then
return rawget(t, k)
end
return setmetatable({ _option = k, }, opt_mt)
end,
__newindex = function(t, k, v)
if k == '_value' then
return rawset(t, k, v)
end
if type(v) == 'table' then
local new_value
if getmetatable(v) ~= opt_mt then
new_value = v
else
assert(v._value, "Must have a value to set this")
new_value = v._value
end
vim.o[k] = convert_lua_to_vimoption(new_value)
return
end
if v == nil then
v = ''
end
-- TODO: Figure out why nvim_set_option doesn't override values the same way.
-- @bfredl said he will fix this for me, so I can just use nvim_set_option
if type(v) == 'boolean' then
vim.o[k] = clean_value(v)
if v then
vim.cmd(string.format("set %s", k))
else
vim.cmd(string.format("set no%s", k))
end
else
vim.cmd(string.format("set %s=%s", k, clean_value(v)))
end
end,
__add = function(left, right)
--[[
set.wildignore = set.wildignore + 'hello'
set.wildignore = set.wildignore + { '*.o', '*~', }
--]]
assert(left._option, "must have an option key")
if left._option == 'foldcolumn' then
error("not implemented for foldcolumn.. use a string")
end
local existing = if_nil(left._value, vim.o[left._option])
local current = convert_vimoption_to_lua(left._option, existing)
if not current then
left._value = convert_vimoption_to_lua(right)
end
left._value = add_value(current, right)
return left
end,
__sub = function(left, right)
assert(left._option, "must have an option key")
local existing = if_nil(left._value, vim.o[left._option])
local current = convert_vimoption_to_lua(left._option, existing)
if not current then
return left
end
left._value = remove_value(current, right)
return left
end
}
vim.opt = setmetatable({}, opt_mt)
return {
convert_vimoption_to_lua = convert_vimoption_to_lua,
opt = vim.opt,
opt_mt = opt_mt
}