diff --git a/doc/pending.txt b/doc/pending.txt index 11c3973..f8c61a9 100644 --- a/doc/pending.txt +++ b/doc/pending.txt @@ -589,14 +589,20 @@ Configuration is done via `vim.g.pending`. Set this before the plugin loads: >lua vim.g.pending = { data_path = vim.fn.stdpath('data') .. '/pending/tasks.json', - default_view = 'category', default_category = 'Todo', date_format = '%b %d', date_syntax = 'due', recur_syntax = 'rec', someday_date = '9999-12-30', - folding = true, - category_order = {}, + view = { + default = 'category', + eol_format = '%c %r %d', + category = { + order = {}, + folding = true, + }, + queue = {}, + }, keymaps = { close = 'q', toggle = '', @@ -634,10 +640,6 @@ Fields: ~ See |pending-store-resolution| for how the active store is chosen at runtime. - {default_view} ('category'|'priority', default: 'category') - The view to use when the buffer is opened for the - first time in a session. - {default_category} (string, default: 'Todo') Category assigned to new tasks when no `cat:` token is present and no `Category: ` prefix is used with @@ -648,32 +650,6 @@ Fields: ~ virtual text in the buffer. Examples: `'%Y-%m-%d'` for ISO dates, `'%d %b'` for day-first. - {eol_format} (string, default: '%c %r %d') - Format string controlling the order, content, and - separators of end-of-line virtual text on task lines. - Three specifiers are available: - - `%c` category icon + name (`PendingHeader`) - `%r` recurrence icon + pattern (`PendingRecur`) - `%d` due icon + date (`PendingDue` / `PendingOverdue`) - - Literal text between specifiers is rendered with the - `Normal` highlight group and acts as a separator. - When a specifier's data is absent (e.g. `%d` on a - task with no due date), the specifier and any - surrounding literal text up to the next specifier - are omitted — missing fields never leave gaps. - - `%c` only renders in priority view (where - `show_category` is true). In category view it is - always omitted regardless of the format string. - - Examples: >lua - vim.g.pending = { eol_format = '%d %r' } - vim.g.pending = { eol_format = '%d | %r' } - vim.g.pending = { eol_format = '%c %d %r' } -< - {input_date_formats} (string[], default: {}) *pending-input-formats* List of strftime-like format strings tried in order when parsing a `due:` token that does not match the @@ -705,38 +681,57 @@ Fields: ~ The date that `later` and `someday` resolve to. This acts as a "no date" sentinel for GTD-style workflows. - {category_order} (string[], default: {}) - Ordered list of category names. In category view, - categories that appear in this list are shown in the - given order. Categories not in the list are appended - after the ordered ones in their natural order. + {view} (table) *pending.ViewConfig* + View rendering configuration. Groups all settings + that affect how the buffer displays tasks. - {folding} (boolean|table, default: true) *pending.FoldingConfig* - Controls category-level folds in category view. When - `true`, folds are enabled with the default foldtext - `'%c (%n tasks)'`. When `false`, folds are disabled - entirely. When a table, folds are enabled and the - table may contain: + {default} ('category'|'priority', default: 'category') + The view to use when the buffer is opened + for the first time in a session. - {foldtext} (string|false, default: '%c (%n tasks)') - Custom foldtext format string. Set to - `false` to use Vim's built-in - foldtext. Two specifiers are - available: - `%c` category name - `%n` number of tasks in the fold - The category icon is prepended - automatically. When `false`, the - default Vim foldtext is used. + {eol_format} (string, default: '%c %r %d') + Format string for end-of-line virtual text. + Specifiers: + `%c` category icon + name (`PendingHeader`) + `%r` recurrence icon + pattern (`PendingRecur`) + `%d` due icon + date (`PendingDue`/`PendingOverdue`) + Literal text between specifiers acts as a + separator. Absent fields and surrounding + literals are collapsed automatically. `%c` + only renders in priority view. - Folds only apply to category view; priority view - is always fold-free regardless of this setting. + {category} (table) *pending.CategoryViewConfig* + Category view settings. + + {order} (string[], default: {}) + Ordered list of category names. Categories + in this list appear in the given order; + others are appended after. + + {folding} (boolean|table, default: true) + *pending.FoldingConfig* + Controls category-level folds. `true` + enables with default foldtext `'%c (%n + tasks)'`. `false` disables entirely. A + table may contain: + {foldtext} (string|false) Format string + with `%c` (category) and `%n` (count). + `false` uses Vim's built-in foldtext. + Folds only apply to category view. + + {queue} (table) *pending.QueueViewConfig* + Queue (priority) view settings. Examples: >lua - vim.g.pending = { folding = true } - vim.g.pending = { folding = false } vim.g.pending = { - folding = { foldtext = '%c (%n tasks)' }, + view = { + default = 'priority', + eol_format = '%d | %r', + category = { + order = { 'Work', 'Personal' }, + folding = { foldtext = '%c: %n items' }, + }, + }, } < diff --git a/lua/pending/buffer.lua b/lua/pending/buffer.lua index 638ea60..012dc35 100644 --- a/lua/pending/buffer.lua +++ b/lua/pending/buffer.lua @@ -440,7 +440,7 @@ end local function apply_extmarks(bufnr, line_meta) local cfg = config.get() local icons = cfg.icons - local eol_segments = parse_eol_format(cfg.eol_format or '%c %r %d') + local eol_segments = parse_eol_format(cfg.view.eol_format or '%c %r %d') vim.api.nvim_buf_clear_namespace(bufnr, ns_eol, 0, -1) vim.api.nvim_buf_clear_namespace(bufnr, ns_inline, 0, -1) for i, m in ipairs(line_meta) do @@ -578,7 +578,7 @@ function M.render(bufnr) return end - current_view = current_view or config.get().default_view + current_view = current_view or config.get().view.default local view_label = current_view == 'priority' and 'queue' or current_view vim.api.nvim_buf_set_name(bufnr, 'pending://' .. view_label) local all_tasks = _store and _store:active_tasks() or {} diff --git a/lua/pending/config.lua b/lua/pending/config.lua index b7a42ad..36c63d2 100644 --- a/lua/pending/config.lua +++ b/lua/pending/config.lua @@ -49,22 +49,31 @@ ---@field next_task? string|false ---@field prev_task? string|false +---@class pending.CategoryViewConfig +---@field order? string[] +---@field folding? boolean|pending.FoldingConfig + +---@class pending.QueueViewConfig + +---@class pending.ViewConfig +---@field default? 'category'|'priority' +---@field eol_format? string +---@field category? pending.CategoryViewConfig +---@field queue? pending.QueueViewConfig + ---@class pending.Config ---@field data_path string ----@field default_view 'category'|'priority' ---@field default_category string ---@field date_format string ---@field date_syntax string ---@field recur_syntax string ---@field someday_date string ---@field input_date_formats? string[] ----@field category_order? string[] ---@field drawer_height? integer ---@field debug? boolean ---@field keymaps pending.Keymaps ----@field folding? boolean|pending.FoldingConfig +---@field view pending.ViewConfig ---@field sync? pending.SyncConfig ----@field eol_format? string ---@field icons pending.Icons ---@class pending.config @@ -73,15 +82,20 @@ local M = {} ---@type pending.Config local defaults = { data_path = vim.fn.stdpath('data') .. '/pending/tasks.json', - default_view = 'category', default_category = 'Todo', date_format = '%b %d', date_syntax = 'due', recur_syntax = 'rec', someday_date = '9999-12-30', - eol_format = '%c %r %d', - folding = true, - category_order = {}, + view = { + default = 'category', + eol_format = '%c %r %d', + category = { + order = {}, + folding = true, + }, + queue = {}, + }, keymaps = { close = 'q', toggle = '', @@ -132,7 +146,7 @@ end ---@return pending.ResolvedFolding function M.resolve_folding() - local raw = M.get().folding + local raw = M.get().view.category.folding if raw == false then return { enabled = false, foldtext = false } elseif raw == true or raw == nil then diff --git a/lua/pending/views.lua b/lua/pending/views.lua index 3b67f90..3f7a4cf 100644 --- a/lua/pending/views.lua +++ b/lua/pending/views.lua @@ -102,7 +102,7 @@ function M.category_view(tasks) end end - local cfg_order = config.get().category_order + local cfg_order = config.get().view.category.order if cfg_order and #cfg_order > 0 then local ordered = {} local seen = {} diff --git a/spec/views_spec.lua b/spec/views_spec.lua index ede9de9..b09633f 100644 --- a/spec/views_spec.lua +++ b/spec/views_spec.lua @@ -228,7 +228,7 @@ describe('views', function() end) it('respects category_order when set', function() - vim.g.pending = { data_path = tmpdir .. '/tasks.json', category_order = { 'Work', 'Inbox' } } + vim.g.pending = { data_path = tmpdir .. '/tasks.json', view = { category = { order = { 'Work', 'Inbox' } } } } config.reset() s:add({ description = 'Inbox task', category = 'Inbox' }) s:add({ description = 'Work task', category = 'Work' }) @@ -248,7 +248,7 @@ describe('views', function() end) it('appends categories not in category_order after ordered ones', function() - vim.g.pending = { data_path = tmpdir .. '/tasks.json', category_order = { 'Work' } } + vim.g.pending = { data_path = tmpdir .. '/tasks.json', view = { category = { order = { 'Work' } } } } config.reset() s:add({ description = 'Errand', category = 'Errands' }) s:add({ description = 'Work task', category = 'Work' })