local config = require('pending.config') ---@class pending.complete local M = {} ---@return string local function date_key() return config.get().date_syntax or 'due' end ---@return string local function recur_key() return config.get().recur_syntax or 'rec' end ---@return string[] local function get_categories() local s = require('pending.buffer').store() if not s then return {} end local seen = {} local result = {} for _, task in ipairs(s:active_tasks()) do local cat = task.category if cat and not seen[cat] then seen[cat] = true table.insert(result, cat) end end table.sort(result) return result end ---@return { word: string, info: string }[] local function date_completions() return { { word = 'today', info = "Today's date" }, { word = 'tomorrow', info = "Tomorrow's date" }, { word = 'yesterday', info = "Yesterday's date" }, { word = '+1d', info = '1 day from today' }, { word = '+2d', info = '2 days from today' }, { word = '+3d', info = '3 days from today' }, { word = '+1w', info = '1 week from today' }, { word = '+2w', info = '2 weeks from today' }, { word = '+1m', info = '1 month from today' }, { word = 'mon', info = 'Next Monday' }, { word = 'tue', info = 'Next Tuesday' }, { word = 'wed', info = 'Next Wednesday' }, { word = 'thu', info = 'Next Thursday' }, { word = 'fri', info = 'Next Friday' }, { word = 'sat', info = 'Next Saturday' }, { word = 'sun', info = 'Next Sunday' }, { word = 'eod', info = 'End of day (today)' }, { word = 'eow', info = 'End of week (Sunday)' }, { word = 'eom', info = 'End of month' }, { word = 'eoq', info = 'End of quarter' }, { word = 'eoy', info = 'End of year (Dec 31)' }, { word = 'sow', info = 'Start of week (Monday)' }, { word = 'som', info = 'Start of month' }, { word = 'soq', info = 'Start of quarter' }, { word = 'soy', info = 'Start of year (Jan 1)' }, { word = 'later', info = 'Someday (sentinel date)' }, { word = 'today@08:00', info = 'Today at 08:00' }, { word = 'today@09:00', info = 'Today at 09:00' }, { word = 'today@10:00', info = 'Today at 10:00' }, { word = 'today@12:00', info = 'Today at 12:00' }, { word = 'today@14:00', info = 'Today at 14:00' }, { word = 'today@17:00', info = 'Today at 17:00' }, } end ---@type table local recur_descriptions = { daily = 'Every day', weekdays = 'Monday through Friday', weekly = 'Every week', biweekly = 'Every 2 weeks', monthly = 'Every month', quarterly = 'Every 3 months', yearly = 'Every year', ['2d'] = 'Every 2 days', ['3d'] = 'Every 3 days', ['2w'] = 'Every 2 weeks', ['3w'] = 'Every 3 weeks', ['2m'] = 'Every 2 months', ['3m'] = 'Every 3 months', ['6m'] = 'Every 6 months', ['2y'] = 'Every 2 years', } ---@return { word: string, info: string }[] local function recur_completions() local recur = require('pending.recur') local list = recur.shorthand_list() local result = {} for _, s in ipairs(list) do local desc = recur_descriptions[s] or s table.insert(result, { word = s, info = desc }) end for _, s in ipairs(list) do local desc = recur_descriptions[s] or s table.insert(result, { word = '!' .. s, info = desc .. ' (from completion date)' }) end return result end ---@type string? local _complete_source = nil ---@param findstart integer ---@param base string ---@return integer|table[] function M.omnifunc(findstart, base) if findstart == 1 then local line = vim.api.nvim_get_current_line() local col = vim.api.nvim_win_get_cursor(0)[2] local before = line:sub(1, col) local dk = date_key() local rk = recur_key() local checks = { { vim.pesc(dk) .. ':([%S]*)$', dk }, { 'cat:([%S]*)$', 'cat' }, { vim.pesc(rk) .. ':([%S]*)$', rk }, { 'file:([%S]*)$', 'file' }, } for _, check in ipairs(checks) do local start = before:find(check[1]) if start then local colon_pos = before:find(':', start, true) if colon_pos then _complete_source = check[2] return colon_pos end end end _complete_source = nil return -1 end local matches = {} local source = _complete_source or '' local dk = date_key() local rk = recur_key() if source == dk then for _, c in ipairs(date_completions()) do if base == '' or c.word:sub(1, #base) == base then table.insert(matches, { word = c.word, menu = '[' .. source .. ']', info = c.info }) end end elseif source == 'cat' then for _, c in ipairs(get_categories()) do if base == '' or c:sub(1, #base) == base then table.insert(matches, { word = c, menu = '[cat]' }) end end elseif source == rk then for _, c in ipairs(recur_completions()) do if base == '' or c.word:sub(1, #base) == base then table.insert(matches, { word = c.word, menu = '[' .. source .. ']', info = c.info }) end end end return matches end return M