pending.nvim/lua/pending/sync/util.lua
Barrett Ruth 58804fcfc7 feat(s3): create bucket interactively during auth when unconfigured
Problem: when a user runs `:Pending s3 auth` with no bucket configured,
auth succeeds but offers no way to create the bucket. The user must
manually run `aws s3api create-bucket` and update their config.

Solution: add `util.input()` coroutine-aware prompt wrapper and a
`create_bucket()` flow in `s3.lua` that prompts for bucket name and
region, handles the `us-east-1` LocationConstraint quirk, and logs a
config snippet on success. Called automatically from `auth()` when
`sync.s3.bucket` is absent.
2026-03-08 20:16:00 -04:00

98 lines
2.2 KiB
Lua

local log = require('pending.log')
---@class pending.SystemResult
---@field code integer
---@field stdout string
---@field stderr string
---@class pending.CountPart
---@field [1] integer
---@field [2] 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 opts? {prompt?: string, default?: string}
---@return string?
function M.input(opts)
local co = coroutine.running()
if not co then
error('util.input() must be called inside a coroutine')
end
vim.ui.input(opts or {}, function(result)
vim.schedule(function()
coroutine.resume(co, result)
end)
end)
return coroutine.yield() --[[@as 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 pending.CountPart[]
---@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