From: Ruben Beltran del Rio Date: Wed, 6 Mar 2024 13:51:14 +0000 (+0100) Subject: Allow next and previous X-Git-Url: https://git.r.bdr.sh/rbdr/nota.nvim/commitdiff_plain/ca10d2a36e3e7d8d28f15f36f0812384606c238d Allow next and previous --- diff --git a/README.md b/README.md index 852032e..87238ad 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ require('lazy').setup({ - `os`, `:NotaOpenSeasonalNote`, Opens this season's seasonal note. - `oy`, `:NotaOpenYearlyNote`, Opens this year's yearly note. - `on`, `:NotaOpenNote`, Opens an arbitrary note. (Requires [fzf-lua][fzf-lua]) +- `N`, `:NotaOpenNextNote`, Opens the next periodic note. (eg. tomorrow or next year) +- `P`, `:NotaOpenPreviousNote`, Opens the previous periodic note. (eg. yesterday or last week) ### Task Views - `oa`, `:NotaOpenAgenda`, Opens the agenda window with this week's tasks. diff --git a/lua/keybinds.lua b/lua/keybinds.lua index 1b661ac..88324f0 100644 --- a/lua/keybinds.lua +++ b/lua/keybinds.lua @@ -17,6 +17,8 @@ function Keybinds.bind() api.nvim_set_keymap('n', 'os', 'NotaOpenSeasonalNote', { noremap = true, silent = true }) api.nvim_set_keymap('n', 'oy', 'NotaOpenYearlyNote', { noremap = true, silent = true }) api.nvim_set_keymap('n', 'on', 'NotaOpenNote', { noremap = true, silent = true }) + api.nvim_set_keymap('n', 'N', 'NotaOpenNextNote', { noremap = true, silent = true }) + api.nvim_set_keymap('n', 'P', 'NotaOpenPreviousNote', { noremap = true, silent = true }) api.nvim_set_keymap('n', 'oa', 'NotaOpenAgenda', { noremap = true, silent = true }) api.nvim_set_keymap('n', 'oo', 'NotaOpenOpen', { noremap = true, silent = true }) diff --git a/lua/notes.lua b/lua/notes.lua index b23d6df..ca61735 100644 --- a/lua/notes.lua +++ b/lua/notes.lua @@ -9,6 +9,21 @@ local api = vim.api ------------------------------------------------------------------------------- -- Internal Functions ------------------------------------------------------------------------------- +local templates = { + daily = '%Y-%m-%d', + weekly = '%Y-w%V', + monthly = '%Y-%m', + yearly = '%Y' +} + +local patterns = { + daily = '^(%d+)-(%d+)-(%d+).md$', + weekly = '^(%d+)-w(%d+).md$', + monthly = '^(%d+)-(%d+).md$', + seasonal = '^(%d+)-s(%d+).md$', + yearly = '^(%d+).md$' +} + local function open_or_create_from_template(type, file_path) local journal_file = io.open(file_path, 'r') @@ -31,6 +46,72 @@ local function open_periodic_note(type, filename) open_or_create_from_template(type, file_path) end +local function find_next(type, filename, go_back_in_time) + local multiplier = 1 + if go_back_in_time then + multiplier = -1 + end + + local pattern = patterns[type] + local year, second_match, day = filename:match(pattern) + year = tonumber(year) + + -- Depending on context, second_match is either month, week, or season. + if second_match then + second_match = tonumber(second_match) + end + + if day then + day = tonumber(day) + end + + local next = nil + + if type == 'daily' and year and second_match and day then + next = os.date(templates.daily, os.time({ + year = year, + month = second_match, + day = day + }) + multiplier * 24 * 60 * 60) + elseif type == 'weekly' and year and second_match then + -- According to ISO, the first week is the one that contains january 4 + local first_day_of_the_week = os.time({year = year, month = 1, day = 4}) + if multiplier < 0 then + second_match = second_match - 2 + end + next = os.date(templates.weekly, first_day_of_the_week + second_match * 7 * 24 * 60 * 60) + elseif type == 'monthly' and year and second_match then + next = os.date(templates.monthly, os.time({ + year = year, + month = second_match + multiplier, + day = 1 + })) + elseif type == 'seasonal' and year and second_match then + if multiplier > 0 and second_match == 4 then + year = year + 1 + end + if multiplier < 0 and second_match == 1 then + year = year - 1 + end + if multiplier > 0 then + second_match = (second_match % 4) + 1 + else + second_match = (second_match + 2) % 4 + 1 + end + next = year .. '-s' .. second_match + elseif type == 'yearly' and year then + next = os.date(templates.yearly, os.time({ + year = year + multiplier, + month = 1, + day = 1 + })) + end + + if next then + Notes['open_' .. type](next) + end +end + ------------------------------------------------------------------------------- -- Public Interface ------------------------------------------------------------------------------- @@ -38,40 +119,74 @@ end --- Opens the daily note function Notes.open_daily(date) if not date or date == '' then - date = os.date('%Y-%m-%d') + date = os.date(templates.daily) end local filename = date .. '.md' open_periodic_note('daily', filename) end --- Opens the weekly note -function Notes.open_weekly() - local filename = os.date('%Y-w%V') +function Notes.open_weekly(date) + if not date or date == '' then + date = os.date(templates.weekly) + end + local filename = date .. '.md' open_periodic_note('weekly', filename) end --- Opens the monthly note -function Notes.open_monthly() - local filename = os.date('%Y-%m') .. '.md' +function Notes.open_monthly(date) + if not date or date == '' then + date = os.date(templates.monthly) + end + local filename = date .. '.md' open_periodic_note('monthly', filename) end --- Opens the seasonal note -function Notes.open_seasonal() - local year = os.date('%Y') - local month = tonumber(os.date('%m')) - local season = math.ceil(month / 3) +function Notes.open_seasonal(date) + if not date or date == '' then + local year = os.date('%Y') + local month = tonumber(os.date('%m')) + local season = math.ceil(month / 3) + date = year .. '-s' .. season + end - local filename = year .. '-s' .. season .. '.md' + local filename = date .. '.md' open_periodic_note('seasonal', filename) end --- Opens the yearly note -function Notes.open_yearly() - local filename = os.date('%Y') .. '.md' +function Notes.open_yearly(date) + if not date or date == '' then + date = os.date(templates.yearly) + end + local filename = date .. '.md' open_periodic_note('yearly', filename) end +--- Opens the next note +function Notes.open_next() + local filename = vim.fn.expand('%:t') + for type, pattern in pairs(patterns) do + if filename:match(pattern) ~= nil then + return find_next(type, filename) + end + end + api.nvim_err_writeln('Opening next only works on periodic notes.') +end + +--- Opens the previous note +function Notes.open_previous() + local filename = vim.fn.expand('%:t') + for type, pattern in pairs(patterns) do + if filename:match(pattern) ~= nil then + return find_next(type, filename, true) + end + end + api.nvim_err_writeln('Opening previous only works on periodic notes.') +end + --- Opens an arbitrary note function Notes.open() local success, module = pcall(require, 'fzf-lua') diff --git a/plugin/nota.lua b/plugin/nota.lua index 9e09d61..180c84d 100644 --- a/plugin/nota.lua +++ b/plugin/nota.lua @@ -59,6 +59,8 @@ command('NotaOpenMonthlyNote', function() require('notes').open_monthly() end, { command('NotaOpenSeasonalNote', function() require('notes').open_seasonal() end, { nargs = 0 }) command('NotaOpenYearlyNote', function() require('notes').open_yearly() end, { nargs = 0 }) command('NotaOpenNote', function() require('notes').open() end, { nargs = 0 }) +command('NotaOpenNextNote', function() require('notes').open_next() end, { nargs = 0 }) +command('NotaOpenPreviousNote', function() require('notes').open_previous() end, { nargs = 0 }) -- Task View Handling Commands command('NotaOpenAgenda', function() require('task_views').open_agenda() end, { nargs = 0 })