minetest_x_bows/bin/lua-language-server-3.5.6-l.../script/config/config.lua
2022-11-03 11:37:33 -04:00

277 lines
6.7 KiB
Lua

local util = require 'utility'
local timer = require 'timer'
local scope = require 'workspace.scope'
local template = require 'config.template'
---@alias config.source '"client"'|'"path"'|'"local"'
---@class config.api
local m = {}
m.watchList = {}
m.NULL = {}
m.nullSymbols = {
[m.NULL] = true,
}
---@param scp scope
---@param key string
---@param nowValue any
---@param rawValue any
local function update(scp, key, nowValue, rawValue)
local now = m.getNowTable(scp)
local raw = m.getRawTable(scp)
now[key] = nowValue
raw[key] = rawValue
end
---@param uri? uri
---@param key? string
---@return scope
local function getScope(uri, key)
local raw = m.getRawTable(scope.override)
if raw then
if not key or raw[key] ~= nil then
return scope.override
end
end
if uri then
---@type scope?
local scp = scope.getFolder(uri) or scope.getLinkedScope(uri)
if scp then
if not key
or m.getRawTable(scp)[key] ~= nil then
return scp
end
end
end
return scope.fallback
end
---@param scp scope
---@param key string
---@param value any
function m.setByScope(scp, key, value)
local unit = template[key]
if not unit then
return false
end
local raw = m.getRawTable(scp)
if util.equal(raw[key], value) then
return false
end
if unit:checker(value) then
update(scp, key, unit:loader(value), value)
else
update(scp, key, unit.default, unit.default)
end
return true
end
---@param uri? uri
---@param key string
---@param value any
function m.set(uri, key, value)
local unit = template[key]
assert(unit, 'unknown key: ' .. key)
local scp = getScope(uri)
local oldValue = m.get(uri, key)
m.setByScope(scp, key, value)
local newValue = m.get(uri, key)
if not util.equal(oldValue, newValue) then
m.event(uri, key, newValue, oldValue)
return true
end
return false
end
function m.add(uri, key, value)
local unit = template[key]
assert(unit, 'unknown key: ' .. key)
local list = m.getRaw(uri, key)
assert(type(list) == 'table', 'not a list: ' .. key)
local copyed = {}
for i, v in ipairs(list) do
if util.equal(v, value) then
return false
end
copyed[i] = v
end
copyed[#copyed+1] = value
local oldValue = m.get(uri, key)
m.set(uri, key, copyed)
local newValue = m.get(uri, key)
if not util.equal(oldValue, newValue) then
m.event(uri, key, newValue, oldValue)
return true
end
return false
end
function m.remove(uri, key, value)
local unit = template[key]
assert(unit, 'unknown key: ' .. key)
local list = m.getRaw(uri, key)
assert(type(list) == 'table', 'not a list: ' .. key)
local copyed = {}
for i, v in ipairs(list) do
if not util.equal(v, value) then
copyed[i] = v
end
end
local oldValue = m.get(uri, key)
m.set(uri, key, copyed)
local newValue = m.get(uri, key)
if not util.equal(oldValue, newValue) then
m.event(uri, key, newValue, oldValue)
return true
end
return false
end
function m.prop(uri, key, prop, value)
local unit = template[key]
assert(unit, 'unknown key: ' .. key)
local map = m.getRaw(uri, key)
assert(type(map) == 'table', 'not a map: ' .. key)
if util.equal(map[prop], value) then
return false
end
local copyed = {}
for k, v in pairs(map) do
copyed[k] = v
end
copyed[prop] = value
local oldValue = m.get(uri, key)
m.set(uri, key, copyed)
local newValue = m.get(uri, key)
if not util.equal(oldValue, newValue) then
m.event(uri, key, newValue, oldValue)
return true
end
return false
end
---@param uri? uri
---@param key string
---@return any
function m.get(uri, key)
local scp = getScope(uri, key)
local value = m.getNowTable(scp)[key]
if value == nil then
value = template[key].default
end
if value == m.NULL then
value = nil
end
return value
end
---@param uri uri
---@param key string
---@return any
function m.getRaw(uri, key)
local scp = getScope(uri, key)
local value = m.getRawTable(scp)[key]
if value == nil then
value = template[key].default
end
if value == m.NULL then
value = nil
end
return value
end
---@param scp scope
function m.getNowTable(scp)
return scp:get 'config.now'
or scp:set('config.now', {})
end
---@param scp scope
function m.getRawTable(scp)
return scp:get 'config.raw'
or scp:set('config.raw', {})
end
---@param scp scope
---@param ... table
function m.update(scp, ...)
local oldConfig = m.getNowTable(scp)
local newConfig = {}
scp:set('config.now', newConfig)
scp:set('config.raw', {})
local function expand(t, left)
for key, value in pairs(t) do
local fullKey = key
if left then
fullKey = left .. '.' .. key
end
if m.nullSymbols[value] then
value = m.NULL
end
if template[fullKey] then
m.setByScope(scp, fullKey, value)
elseif template['Lua.' .. fullKey] then
m.setByScope(scp, 'Lua.' .. fullKey, value)
elseif type(value) == 'table' then
expand(value, fullKey)
end
end
end
local news = table.pack(...)
for i = 1, news.n do
if type(news[i]) == 'table' then
expand(news[i])
end
end
-- compare then fire event
if oldConfig then
for key, oldValue in pairs(oldConfig) do
local newValue = newConfig[key]
if not util.equal(oldValue, newValue) then
m.event(scp.uri, key, newValue, oldValue)
end
end
end
m.event(scp.uri, '')
end
---@param callback fun(uri: uri, key: string, value: any, oldValue: any)
function m.watch(callback)
m.watchList[#m.watchList+1] = callback
end
function m.event(uri, key, value, oldValue)
if not m.changes then
m.changes = {}
timer.wait(0, function ()
local delay = m.changes
m.changes = nil
for _, info in ipairs(delay) do
for _, callback in ipairs(m.watchList) do
callback(info.uri, info.key, info.value, info.oldValue)
end
end
end)
end
m.changes[#m.changes+1] = {
uri = uri,
key = key,
value = value,
oldValue = oldValue,
}
end
function m.addNullSymbol(null)
m.nullSymbols[null] = true
end
return m