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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
|
local brain_home = os.getenv('HOME') .. '/brain'
local templates_path = brain_home .. '/1 periodic/99 templates'
-------------------------------------------------------------------------------
-- Private functions for Periodic Tasks
-------------------------------------------------------------------------------
local function load_template(template_name)
local template_path = templates_path .. '/' .. template_name
print(template_path)
local template_file = io.open(template_path, 'r')
if not template_file then
print('Template file not found')
return
end
local content = template_file:read('*a')
template_file:close()
return content
end
local function open_or_create_from_template(template_name, file)
local journal_file = io.open(file, 'r')
if not journal_file then
local template_contents = load_template(template_name)
journal_file = io.open(file, 'w')
journal_file:write(template_contents)
journal_file:close()
end
vim.cmd('edit ' .. file)
end
local function find_tasks(completed)
local journal_path = brain_home .. '/1 periodic/01 journal/'
local pattern = '^\\s*\\- \\[ \\]'
if completed == 1 then
pattern = '^\\s*\\- \\[x\\]'
end
local command = string.format('rg --vimgrep \'%s\' \'%s\'', pattern, journal_path)
local results = vim.fn.systemlist(command)
if vim.v.shell_error == 0 then
local items = {}
for _, line in ipairs(results) do
local filename, lnum, col, text = line:match("([^:]+):(%d+):(%d+):(.*)")
table.insert(items, {
filename = filename,
lnum = tonumber(lnum),
col = tonumber(col),
text = text,
})
end
-- Set location list for the current window and open it
vim.fn.setloclist(0, items)
vim.cmd('lopen')
end
end
local function get_this_weeks_files()
local today = os.time()
local day_of_week = os.date('*t', today).wday
local week_start = today - (day_of_week - 2) * 86400
local filenames = {}
for i = 0, 6 do
local date = os.date('*t', week_start + i * 86400)
table.insert(filenames, string.format('%04d-%02d-%02d.md', date.year, date.month, date.day))
end
return filenames
end
local function populate_quicklist_with_files(filenames)
local uv = vim.loop
local items = {}
local pattern = '^%s*%- %[[ ]?x?%]'
for _, filename in ipairs(filenames) do
local daily_note = brain_home .. '/1 periodic/01 journal/' .. filename
local stat = uv.fs_stat(daily_note)
if stat then -- File exists
local file, err = io.open(daily_note, 'r')
if file then
local set_header = 0
local line_number = 0
for line in file:lines() do
line_number = line_number + 1
if line:match(pattern) then
if set_header == 0 then
local header = string.sub(filename:match('([^/\\]+)$'), 1, -4)
table.insert(items, {filename = '', lnum = 0, text = header})
set_header = 1
end
table.insert(items, {filename = daily_note, text = line, lnum = line_number})
end
end
file:close()
end
end
end
vim.fn.setloclist(0, {}, ' ', {title = 'Weekly Tasks', items = items})
vim.cmd('lopen')
end
-------------------------------------------------------------------------------
-- Periodic Notes
-------------------------------------------------------------------------------
function open_daily_note()
local filename_format = os.date('%Y-%m-%d')
local template_name = '001 daily.md'
local daily_note = brain_home .. '/1 periodic/01 journal/' .. filename_format .. '.md'
open_or_create_from_template(template_name, daily_note)
end
function open_weekly_note()
local filename_format = os.date('%Y-w%V')
local template_name = '002 weekly.md'
local weekly_note = brain_home .. '/1 periodic/02 weeks/' .. filename_format .. '.md'
open_or_create_from_template(template_name, weekly_note)
end
-------------------------------------------------------------------------------
-- Task Utilities
-------------------------------------------------------------------------------
function toggle_task()
local line_num = vim.api.nvim_win_get_cursor(0)[1]
local line = vim.api.nvim_get_current_line()
local unchecked_pattern = '^%s*%- %[ %]'
local checked_pattern = '^%s*%- %[x%]'
if line:match(unchecked_pattern) then
line = line:gsub(unchecked_pattern, '- [x]', 1)
elseif line:match(checked_pattern) then
line = line:gsub(checked_pattern, '- [ ]', 1)
end
vim.api.nvim_buf_set_lines(0, line_num - 1, line_num, false, {line})
end
-------------------------------------------------------------------------------
-- Task Quicklist Views
-------------------------------------------------------------------------------
function open_agenda()
local week_filenames = get_this_weeks_files()
populate_quicklist_with_files(week_filenames)
end
function open_open()
find_tasks(0)
end
-------------------------------------------------------------------------------
-- Key Bindings
-------------------------------------------------------------------------------
-- Periodic Notes
vim.api.nvim_set_keymap('n', '<leader>od', '<cmd>lua open_daily_note()<CR>', { noremap = true, silent = true })
vim.api.nvim_set_keymap('n', '<leader>ow', '<cmd>lua open_weekly_note()<CR>', { noremap = true, silent = true })
-- Planned: \om to open monthly, \os to open seasonly, and \oy to open yearly
-- Agenda Views
vim.api.nvim_set_keymap('n', '<leader>oa', '<cmd>lua open_agenda()<CR>', { noremap = true, silent = true })
vim.api.nvim_set_keymap('n', '<leader>oo', '<cmd>lua open_open()<CR>', { noremap = true, silent = true })
-- Planned: \oj to open journal
-- Task Helpers
vim.api.nvim_set_keymap('n', '<leader>t', '<cmd>lua toggle_task()<CR>', { noremap = true, silent = true })
-- Planned: \it to insert tasks
-- Planned: \ct to capture task to an inbox
-- Planned: \cl to capture a learning
-- Planned: \cp to capture .plan
-- Planned: \rt reschedule task to today
-- Planned: \rT reschedule task for tomorrow
-- Planned But even later: \rr reschedule task for an arbitrary date.
-- Planned: \rs reschedule task for someday
-------------------------------------------------------------------------------
-- Ideas:
-- Navigate through the weeks like in org mode?
-- Labels?
|