local util = require 'utility' local define = require 'proto.define' local diag = require 'proto.diagnostic' ---@class config.unit ---@field caller function ---@field _checker fun(self: config.unit, value: any): boolean ---@field name string ---@field [string] config.unit ---@operator shl: config.unit ---@operator shr: config.unit ---@operator call: config.unit local mt = {} mt.__index = mt function mt:__call(...) self:caller(...) return self end function mt:__shr(default) self.default = default self.hasDefault = true return self end function mt:__shl(enums) self.enums = enums return self end function mt:checker(v) if self.enums then local ok for _, enum in ipairs(self.enums) do if util.equal(enum, v) then ok = true break end end if not ok then return false end end return self:_checker(v) end local units = {} local function register(name, default, checker, loader, caller) units[name] = { name = name, default = default, _checker = checker, loader = loader, caller = caller, } end ---@type config.unit local Type = setmetatable({}, { __index = function (_, name) local unit = {} for k, v in pairs(units[name]) do unit[k] = v end return setmetatable(unit, mt) end }) register('Boolean', false, function (self, v) return type(v) == 'boolean' end, function (self, v) return v end) register('Integer', 0, function (self, v) return type(v) == 'number' end, function (self, v) return math.floor(v) end) register('String', '', function (self, v) return type(v) == 'string' end, function (self, v) return tostring(v) end) register('Nil', nil, function (self, v) return type(v) == 'nil' end, function (self, v) return nil end) register('Array', {}, function (self, value) return type(value) == 'table' end, function (self, value) local t = {} if #value == 0 then for k in pairs(value) do if self.sub:checker(k) then t[#t+1] = self.sub:loader(k) end end else for _, v in ipairs(value) do if self.sub:checker(v) then t[#t+1] = self.sub:loader(v) end end end return t end, function (self, sub) self.sub = sub end) register('Hash', {}, function (self, value) if type(value) == 'table' then if #value == 0 then for k, v in pairs(value) do if not self.subkey:checker(k) or not self.subvalue:checker(v) then return false end end else if not self.subvalue:checker(true) then return false end for _, v in ipairs(value) do if not self.subkey:checker(v) then return false end end end return true end if type(value) == 'string' then return self.subkey:checker('') and self.subvalue:checker(true) end end, function (self, value) if type(value) == 'table' then local t = {} if #value == 0 then for k, v in pairs(value) do t[k] = v end else for _, k in pairs(value) do t[k] = true end end return t end if type(value) == 'string' then local t = {} for s in value:gmatch('[^' .. self.sep .. ']+') do t[s] = true end return t end end, function (self, subkey, subvalue, sep) self.subkey = subkey self.subvalue = subvalue self.sep = sep end) register('Or', nil, function (self, value) for _, sub in ipairs(self.subs) do if sub:checker(value) then return true end end return false end, function (self, value) for _, sub in ipairs(self.subs) do if sub:checker(value) then return sub:loader(value) end end end, function (self, ...) self.subs = { ... } end) local template = { ['Lua.runtime.version'] = Type.String >> 'Lua 5.4' << { 'Lua 5.1', 'Lua 5.2', 'Lua 5.3', 'Lua 5.4', 'LuaJIT', }, ['Lua.runtime.path'] = Type.Array(Type.String) >> { "?.lua", "?/init.lua", }, ['Lua.runtime.pathStrict'] = Type.Boolean >> false, ['Lua.runtime.special'] = Type.Hash( Type.String, Type.String >> 'require' << { '_G', 'rawset', 'rawget', 'setmetatable', 'require', 'dofile', 'loadfile', 'pcall', 'xpcall', 'assert', 'error', 'type', } ), ['Lua.runtime.meta'] = Type.String >> '${version} ${language} ${encoding}', ['Lua.runtime.unicodeName'] = Type.Boolean, ['Lua.runtime.nonstandardSymbol'] = Type.Array(Type.String << { '//', '/**/', '`', '+=', '-=', '*=', '/=', '%=', '^=', '//=', '|=', '&=', '<<=', '>>=', '||', '&&', '!', '!=', 'continue', }), ['Lua.runtime.plugin'] = Type.String, ['Lua.runtime.pluginArgs'] = Type.Array(Type.String), ['Lua.runtime.fileEncoding'] = Type.String >> 'utf8' << { 'utf8', 'ansi', 'utf16le', 'utf16be', }, ['Lua.runtime.builtin'] = Type.Hash( Type.String << util.getTableKeys(define.BuiltIn, true), Type.String >> 'default' << { 'default', 'enable', 'disable', } ) >> util.deepCopy(define.BuiltIn), ['Lua.diagnostics.enable'] = Type.Boolean >> true, ['Lua.diagnostics.globals'] = Type.Array(Type.String), ['Lua.diagnostics.disable'] = Type.Array(Type.String << util.getTableKeys(diag.getDiagAndErrNameMap(), true)), ['Lua.diagnostics.severity'] = Type.Hash( Type.String << util.getTableKeys(define.DiagnosticDefaultNeededFileStatus, true), Type.String << { 'Error', 'Warning', 'Information', 'Hint', 'Error!', 'Warning!', 'Information!', 'Hint!', } ) >> util.deepCopy(define.DiagnosticDefaultSeverity), ['Lua.diagnostics.neededFileStatus'] = Type.Hash( Type.String << util.getTableKeys(define.DiagnosticDefaultNeededFileStatus, true), Type.String << { 'Any', 'Opened', 'None', 'Any!', 'Opened!', 'None!', } ) >> util.deepCopy(define.DiagnosticDefaultNeededFileStatus), ['Lua.diagnostics.groupSeverity'] = Type.Hash( Type.String << util.getTableKeys(define.DiagnosticDefaultGroupSeverity, true), Type.String << { 'Error', 'Warning', 'Information', 'Hint', 'Fallback', } ) >> util.deepCopy(define.DiagnosticDefaultGroupSeverity), ['Lua.diagnostics.groupFileStatus'] = Type.Hash( Type.String << util.getTableKeys(define.DiagnosticDefaultGroupFileStatus, true), Type.String << { 'Any', 'Opened', 'None', 'Fallback', } ) >> util.deepCopy(define.DiagnosticDefaultGroupFileStatus), ['Lua.diagnostics.disableScheme'] = Type.Array(Type.String) >> { 'git' }, ['Lua.diagnostics.workspaceDelay'] = Type.Integer >> 3000, ['Lua.diagnostics.workspaceRate'] = Type.Integer >> 100, ['Lua.diagnostics.libraryFiles'] = Type.String >> 'Opened' << { 'Enable', 'Opened', 'Disable', }, ['Lua.diagnostics.ignoredFiles'] = Type.String >> 'Opened' << { 'Enable', 'Opened', 'Disable', }, ['Lua.diagnostics.unusedLocalExclude'] = Type.Array(Type.String), ['Lua.workspace.ignoreDir'] = Type.Array(Type.String) >> { '.vscode', }, ['Lua.workspace.ignoreSubmodules'] = Type.Boolean >> true, ['Lua.workspace.useGitIgnore'] = Type.Boolean >> true, ['Lua.workspace.maxPreload'] = Type.Integer >> 5000, ['Lua.workspace.preloadFileSize'] = Type.Integer >> 500, ['Lua.workspace.library'] = Type.Array(Type.String), ['Lua.workspace.checkThirdParty'] = Type.Boolean >> true, ['Lua.workspace.userThirdParty'] = Type.Array(Type.String), ['Lua.workspace.supportScheme'] = Type.Array(Type.String) >> { 'file', 'untitled', 'git' }, ['Lua.completion.enable'] = Type.Boolean >> true, ['Lua.completion.callSnippet'] = Type.String >> 'Disable' << { 'Disable', 'Both', 'Replace', }, ['Lua.completion.keywordSnippet'] = Type.String >> 'Replace' << { 'Disable', 'Both', 'Replace', }, ['Lua.completion.displayContext'] = Type.Integer >> 0, ['Lua.completion.workspaceWord'] = Type.Boolean >> true, ['Lua.completion.showWord'] = Type.String >> 'Fallback' << { 'Enable', 'Fallback', 'Disable', }, ['Lua.completion.autoRequire'] = Type.Boolean >> true, ['Lua.completion.showParams'] = Type.Boolean >> true, ['Lua.completion.requireSeparator'] = Type.String >> '.', ['Lua.completion.postfix'] = Type.String >> '@', ['Lua.signatureHelp.enable'] = Type.Boolean >> true, ['Lua.hover.enable'] = Type.Boolean >> true, ['Lua.hover.viewString'] = Type.Boolean >> true, ['Lua.hover.viewStringMax'] = Type.Integer >> 1000, ['Lua.hover.viewNumber'] = Type.Boolean >> true, ['Lua.hover.previewFields'] = Type.Integer >> 50, ['Lua.hover.enumsLimit'] = Type.Integer >> 5, ['Lua.hover.expandAlias'] = Type.Boolean >> true, ['Lua.semantic.enable'] = Type.Boolean >> true, ['Lua.semantic.variable'] = Type.Boolean >> true, ['Lua.semantic.annotation'] = Type.Boolean >> true, ['Lua.semantic.keyword'] = Type.Boolean >> false, ['Lua.hint.enable'] = Type.Boolean >> false, ['Lua.hint.paramType'] = Type.Boolean >> true, ['Lua.hint.setType'] = Type.Boolean >> false, ['Lua.hint.paramName'] = Type.String >> 'All' << { 'All', 'Literal', 'Disable', }, ['Lua.hint.await'] = Type.Boolean >> true, ['Lua.hint.arrayIndex'] = Type.String >> 'Auto' << { 'Enable', 'Auto', 'Disable', }, ['Lua.hint.semicolon'] = Type.String >> 'SameLine' << { 'All', 'SameLine', 'Disable', }, ['Lua.window.statusBar'] = Type.Boolean >> true, ['Lua.window.progressBar'] = Type.Boolean >> true, ['Lua.format.enable'] = Type.Boolean >> true, ['Lua.format.defaultConfig'] = Type.Hash(Type.String, Type.String) >> {}, ['Lua.spell.dict'] = Type.Array(Type.String), ['Lua.telemetry.enable'] = Type.Or(Type.Boolean >> false, Type.Nil) >> nil, ['Lua.misc.parameters'] = Type.Array(Type.String), ['Lua.type.castNumberToInteger'] = Type.Boolean >> true, ['Lua.type.weakUnionCheck'] = Type.Boolean >> false, ['Lua.type.weakNilCheck'] = Type.Boolean >> false, -- VSCode ['files.associations'] = Type.Hash(Type.String, Type.String), ['files.exclude'] = Type.Hash(Type.String, Type.Boolean), ['editor.semanticHighlighting.enabled'] = Type.Or(Type.Boolean, Type.String), ['editor.acceptSuggestionOnEnter'] = Type.String >> 'on', } return template