local policy = require("clever_f.policy") local M = {} local FeedbackService = {} FeedbackService.__index = FeedbackService M.FeedbackService = FeedbackService M.DEFAULT_LABEL_GROUP = "CleverFDefaultLabel" M.Priority = { HIGH = "high", ORDINARY = "ordinary", } local OVERLAY_PRIORITIES = { CleverFCursor = M.Priority.HIGH, CleverFChar = M.Priority.HIGH, CleverFDirect = M.Priority.ORDINARY, } local service_records = setmetatable({}, { __mode = "k" }) local FEATURE_GROUPS = { "CleverFCursor", "CleverFChar", "CleverFDirect", } 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 function M.overlay_priority(group) local priority = OVERLAY_PRIORITIES[group] if priority == nil then error("unknown feedback overlay group '" .. tostring(group) .. "'", 2) end return priority 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 local function require_policy(service, host) service = service or policy.new(host) if type(service) ~= "table" or type(service.evaluate_highlight_links) ~= "function" then fail("FeedbackService policy must evaluate highlight links", 3) end return service end function FeedbackService.new(options) if FeedbackService.is(options) then return options end options = normalize_options(options) local service = setmetatable({}, FeedbackService) local host = require_host(options.host) service_records[service] = { host = host, policy = require_policy(options.policy or options.policy_service, host), } return service end function FeedbackService.is(value) return type(value) == "table" and service_records[value] ~= nil end function FeedbackService:evaluate_feature_links() local record = service_records[self] local rules = record.policy:evaluate_highlight_links() local results = {} for _, group in ipairs(FEATURE_GROUPS) do local rule = rules[group] if rule.enabled then if rule.configured_target ~= nil then record.host:define_highlight_group( group, { link = rule.configured_target }, { force = true } ) results[group] = { group = group, target = rule.configured_target, source = "configured", applied = true, } else local existing = record.host:read_highlight_group(group) if existing ~= nil then results[group] = { group = group, definition = existing, source = "colorscheme", applied = false, } else record.host:define_highlight_group( group, { link = rule.target }, { default = true } ) results[group] = { group = group, target = rule.target, source = "fallback", applied = true, } end end end end return results 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