]>
Commit | Line | Data |
---|---|---|
7d35a7fc RBR |
1 | local brain_home = os.getenv('HOME') .. '/brain' |
2 | local templates_path = brain_home .. '/1 periodic/99 templates' | |
3 | ||
fc82060a RBR |
4 | ------------------------------------------------------------------------------- |
5 | -- Private functions for Periodic Tasks | |
6 | ------------------------------------------------------------------------------- | |
7 | ||
7d35a7fc | 8 | local function load_template(template_name) |
fc82060a RBR |
9 | local template_path = templates_path .. '/' .. template_name |
10 | ||
11 | print(template_path) | |
7d35a7fc | 12 | |
66b09f6c | 13 | local template_file = io.open(template_path, 'r') |
7d35a7fc | 14 | if not template_file then |
66b09f6c | 15 | print('Template file not found') |
7d35a7fc RBR |
16 | return |
17 | end | |
66b09f6c | 18 | local content = template_file:read('*a') |
7d35a7fc | 19 | template_file:close() |
fc82060a | 20 | return content |
7d35a7fc RBR |
21 | end |
22 | ||
23 | local function open_or_create_from_template(template_name, file) | |
66b09f6c | 24 | local journal_file = io.open(file, 'r') |
7d35a7fc RBR |
25 | if not journal_file then |
26 | local template_contents = load_template(template_name) | |
27 | ||
66b09f6c | 28 | journal_file = io.open(file, 'w') |
7d35a7fc RBR |
29 | journal_file:write(template_contents) |
30 | journal_file:close() | |
31 | end | |
66b09f6c | 32 | vim.cmd('edit ' .. file) |
7d35a7fc RBR |
33 | end |
34 | ||
fc82060a RBR |
35 | local function find_tasks(completed) |
36 | local journal_path = brain_home .. '/1 periodic/01 journal/' | |
37 | ||
38 | local pattern = '^\\s*\\- \\[ \\]' | |
39 | if completed == 1 then | |
40 | pattern = '^\\s*\\- \\[x\\]' | |
41 | end | |
42 | ||
43 | local command = string.format('rg --vimgrep \'%s\' \'%s\'', pattern, journal_path) | |
44 | local results = vim.fn.systemlist(command) | |
45 | ||
46 | if vim.v.shell_error == 0 then | |
47 | local items = {} | |
48 | for _, line in ipairs(results) do | |
49 | local filename, lnum, col, text = line:match("([^:]+):(%d+):(%d+):(.*)") | |
50 | table.insert(items, { | |
51 | filename = filename, | |
52 | lnum = tonumber(lnum), | |
53 | col = tonumber(col), | |
54 | text = text, | |
55 | }) | |
56 | end | |
57 | ||
58 | -- Set location list for the current window and open it | |
59 | vim.fn.setloclist(0, items) | |
60 | vim.cmd('lopen') | |
61 | end | |
62 | end | |
63 | ||
66b09f6c RBR |
64 | local function get_this_weeks_files() |
65 | local today = os.time() | |
66 | local day_of_week = os.date('*t', today).wday | |
67 | local week_start = today - (day_of_week - 2) * 86400 | |
68 | local filenames = {} | |
69 | ||
70 | for i = 0, 6 do | |
71 | local date = os.date('*t', week_start + i * 86400) | |
72 | table.insert(filenames, string.format('%04d-%02d-%02d.md', date.year, date.month, date.day)) | |
73 | end | |
74 | ||
75 | return filenames | |
76 | end | |
77 | ||
fc82060a RBR |
78 | local function populate_quicklist_with_files(filenames) |
79 | local uv = vim.loop | |
80 | local items = {} | |
81 | local pattern = '^%s*%- %[[ ]?x?%]' | |
82 | ||
83 | for _, filename in ipairs(filenames) do | |
84 | local daily_note = brain_home .. '/1 periodic/01 journal/' .. filename | |
85 | local stat = uv.fs_stat(daily_note) | |
86 | ||
87 | if stat then -- File exists | |
88 | local file, err = io.open(daily_note, 'r') | |
89 | if file then | |
90 | local set_header = 0 | |
91 | local line_number = 0 | |
92 | for line in file:lines() do | |
93 | line_number = line_number + 1 | |
94 | if line:match(pattern) then | |
95 | if set_header == 0 then | |
96 | local header = string.sub(filename:match('([^/\\]+)$'), 1, -4) | |
97 | table.insert(items, {filename = '', lnum = 0, text = header}) | |
98 | set_header = 1 | |
99 | end | |
100 | table.insert(items, {filename = daily_note, text = line, lnum = line_number}) | |
101 | end | |
102 | end | |
103 | file:close() | |
104 | end | |
105 | end | |
106 | end | |
107 | vim.fn.setloclist(0, {}, ' ', {title = 'Weekly Tasks', items = items}) | |
108 | vim.cmd('lopen') | |
109 | end | |
110 | ||
66b09f6c RBR |
111 | ------------------------------------------------------------------------------- |
112 | -- Periodic Notes | |
113 | ------------------------------------------------------------------------------- | |
114 | ||
7d35a7fc RBR |
115 | function open_daily_note() |
116 | local filename_format = os.date('%Y-%m-%d') | |
117 | local template_name = '001 daily.md' | |
118 | ||
66b09f6c | 119 | local daily_note = brain_home .. '/1 periodic/01 journal/' .. filename_format .. '.md' |
7d35a7fc RBR |
120 | open_or_create_from_template(template_name, daily_note) |
121 | end | |
122 | ||
123 | function open_weekly_note() | |
124 | local filename_format = os.date('%Y-w%V') | |
125 | local template_name = '002 weekly.md' | |
126 | ||
66b09f6c | 127 | local weekly_note = brain_home .. '/1 periodic/02 weeks/' .. filename_format .. '.md' |
7d35a7fc RBR |
128 | open_or_create_from_template(template_name, weekly_note) |
129 | end | |
130 | ||
66b09f6c RBR |
131 | ------------------------------------------------------------------------------- |
132 | -- Task Utilities | |
133 | ------------------------------------------------------------------------------- | |
134 | ||
7d35a7fc RBR |
135 | function toggle_task() |
136 | local line_num = vim.api.nvim_win_get_cursor(0)[1] | |
137 | local line = vim.api.nvim_get_current_line() | |
138 | ||
139 | local unchecked_pattern = '^%s*%- %[ %]' | |
140 | local checked_pattern = '^%s*%- %[x%]' | |
141 | ||
142 | if line:match(unchecked_pattern) then | |
143 | line = line:gsub(unchecked_pattern, '- [x]', 1) | |
144 | elseif line:match(checked_pattern) then | |
145 | line = line:gsub(checked_pattern, '- [ ]', 1) | |
146 | end | |
147 | ||
148 | vim.api.nvim_buf_set_lines(0, line_num - 1, line_num, false, {line}) | |
149 | end | |
150 | ||
66b09f6c | 151 | ------------------------------------------------------------------------------- |
fc82060a | 152 | -- Task Quicklist Views |
66b09f6c RBR |
153 | ------------------------------------------------------------------------------- |
154 | ||
155 | function open_agenda() | |
66b09f6c | 156 | local week_filenames = get_this_weeks_files() |
fc82060a RBR |
157 | populate_quicklist_with_files(week_filenames) |
158 | end | |
66b09f6c | 159 | |
fc82060a RBR |
160 | function open_open() |
161 | find_tasks(0) | |
66b09f6c RBR |
162 | end |
163 | ||
164 | ------------------------------------------------------------------------------- | |
165 | -- Key Bindings | |
166 | ------------------------------------------------------------------------------- | |
fc82060a | 167 | -- Periodic Notes |
7d35a7fc RBR |
168 | vim.api.nvim_set_keymap('n', '<leader>od', '<cmd>lua open_daily_note()<CR>', { noremap = true, silent = true }) |
169 | vim.api.nvim_set_keymap('n', '<leader>ow', '<cmd>lua open_weekly_note()<CR>', { noremap = true, silent = true }) | |
fc82060a RBR |
170 | -- Planned: \om to open monthly, \os to open seasonly, and \oy to open yearly |
171 | -- Agenda Views | |
66b09f6c | 172 | vim.api.nvim_set_keymap('n', '<leader>oa', '<cmd>lua open_agenda()<CR>', { noremap = true, silent = true }) |
fc82060a RBR |
173 | vim.api.nvim_set_keymap('n', '<leader>oo', '<cmd>lua open_open()<CR>', { noremap = true, silent = true }) |
174 | -- Planned: \oj to open journal | |
175 | -- Task Helpers | |
7d35a7fc | 176 | vim.api.nvim_set_keymap('n', '<leader>t', '<cmd>lua toggle_task()<CR>', { noremap = true, silent = true }) |
fc82060a RBR |
177 | -- Planned: \it to insert tasks |
178 | -- Planned: \ct to capture task to an inbox | |
179 | -- Planned: \cl to capture a learning | |
180 | -- Planned: \cp to capture .plan | |
181 | -- Planned: \rt reschedule task to today | |
182 | -- Planned: \rT reschedule task for tomorrow | |
183 | -- Planned But even later: \rr reschedule task for an arbitrary date. | |
184 | -- Planned: \rs reschedule task for someday | |
185 | ------------------------------------------------------------------------------- | |
186 | -- Ideas: | |
187 | -- Navigate through the weeks like in org mode? | |
188 | -- Labels? |