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', 'od', 'lua open_daily_note()', { noremap = true, silent = true }) vim.api.nvim_set_keymap('n', 'ow', 'lua open_weekly_note()', { 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', 'oa', 'lua open_agenda()', { noremap = true, silent = true }) vim.api.nvim_set_keymap('n', 'oo', 'lua open_open()', { noremap = true, silent = true }) -- Planned: \oj to open journal -- Task Helpers vim.api.nvim_set_keymap('n', 't', 'lua toggle_task()', { 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?