1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
local M = {}
local A = vim.api
local F = vim.fn
local TASK_STATUS_PATTERN = [=[\[[ x-]\] ]=]
local TASK_STATUS_PATTERN_EXCEPT_DONE = [=[\[[ -]\] ]=]
local TASK_STATUS_PATTERN_EXCEPT_CANCELED = [=[\[[ x]\] ]=]
-- op = T
-- T => T
-- D => T
-- C => T
-- op = D
-- T => D
-- D => D
-- C => C
-- op = C
-- T => C
-- D => D
-- C => C
local function vim_match(s, pattern)
return vim.regex(pattern):match_str(s)
end
local function switch_task_status_internal(line_num, op, is_subtask)
local line = F.getline(line_num)
local pattern
if is_subtask then
if op == ' ' then
pattern = TASK_STATUS_PATTERN
elseif op == 'x' then
pattern = TASK_STATUS_PATTERN_EXCEPT_CANCELED
elseif op == '-' then
pattern = TASK_STATUS_PATTERN_EXCEPT_DONE
else
assert('unexpected op: ' .. tostring(op))
end
else
pattern = TASK_STATUS_PATTERN
end
if vim_match(line, pattern) then
local replacement = ('[%s] '):format(op)
F.setline(line_num, F.substitute(line, pattern, replacement, ''))
return true
else
return false
end
end
function M.checkbox(check, char)
local line = F.getline('.')
if vim_match(line, [[^\s*$]]) and #line % F.shiftwidth() == 0 then
return check and '[x] ' or '[ ] '
else
return char
end
end
function M.switch_task_status(op)
switch_task_status_internal(F.line('.'), op)
end
function M.switch_task_status_rec(op)
local current_line_num = F.line('.')
local replaced = switch_task_status_internal(current_line_num, op)
if not replaced then
return
end
local last_line_num = F.line('$')
if current_line_num == last_line_num then
return
end
local base_indent_level = F.indent('.')
for l = current_line_num + 1, last_line_num do
if F.indent(l) <= base_indent_level then
break
end
switch_task_status_internal(l, op, true)
end
end
return M
|