refactor(views): adopt markdown checkbox line format

Problem: task lines used an opaque /ID/  [N] prefix format that was
hard to read and inconsistent between category and priority views.
Header lines had no visual marker distinguishing them from tasks.

Solution: render headers as '## Cat', task lines as
'/ID/- [x|!| ] description'. State encoding: [x]=done, [!]=urgent,
[ ]=pending. Both views use the same construction.
This commit is contained in:
Barrett Ruth 2026-02-24 23:14:32 -05:00
parent 4c8944c5ee
commit afb9e65f8d
2 changed files with 17 additions and 19 deletions

View file

@ -125,7 +125,7 @@ function M.category_view(tasks)
table.insert(lines, '')
table.insert(meta, { type = 'blank' })
end
table.insert(lines, cat)
table.insert(lines, '## ' .. cat)
table.insert(meta, { type = 'header', category = cat })
local all = {}
@ -138,9 +138,8 @@ function M.category_view(tasks)
for _, task in ipairs(all) do
local prefix = '/' .. task.id .. '/'
local indent = ' '
local prio = task.priority > 0 and ('[' .. task.priority .. '] ') or ''
local line = prefix .. indent .. prio .. task.description
local state = task.status == 'done' and 'x' or (task.priority > 0 and '!' or ' ')
local line = prefix .. '- [' .. state .. '] ' .. task.description
table.insert(lines, line)
table.insert(meta, {
type = 'task',
@ -189,9 +188,8 @@ function M.priority_view(tasks)
for _, task in ipairs(all) do
local prefix = '/' .. task.id .. '/'
local indent = ' '
local prio = task.priority == 1 and '! ' or ''
local line = prefix .. indent .. prio .. task.description
local state = task.status == 'done' and 'x' or (task.priority > 0 and '!' or ' ')
local line = prefix .. '- [' .. state .. '] ' .. task.description
table.insert(lines, line)
table.insert(meta, {
type = 'task',

View file

@ -27,7 +27,7 @@ describe('views', function()
store.add({ description = 'Task A', category = 'Work' })
store.add({ description = 'Task B', category = 'Work' })
local lines, meta = views.category_view(store.active_tasks())
assert.are.equal('Work', lines[1])
assert.are.equal('## Work', lines[1])
assert.are.equal('header', meta[1].type)
assert.is_true(lines[2]:find('Task A') ~= nil)
assert.is_true(lines[3]:find('Task B') ~= nil)
@ -113,10 +113,10 @@ describe('views', function()
task_line = lines[i]
end
end
assert.are.equal('/1/ My task', task_line)
assert.are.equal('/1/- [ ] My task', task_line)
end)
it('formats priority task lines as /ID/ ! description', function()
it('formats priority task lines as /ID/- [!] description', function()
store.add({ description = 'Important', category = 'Inbox', priority = 1 })
local lines, meta = views.category_view(store.active_tasks())
local task_line
@ -125,7 +125,7 @@ describe('views', function()
task_line = lines[i]
end
end
assert.are.equal('/1/ ! Important', task_line)
assert.are.equal('/1/- [!] Important', task_line)
end)
it('sets LineMeta type=header for header lines with correct category', function()
@ -220,8 +220,8 @@ describe('views', function()
end
end
end
assert.are.equal('Work', first_header)
assert.are.equal('Inbox', second_header)
assert.are.equal('## Work', first_header)
assert.are.equal('## Inbox', second_header)
end)
it('appends categories not in category_order after ordered ones', function()
@ -236,8 +236,8 @@ describe('views', function()
table.insert(headers, lines[i])
end
end
assert.are.equal('Work', headers[1])
assert.are.equal('Errands', headers[2])
assert.are.equal('## Work', headers[1])
assert.are.equal('## Errands', headers[2])
end)
it('preserves insertion order when category_order is empty', function()
@ -250,8 +250,8 @@ describe('views', function()
table.insert(headers, lines[i])
end
end
assert.are.equal('Alpha', headers[1])
assert.are.equal('Beta', headers[2])
assert.are.equal('## Alpha', headers[1])
assert.are.equal('## Beta', headers[2])
end)
end)
@ -325,10 +325,10 @@ describe('views', function()
assert.is_true(earlier_row < later_row)
end)
it('formats task lines as /ID/ description', function()
it('formats task lines as /ID/- [ ] description', function()
store.add({ description = 'My task', category = 'Inbox' })
local lines, _ = views.priority_view(store.active_tasks())
assert.are.equal('/1/ My task', lines[1])
assert.are.equal('/1/- [ ] My task', lines[1])
end)
it('sets show_category=true for all task meta entries', function()