Compare commits
10 commits
90f85ba098
...
b57cdd20b0
| Author | SHA1 | Date | |
|---|---|---|---|
| b57cdd20b0 | |||
| c45aacfcbb | |||
| cfdcff9eba | |||
| fadad3ed95 | |||
| 628286c471 | |||
| 06a325baa4 | |||
| edd1750a0e | |||
| 23ae390f23 | |||
| 2a654ad27d | |||
| 133369b968 |
6 changed files with 77 additions and 30 deletions
|
|
@ -133,6 +133,7 @@ function M.open_line(above)
|
||||||
local insert_row = above and (row - 1) or row
|
local insert_row = above and (row - 1) or row
|
||||||
vim.bo[bufnr].modifiable = true
|
vim.bo[bufnr].modifiable = true
|
||||||
vim.api.nvim_buf_set_lines(bufnr, insert_row, insert_row, false, { '- [ ] ' })
|
vim.api.nvim_buf_set_lines(bufnr, insert_row, insert_row, false, { '- [ ] ' })
|
||||||
|
table.insert(_meta, insert_row + 1, { type = 'task' })
|
||||||
vim.api.nvim_win_set_cursor(0, { insert_row + 1, 6 })
|
vim.api.nvim_win_set_cursor(0, { insert_row + 1, 6 })
|
||||||
vim.cmd('startinsert!')
|
vim.cmd('startinsert!')
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,16 @@ local function _save_and_notify()
|
||||||
M._recompute_counts()
|
M._recompute_counts()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@return boolean
|
||||||
|
local function require_saved()
|
||||||
|
local bufnr = buffer.bufnr()
|
||||||
|
if bufnr and vim.bo[bufnr].modified then
|
||||||
|
log.warn('save changes first (:w)')
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
---@return pending.Counts
|
---@return pending.Counts
|
||||||
function M.counts()
|
function M.counts()
|
||||||
if not _counts then
|
if not _counts then
|
||||||
|
|
@ -175,6 +185,9 @@ end
|
||||||
---@param pred_str string
|
---@param pred_str string
|
||||||
---@return nil
|
---@return nil
|
||||||
function M.filter(pred_str)
|
function M.filter(pred_str)
|
||||||
|
if not require_saved() then
|
||||||
|
return
|
||||||
|
end
|
||||||
if pred_str == 'clear' or pred_str == '' then
|
if pred_str == 'clear' or pred_str == '' then
|
||||||
buffer.set_filter({}, {})
|
buffer.set_filter({}, {})
|
||||||
local bufnr = buffer.bufnr()
|
local bufnr = buffer.bufnr()
|
||||||
|
|
@ -243,6 +256,9 @@ function M._setup_buf_mappings(bufnr)
|
||||||
M.toggle_complete()
|
M.toggle_complete()
|
||||||
end,
|
end,
|
||||||
view = function()
|
view = function()
|
||||||
|
if not require_saved() then
|
||||||
|
return
|
||||||
|
end
|
||||||
buffer.toggle_view()
|
buffer.toggle_view()
|
||||||
end,
|
end,
|
||||||
priority = function()
|
priority = function()
|
||||||
|
|
@ -255,6 +271,9 @@ function M._setup_buf_mappings(bufnr)
|
||||||
M.undo_write()
|
M.undo_write()
|
||||||
end,
|
end,
|
||||||
filter = function()
|
filter = function()
|
||||||
|
if not require_saved() then
|
||||||
|
return
|
||||||
|
end
|
||||||
vim.ui.input({ prompt = 'Filter: ' }, function(input)
|
vim.ui.input({ prompt = 'Filter: ' }, function(input)
|
||||||
if input then
|
if input then
|
||||||
M.filter(input)
|
M.filter(input)
|
||||||
|
|
@ -370,6 +389,9 @@ end
|
||||||
|
|
||||||
---@return nil
|
---@return nil
|
||||||
function M.undo_write()
|
function M.undo_write()
|
||||||
|
if not require_saved() then
|
||||||
|
return
|
||||||
|
end
|
||||||
local s = get_store()
|
local s = get_store()
|
||||||
local stack = s:undo_stack()
|
local stack = s:undo_stack()
|
||||||
if #stack == 0 then
|
if #stack == 0 then
|
||||||
|
|
@ -388,6 +410,9 @@ function M.toggle_complete()
|
||||||
if not bufnr then
|
if not bufnr then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if not require_saved() then
|
||||||
|
return
|
||||||
|
end
|
||||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
local meta = buffer.meta()
|
local meta = buffer.meta()
|
||||||
if not meta[row] or meta[row].type ~= 'task' then
|
if not meta[row] or meta[row].type ~= 'task' then
|
||||||
|
|
@ -435,6 +460,9 @@ end
|
||||||
function M.done(id_str)
|
function M.done(id_str)
|
||||||
local id
|
local id
|
||||||
if not id_str or id_str == '' then
|
if not id_str or id_str == '' then
|
||||||
|
if not require_saved() then
|
||||||
|
return
|
||||||
|
end
|
||||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
local meta = buffer.meta()
|
local meta = buffer.meta()
|
||||||
if not meta[row] or meta[row].type ~= 'task' then
|
if not meta[row] or meta[row].type ~= 'task' then
|
||||||
|
|
@ -443,7 +471,6 @@ function M.done(id_str)
|
||||||
end
|
end
|
||||||
id = meta[row].id
|
id = meta[row].id
|
||||||
if not id then
|
if not id then
|
||||||
log.error('Task has no ID — save the buffer first.')
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
@ -493,6 +520,9 @@ function M.toggle_priority()
|
||||||
if not bufnr then
|
if not bufnr then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if not require_saved() then
|
||||||
|
return
|
||||||
|
end
|
||||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
local meta = buffer.meta()
|
local meta = buffer.meta()
|
||||||
if not meta[row] or meta[row].type ~= 'task' then
|
if not meta[row] or meta[row].type ~= 'task' then
|
||||||
|
|
@ -525,6 +555,9 @@ function M.prompt_date()
|
||||||
if not bufnr then
|
if not bufnr then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
if not require_saved() then
|
||||||
|
return
|
||||||
|
end
|
||||||
local row = vim.api.nvim_win_get_cursor(0)[1]
|
local row = vim.api.nvim_win_get_cursor(0)[1]
|
||||||
local meta = buffer.meta()
|
local meta = buffer.meta()
|
||||||
if not meta[row] or meta[row].type ~= 'task' then
|
if not meta[row] or meta[row].type ~= 'task' then
|
||||||
|
|
@ -885,22 +918,33 @@ function M.edit(id_str, rest)
|
||||||
log.info('Task #' .. id .. ' updated: ' .. table.concat(feedback, ', '))
|
log.info('Task #' .. id .. ' updated: ' .. table.concat(feedback, ', '))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@param args? string
|
||||||
---@return nil
|
---@return nil
|
||||||
function M.auth()
|
function M.auth(args)
|
||||||
local oauth = require('pending.sync.oauth')
|
local oauth = require('pending.sync.oauth')
|
||||||
vim.ui.select({ 'Google Tasks', 'Google Calendar', 'Google Tasks and Google Calendar' }, {
|
local parts = {}
|
||||||
prompt = 'Authenticate with:',
|
for w in (args or ''):gmatch('%S+') do
|
||||||
}, function(choice)
|
table.insert(parts, w)
|
||||||
if not choice then
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
|
local action = parts[#parts]
|
||||||
|
if action == parts[1] and (action == 'gtasks' or action == 'gcal') then
|
||||||
|
action = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if action == 'clear' then
|
||||||
|
oauth.google_client:clear_tokens()
|
||||||
|
log.info('OAuth tokens cleared — run :Pending auth to re-authenticate.')
|
||||||
|
elseif action == 'reset' then
|
||||||
|
oauth.google_client:_wipe()
|
||||||
|
log.info('OAuth tokens and credentials cleared — run :Pending auth to set up from scratch.')
|
||||||
|
else
|
||||||
local creds = oauth.google_client:resolve_credentials()
|
local creds = oauth.google_client:resolve_credentials()
|
||||||
if creds.client_id == oauth.BUNDLED_CLIENT_ID then
|
if creds.client_id == oauth.BUNDLED_CLIENT_ID then
|
||||||
oauth.google_client:setup()
|
oauth.google_client:setup()
|
||||||
else
|
else
|
||||||
oauth.google_client:auth()
|
oauth.google_client:auth()
|
||||||
end
|
end
|
||||||
end)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param args string
|
---@param args string
|
||||||
|
|
@ -919,7 +963,7 @@ function M.command(args)
|
||||||
local id_str, edit_rest = rest:match('^(%S+)%s*(.*)')
|
local id_str, edit_rest = rest:match('^(%S+)%s*(.*)')
|
||||||
M.edit(id_str, edit_rest)
|
M.edit(id_str, edit_rest)
|
||||||
elseif cmd == 'auth' then
|
elseif cmd == 'auth' then
|
||||||
M.auth()
|
M.auth(rest)
|
||||||
elseif SYNC_BACKEND_SET[cmd] then
|
elseif SYNC_BACKEND_SET[cmd] then
|
||||||
local action = rest:match('^(%S+)')
|
local action = rest:match('^(%S+)')
|
||||||
run_sync(cmd, action)
|
run_sync(cmd, action)
|
||||||
|
|
|
||||||
|
|
@ -134,16 +134,7 @@ local function with_token(callback)
|
||||||
oauth.async(function()
|
oauth.async(function()
|
||||||
local token = oauth.google_client:get_access_token()
|
local token = oauth.google_client:get_access_token()
|
||||||
if not token then
|
if not token then
|
||||||
oauth.google_client:auth(function()
|
log.warn('not authenticated — run :Pending auth')
|
||||||
oauth.async(function()
|
|
||||||
local fresh = oauth.google_client:get_access_token()
|
|
||||||
if fresh then
|
|
||||||
callback(fresh)
|
|
||||||
else
|
|
||||||
log.error(oauth.google_client.name .. ': authorization failed or was cancelled')
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
callback(token)
|
callback(token)
|
||||||
|
|
|
||||||
|
|
@ -404,16 +404,7 @@ local function with_token(callback)
|
||||||
oauth.async(function()
|
oauth.async(function()
|
||||||
local token = oauth.google_client:get_access_token()
|
local token = oauth.google_client:get_access_token()
|
||||||
if not token then
|
if not token then
|
||||||
oauth.google_client:auth(function()
|
log.warn('not authenticated — run :Pending auth')
|
||||||
oauth.async(function()
|
|
||||||
local fresh = oauth.google_client:get_access_token()
|
|
||||||
if fresh then
|
|
||||||
callback(fresh)
|
|
||||||
else
|
|
||||||
log.error(oauth.google_client.name .. ': authorization failed or was cancelled')
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
callback(token)
|
callback(token)
|
||||||
|
|
|
||||||
|
|
@ -496,6 +496,11 @@ function OAuthClient:_wipe()
|
||||||
os.remove(vim.fn.stdpath('data') .. '/pending/google_credentials.json')
|
os.remove(vim.fn.stdpath('data') .. '/pending/google_credentials.json')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@return nil
|
||||||
|
function OAuthClient:clear_tokens()
|
||||||
|
os.remove(self:token_path())
|
||||||
|
end
|
||||||
|
|
||||||
---@param opts { name: string, scope: string, port: integer, config_key: string }
|
---@param opts { name: string, scope: string, port: integer, config_key: string }
|
||||||
---@return pending.OAuthClient
|
---@return pending.OAuthClient
|
||||||
function M.new(opts)
|
function M.new(opts)
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,21 @@ end, {
|
||||||
if cmd_line:match('^Pending%s+edit') then
|
if cmd_line:match('^Pending%s+edit') then
|
||||||
return complete_edit(arg_lead, cmd_line)
|
return complete_edit(arg_lead, cmd_line)
|
||||||
end
|
end
|
||||||
|
if cmd_line:match('^Pending%s+auth') then
|
||||||
|
local after_auth = cmd_line:match('^Pending%s+auth%s+(.*)') or ''
|
||||||
|
local parts = {}
|
||||||
|
for w in after_auth:gmatch('%S+') do
|
||||||
|
table.insert(parts, w)
|
||||||
|
end
|
||||||
|
local trailing = after_auth:match('%s$')
|
||||||
|
if #parts == 0 or (#parts == 1 and not trailing) then
|
||||||
|
return filter_candidates(arg_lead, { 'gcal', 'gtasks', 'clear', 'reset' })
|
||||||
|
end
|
||||||
|
if #parts == 1 or (#parts == 2 and not trailing) then
|
||||||
|
return filter_candidates(arg_lead, { 'clear', 'reset' })
|
||||||
|
end
|
||||||
|
return {}
|
||||||
|
end
|
||||||
local backend_set = pending.sync_backend_set()
|
local backend_set = pending.sync_backend_set()
|
||||||
local matched_backend = cmd_line:match('^Pending%s+(%S+)')
|
local matched_backend = cmd_line:match('^Pending%s+(%S+)')
|
||||||
if matched_backend and backend_set[matched_backend] then
|
if matched_backend and backend_set[matched_backend] then
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue