feat(filter): oil-like editable filter line (#43)
* feat(filter): oil-like editable filter line with predicate dispatch Problem: no way to narrow the pending buffer to a subset of tasks without manual scrolling; filtered-out tasks would be silently deleted on :w because diff.apply() marks unseen IDs as deleted. Solution: add a FILTER: line rendered at the top of the buffer when a filter is active. The line is editable — :w re-parses it and updates the hidden set. diff.apply() gains a hidden_ids param that prevents filtered-out tasks from being marked deleted. Predicates: cat:X, overdue, today, priority (space-separated AND). :Pending filter sets it programmatically; :Pending filter clear removes it. * ci: format
This commit is contained in:
parent
306e11aee6
commit
836a53b541
7 changed files with 526 additions and 8 deletions
|
|
@ -16,6 +16,10 @@ local current_view = nil
|
|||
local _meta = {}
|
||||
---@type table<integer, table<string, boolean>>
|
||||
local _fold_state = {}
|
||||
---@type string[]
|
||||
local _filter_predicates = {}
|
||||
---@type table<integer, true>
|
||||
local _hidden_ids = {}
|
||||
|
||||
---@return pending.LineMeta[]
|
||||
function M.meta()
|
||||
|
|
@ -37,6 +41,24 @@ function M.current_view_name()
|
|||
return current_view
|
||||
end
|
||||
|
||||
---@return string[]
|
||||
function M.filter_predicates()
|
||||
return _filter_predicates
|
||||
end
|
||||
|
||||
---@return table<integer, true>
|
||||
function M.hidden_ids()
|
||||
return _hidden_ids
|
||||
end
|
||||
|
||||
---@param predicates string[]
|
||||
---@param hidden table<integer, true>
|
||||
---@return nil
|
||||
function M.set_filter(predicates, hidden)
|
||||
_filter_predicates = predicates
|
||||
_hidden_ids = hidden
|
||||
end
|
||||
|
||||
---@return nil
|
||||
function M.clear_winid()
|
||||
task_winid = nil
|
||||
|
|
@ -124,7 +146,13 @@ local function apply_extmarks(bufnr, line_meta)
|
|||
vim.api.nvim_buf_clear_namespace(bufnr, task_ns, 0, -1)
|
||||
for i, m in ipairs(line_meta) do
|
||||
local row = i - 1
|
||||
if m.type == 'task' then
|
||||
if m.type == 'filter' then
|
||||
local line = vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false)[1] or ''
|
||||
vim.api.nvim_buf_set_extmark(bufnr, task_ns, row, 0, {
|
||||
end_col = #line,
|
||||
hl_group = 'PendingFilter',
|
||||
})
|
||||
elseif m.type == 'task' then
|
||||
local due_hl = m.overdue and 'PendingOverdue' or 'PendingDue'
|
||||
local virt_parts = {}
|
||||
if m.show_category and m.category then
|
||||
|
|
@ -170,6 +198,7 @@ local function setup_highlights()
|
|||
vim.api.nvim_set_hl(0, 'PendingDone', { link = 'Comment', default = true })
|
||||
vim.api.nvim_set_hl(0, 'PendingPriority', { link = 'DiagnosticWarn', default = true })
|
||||
vim.api.nvim_set_hl(0, 'PendingRecur', { link = 'DiagnosticInfo', default = true })
|
||||
vim.api.nvim_set_hl(0, 'PendingFilter', { link = 'DiagnosticWarn', default = true })
|
||||
end
|
||||
|
||||
local function snapshot_folds(bufnr)
|
||||
|
|
@ -225,7 +254,13 @@ function M.render(bufnr)
|
|||
current_view = current_view or config.get().default_view
|
||||
local view_label = current_view == 'priority' and 'queue' or current_view
|
||||
vim.api.nvim_buf_set_name(bufnr, 'pending://' .. view_label)
|
||||
local tasks = store.active_tasks()
|
||||
local all_tasks = store.active_tasks()
|
||||
local tasks = {}
|
||||
for _, task in ipairs(all_tasks) do
|
||||
if not _hidden_ids[task.id] then
|
||||
table.insert(tasks, task)
|
||||
end
|
||||
end
|
||||
|
||||
local lines, line_meta
|
||||
if current_view == 'priority' then
|
||||
|
|
@ -234,6 +269,11 @@ function M.render(bufnr)
|
|||
lines, line_meta = views.category_view(tasks)
|
||||
end
|
||||
|
||||
if #_filter_predicates > 0 then
|
||||
table.insert(lines, 1, 'FILTER: ' .. table.concat(_filter_predicates, ' '))
|
||||
table.insert(line_meta, 1, { type = 'filter' })
|
||||
end
|
||||
|
||||
_meta = line_meta
|
||||
|
||||
snapshot_folds(bufnr)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue