local has_cmp, cmp = pcall(require, "cmp") if not has_cmp then return end local has_job, Job = pcall(require, "plenary.job") if not has_job then return end local source = {} local defaults = { space_filter = "-", address_book = nil, } source.new = function() return setmetatable({}, { __index = source }) end function source:is_available() return vim.bo.filetype == "mail" end function source:get_debug_name() return "abook" end function source:complete(params, callback) params.option = vim.tbl_deep_extend("keep", params.option, defaults) vim.validate( "params.option.space_filter", params.option.space_filter, { "string" } ) local ctx = params.context if not ( ctx.cursor_line:match("^To: ") or ctx.cursor_line:match("^Cc: ") or ctx.cursor_line:match("^Bcc: ") ) then callback({}) return end local query = "" local line = ctx.cursor_line local cursor = ctx.cursor.character for i = cursor, 1, -1 do local char = line:sub(i, i) if char == ":" or char == "," then query = line:sub(i + 2, cursor) break end end local abook_addressbook = os.getenv("ABOOK_ADDRESSBOOK") local abook_args = { "--mutt-query", query } if abook_addressbook then table.insert(abook_args, "-f") table.insert(abook_args, abook_addressbook) end Job :new({ command = "abook", args = abook_args, on_exit = function(job, code) if code ~= 0 then return end local result = job:result() local items = {} for _, item in ipairs(result) do local item_parts = vim.split(item, "\t", { trimempty = true }) local label = string.format( "%s <%s>", item_parts[2], item_parts[1] ) or item_parts[1] table.insert(items, { label = label, filterText = label:gsub(" ", params.option.space_filter), kind = cmp.lsp.CompletionItemKind.Text, }) end callback({ items = items, isIncomplete = false }) end, }) :start() end return source