local M = {} local FeedbackService = {} FeedbackService.__index = FeedbackService M.FeedbackService = FeedbackService M.DEFAULT_LABEL_GROUP = "CleverFDefaultLabel" local service_records = setmetatable({}, { __mode = "k" }) local DEFAULT_LABEL_DEFINITION = { guifg = "red", guibg = "NONE", gui = { bold = true, underline = true, }, ctermfg = "red", ctermbg = "NONE", cterm = { bold = true, underline = true, }, } local function copy(value) if type(value) ~= "table" then return value end local result = {} for key, item in pairs(value) do result[key] = copy(item) end return result end function M.default_label_definition() return copy(DEFAULT_LABEL_DEFINITION) end local function fail(message, level) error(message, (level or 1) + 1) end local function normalize_options(options) if type(options) ~= "table" then fail("FeedbackService options must be a table", 3) end if options.host == nil then return { host = options } end return options end local function require_host(host) if type(host) ~= "table" or type(host.read_highlight_group) ~= "function" or type(host.define_highlight_group) ~= "function" then fail("FeedbackService host must provide highlight groups", 3) end return host end function FeedbackService.new(options) if FeedbackService.is(options) then return options end options = normalize_options(options) local service = setmetatable({}, FeedbackService) service_records[service] = { host = require_host(options.host), } return service end function FeedbackService.is(value) return type(value) == "table" and service_records[value] ~= nil end function FeedbackService:ensure_default_label() local existing = service_records[self].host:read_highlight_group( M.DEFAULT_LABEL_GROUP ) if existing ~= nil then return { group = M.DEFAULT_LABEL_GROUP, definition = existing, source = "colorscheme", applied = false, } end local definition = M.default_label_definition() service_records[self].host:define_highlight_group( M.DEFAULT_LABEL_GROUP, definition, { default = true } ) return { group = M.DEFAULT_LABEL_GROUP, definition = definition, source = "fallback", applied = true, } end function M.new(options) return FeedbackService.new(options) end setmetatable(M, { __call = function(_, options) return FeedbackService.new(options) end, }) return M