refactor(icons): ascii defaults, checkbox overlays, and cleanup (#57)

* docs: remove unnecessary mini.ai recipe from vimdoc

Problem: the `*pending-mini-ai*` section assumed mini.ai intercepts
buffer-local `at`/`it`/`aC`/`iC` mappings, requiring a manual
`vim.b.miniai_config` workaround.

Solution: remove the section. Neovim's keymap resolver already
prioritizes longer buffer-local mappings over mini.ai's global
`a`/`i` handlers — no recipe needed.

* refactor(icons): unify category/header icon and use checkbox overlays

Problem: `header` and `category` were separate icons for the same
concept. The icon overlay replaced `[ ]` with a bare character,
hiding the markdown checkbox syntax. Header format `## ` produced
a double-space with single-char icons.

Solution: merge `header` into `category` (one icon for both header
lines and EOL labels). Overlay renders `[icon]` preserving bracket
syntax. Change header line format from `## ` to `# ` so the
2-char overlay (`# `) maps cleanly.

* ci: remove empty `assets/` placeholder
This commit is contained in:
Barrett Ruth 2026-03-04 18:44:41 -05:00 committed by GitHub
parent ee8b660f7c
commit 3e8fd0a6a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 61 additions and 152 deletions

View file

@ -21,11 +21,11 @@ describe('diff', function()
describe('parse_buffer', function()
it('parses headers and tasks', function()
local lines = {
'## School',
'# School',
'/1/- [ ] Do homework',
'/2/- [!] Read chapter 5',
'',
'## Errands',
'# Errands',
'/3/- [ ] Buy groceries',
}
local result = diff.parse_buffer(lines)
@ -44,7 +44,7 @@ describe('diff', function()
it('handles new tasks without ids', function()
local lines = {
'## Inbox',
'# Inbox',
'- [ ] New task here',
}
local result = diff.parse_buffer(lines)
@ -56,7 +56,7 @@ describe('diff', function()
it('inline cat: token overrides header category', function()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Buy milk cat:Work',
}
local result = diff.parse_buffer(lines)
@ -67,7 +67,7 @@ describe('diff', function()
it('extracts rec: token from buffer line', function()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Take trash out rec:weekly',
}
local result = diff.parse_buffer(lines)
@ -76,7 +76,7 @@ describe('diff', function()
it('extracts rec: with completion mode', function()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Water plants rec:!daily',
}
local result = diff.parse_buffer(lines)
@ -86,7 +86,7 @@ describe('diff', function()
it('inline due: token is parsed', function()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Buy milk due:2026-03-15',
}
local result = diff.parse_buffer(lines)
@ -99,7 +99,7 @@ describe('diff', function()
describe('apply', function()
it('creates new tasks from buffer lines', function()
local lines = {
'## Inbox',
'# Inbox',
'- [ ] First task',
'- [ ] Second task',
}
@ -116,7 +116,7 @@ describe('diff', function()
s:add({ description = 'Delete me' })
s:save()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Keep me',
}
diff.apply(lines, s)
@ -132,7 +132,7 @@ describe('diff', function()
s:add({ description = 'Original' })
s:save()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Renamed',
}
diff.apply(lines, s)
@ -146,7 +146,7 @@ describe('diff', function()
t.modified = '2020-01-01T00:00:00Z'
s:save()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Renamed',
}
diff.apply(lines, s)
@ -160,7 +160,7 @@ describe('diff', function()
s:add({ description = 'Original' })
s:save()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Original',
'/1/- [ ] Copy of original',
}
@ -174,7 +174,7 @@ describe('diff', function()
s:add({ description = 'Moving task', category = 'Inbox' })
s:save()
local lines = {
'## Work',
'# Work',
'/1/- [ ] Moving task',
}
diff.apply(lines, s)
@ -187,7 +187,7 @@ describe('diff', function()
s:add({ description = 'Stable task', category = 'Inbox' })
s:save()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Stable task',
}
diff.apply(lines, s)
@ -203,7 +203,7 @@ describe('diff', function()
s:add({ description = 'Pay bill', due = '2026-03-15' })
s:save()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Pay bill',
}
diff.apply(lines, s)
@ -214,7 +214,7 @@ describe('diff', function()
it('stores recur field on new tasks from buffer', function()
local lines = {
'## Inbox',
'# Inbox',
'- [ ] Take out trash rec:weekly',
}
diff.apply(lines, s)
@ -228,7 +228,7 @@ describe('diff', function()
s:add({ description = 'Task', recur = 'daily' })
s:save()
local lines = {
'## Todo',
'# Todo',
'/1/- [ ] Task rec:weekly',
}
diff.apply(lines, s)
@ -241,7 +241,7 @@ describe('diff', function()
s:add({ description = 'Task', recur = 'daily' })
s:save()
local lines = {
'## Todo',
'# Todo',
'/1/- [ ] Task',
}
diff.apply(lines, s)
@ -252,7 +252,7 @@ describe('diff', function()
it('parses rec: with completion mode prefix', function()
local lines = {
'## Inbox',
'# Inbox',
'- [ ] Water plants rec:!weekly',
}
diff.apply(lines, s)
@ -266,7 +266,7 @@ describe('diff', function()
s:add({ description = 'Task name', priority = 1 })
s:save()
local lines = {
'## Inbox',
'# Inbox',
'/1/- [ ] Task name',
}
diff.apply(lines, s)

View file

@ -15,45 +15,42 @@ describe('icons', function()
it('has default icon values', function()
local icons = config.get().icons
assert.equals('-', icons.pending)
assert.equals(' ', icons.pending)
assert.equals('x', icons.done)
assert.equals('!', icons.priority)
assert.equals('>', icons.header)
assert.equals('.', icons.due)
assert.equals('~', icons.recur)
assert.equals('#', icons.category)
end)
it('allows overriding individual icons', function()
vim.g.pending = { icons = { pending = '', done = '' } }
vim.g.pending = { icons = { pending = '*', done = '+' } }
config.reset()
local icons = config.get().icons
assert.equals('', icons.pending)
assert.equals('', icons.done)
assert.equals('*', icons.pending)
assert.equals('+', icons.done)
assert.equals('!', icons.priority)
assert.equals('>', icons.header)
assert.equals('#', icons.category)
end)
it('allows overriding all icons', function()
vim.g.pending = {
icons = {
pending = '-',
done = 'x',
priority = '!',
header = '>',
done = '+',
priority = '*',
due = '@',
recur = '~',
category = '+',
recur = '^',
category = '&',
},
}
config.reset()
local icons = config.get().icons
assert.equals('-', icons.pending)
assert.equals('x', icons.done)
assert.equals('!', icons.priority)
assert.equals('>', icons.header)
assert.equals('+', icons.done)
assert.equals('*', icons.priority)
assert.equals('@', icons.due)
assert.equals('~', icons.recur)
assert.equals('+', icons.category)
assert.equals('^', icons.recur)
assert.equals('&', icons.category)
end)
end)

View file

@ -26,7 +26,7 @@ describe('views', function()
s:add({ description = 'Task A', category = 'Work' })
s:add({ description = 'Task B', category = 'Work' })
local lines, meta = views.category_view(s: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)
@ -243,8 +243,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()
@ -259,8 +259,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()
@ -273,8 +273,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)