dotfiles from arch
This commit is contained in:
@@ -0,0 +1,276 @@
|
||||
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, key)
|
||||
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
|
||||
Reference in New Issue
Block a user