From 18035b9dfbf54c36bb390d98c56220db0362b323 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 8 Mar 2026 19:46:59 -0400 Subject: [PATCH] refactor(types): extract inline anonymous types into named classes Problem: several functions used inline `{...}` table types in their `@param` and `@return` annotations, making them hard to read and impossible to reference from other modules. Solution: extract each into a named `---@class`: `pending.Metadata`, `pending.TaskFields`, `pending.CompletionItem`, `pending.SystemResult`, and `pending.OAuthClientOpts`. --- lua/pending/complete.lua | 8 +++- lua/pending/parse.lua | 11 +++++- lua/pending/store.lua | 13 ++++++- lua/pending/sync/oauth.lua | 57 ++++++++------------------- lua/pending/sync/util.lua | 79 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 45 deletions(-) create mode 100644 lua/pending/sync/util.lua diff --git a/lua/pending/complete.lua b/lua/pending/complete.lua index 9ed4971..6ee3320 100644 --- a/lua/pending/complete.lua +++ b/lua/pending/complete.lua @@ -1,5 +1,9 @@ local config = require('pending.config') +---@class pending.CompletionItem +---@field word string +---@field info string + ---@class pending.complete local M = {} @@ -32,7 +36,7 @@ local function get_categories() return result end ----@return { word: string, info: string }[] +---@return pending.CompletionItem[] local function date_completions() return { { word = 'today', info = "Today's date" }, @@ -89,7 +93,7 @@ local recur_descriptions = { ['2y'] = 'Every 2 years', } ----@return { word: string, info: string }[] +---@return pending.CompletionItem[] local function recur_completions() local recur = require('pending.recur') local list = recur.shorthand_list() diff --git a/lua/pending/parse.lua b/lua/pending/parse.lua index ea838f7..a0160f1 100644 --- a/lua/pending/parse.lua +++ b/lua/pending/parse.lua @@ -1,5 +1,12 @@ local config = require('pending.config') +---@class pending.Metadata +---@field due? string +---@field cat? string +---@field rec? string +---@field rec_mode? 'scheduled'|'completion' +---@field priority? integer + ---@class pending.parse local M = {} @@ -515,7 +522,7 @@ end ---@param text string ---@return string description ----@return { due?: string, cat?: string, rec?: string, rec_mode?: 'scheduled'|'completion' } metadata +---@return pending.Metadata metadata function M.body(text) local tokens = {} for token in text:gmatch('%S+') do @@ -608,7 +615,7 @@ end ---@param text string ---@return string description ----@return { due?: string, cat?: string, rec?: string, rec_mode?: 'scheduled'|'completion' } metadata +---@return pending.Metadata metadata function M.command_add(text) local cat_prefix = text:match('^(%S.-):%s') if cat_prefix then diff --git a/lua/pending/store.lua b/lua/pending/store.lua index 640e256..fcf420e 100644 --- a/lua/pending/store.lua +++ b/lua/pending/store.lua @@ -22,6 +22,17 @@ local config = require('pending.config') ---@field undo pending.Task[][] ---@field folded_categories string[] +---@class pending.TaskFields +---@field description string +---@field status? string +---@field category? string +---@field priority? integer +---@field due? string +---@field recur? string +---@field recur_mode? string +---@field order? integer +---@field _extra? table + ---@class pending.Store ---@field path string ---@field _data pending.Data? @@ -264,7 +275,7 @@ function Store:get(id) return nil end ----@param fields { description: string, status?: string, category?: string, priority?: integer, due?: string, recur?: string, recur_mode?: string, order?: integer, _extra?: table } +---@param fields pending.TaskFields ---@return pending.Task function Store:add(fields) local data = self:data() diff --git a/lua/pending/sync/oauth.lua b/lua/pending/sync/oauth.lua index dabbe2d..516a353 100644 --- a/lua/pending/sync/oauth.lua +++ b/lua/pending/sync/oauth.lua @@ -17,62 +17,39 @@ local BUNDLED_CLIENT_SECRET = 'PLACEHOLDER' ---@field expires_in? integer ---@field obtained_at? integer ----@class pending.OAuthClient +---@class pending.OAuthClientOpts ---@field name string ---@field scope string ---@field port integer ---@field config_key string + +---@class pending.OAuthClient : pending.OAuthClientOpts local OAuthClient = {} OAuthClient.__index = OAuthClient +local util = require('pending.sync.util') + local _active_close = nil -local _sync_in_flight = false ---@class pending.oauth local M = {} ----@param args string[] ----@param opts? table ----@return { code: integer, stdout: string, stderr: string } -function M.system(args, opts) - local co = coroutine.running() - if not co then - return vim.system(args, opts or {}):wait() --[[@as { code: integer, stdout: string, stderr: string }]] - end - vim.system(args, opts or {}, function(result) - vim.schedule(function() - coroutine.resume(co, result) - end) - end) - return coroutine.yield() --[[@as { code: integer, stdout: string, stderr: string }]] -end - ----@param fn fun(): nil -function M.async(fn) - coroutine.resume(coroutine.create(fn)) -end +M.system = util.system +M.async = util.async ---@param client pending.OAuthClient ---@param name string ---@param callback fun(access_token: string): nil function M.with_token(client, name, callback) - if _sync_in_flight then - require('pending.log').warn(name .. ': Sync already in progress — please wait.') - return - end - _sync_in_flight = true - M.async(function() - local token = client:get_access_token() - if not token then - _sync_in_flight = false - require('pending.log').warn(name .. ': Not authenticated — run :Pending auth.') - return - end - local ok, err = pcall(callback, token) - _sync_in_flight = false - if not ok then - require('pending.log').error(name .. ': ' .. tostring(err)) - end + util.async(function() + util.with_guard(name, function() + local token = client:get_access_token() + if not token then + require('pending.log').warn(name .. ': Not authenticated — run :Pending auth.') + return + end + callback(token) + end) end) end @@ -547,7 +524,7 @@ function OAuthClient:clear_tokens() os.remove(self:token_path()) end ----@param opts { name: string, scope: string, port: integer, config_key: string } +---@param opts pending.OAuthClientOpts ---@return pending.OAuthClient function M.new(opts) return setmetatable({ diff --git a/lua/pending/sync/util.lua b/lua/pending/sync/util.lua new file mode 100644 index 0000000..3c5c644 --- /dev/null +++ b/lua/pending/sync/util.lua @@ -0,0 +1,79 @@ +local log = require('pending.log') + +---@class pending.SystemResult +---@field code integer +---@field stdout string +---@field stderr string + +---@class pending.sync.util +local M = {} + +local _sync_in_flight = false + +---@param fn fun(): nil +function M.async(fn) + coroutine.resume(coroutine.create(fn)) +end + +---@param args string[] +---@param opts? table +---@return pending.SystemResult +function M.system(args, opts) + local co = coroutine.running() + if not co then + return vim.system(args, opts or {}):wait() --[[@as pending.SystemResult]] + end + vim.system(args, opts or {}, function(result) + vim.schedule(function() + coroutine.resume(co, result) + end) + end) + return coroutine.yield() --[[@as { code: integer, stdout: string, stderr: string }]] +end + +---@param name string +---@param fn fun(): nil +function M.with_guard(name, fn) + if _sync_in_flight then + log.warn(name .. ': Sync already in progress — please wait.') + return + end + _sync_in_flight = true + local ok, err = pcall(fn) + _sync_in_flight = false + if not ok then + log.error(name .. ': ' .. tostring(err)) + end +end + +---@return boolean +function M.sync_in_flight() + return _sync_in_flight +end + +---@param s pending.Store +function M.finish(s) + s:save() + require('pending')._recompute_counts() + local buffer = require('pending.buffer') + if buffer.bufnr() and vim.api.nvim_buf_is_valid(buffer.bufnr()) then + buffer.render(buffer.bufnr()) + end +end + +---@param parts [integer, string][] +---@return string +function M.fmt_counts(parts) + local items = {} + for _, p in ipairs(parts) do + if p[1] > 0 then + table.insert(items, p[1] .. ' ' .. p[2]) + end + end + if #items == 0 then + return 'nothing to do' + end + return table.concat(items, ' | ') +end + +return M