From 0e8990f5fa10b518beeede0a63cb33b7d2d9716e Mon Sep 17 00:00:00 2001 From: Kristijan Husak Date: Wed, 26 May 2021 22:57:12 +0200 Subject: [PATCH] Add few org mappings for changing date. --- ftplugin/org.vim | 2 + lua/orgmode/config/defaults.lua | 2 + lua/orgmode/config/mappings.lua | 2 + lua/orgmode/config/org_mappings.lua | 58 ++++++++++++++++++++++++ lua/orgmode/init.lua | 3 ++ lua/orgmode/objects/date.lua | 10 +++-- lua/orgmode/utils.lua | 4 ++ syntax/orgagenda.vim | 2 + tests/plenary/object/date_spec.lua | 70 ++++++++++++++--------------- 9 files changed, 115 insertions(+), 38 deletions(-) create mode 100644 lua/orgmode/config/org_mappings.lua diff --git a/ftplugin/org.vim b/ftplugin/org.vim index 04f5f1809..680a06442 100644 --- a/ftplugin/org.vim +++ b/ftplugin/org.vim @@ -1 +1,3 @@ lua require('orgmode.config'):setup_mappings('org') +inoreabbrev :today: <=luaeval("require('orgmode.objects.date').today():to_string()")> +inoreabbrev :now: <=luaeval("require('orgmode.objects.date').now():to_string()")> diff --git a/lua/orgmode/config/defaults.lua b/lua/orgmode/config/defaults.lua index 43b007d5e..ee8f6f41c 100644 --- a/lua/orgmode/config/defaults.lua +++ b/lua/orgmode/config/defaults.lua @@ -39,6 +39,8 @@ return { }, org = { org_capture_refile = 'or', + org_increase_date = '', + org_decrease_date = '', } } } diff --git a/lua/orgmode/config/mappings.lua b/lua/orgmode/config/mappings.lua index 0d7fc9036..f509c6180 100644 --- a/lua/orgmode/config/mappings.lua +++ b/lua/orgmode/config/mappings.lua @@ -17,6 +17,8 @@ return { }, org = { org_capture_refile = {'capture.refile_headline_to_destination'}, + org_increase_date = {'org_mappings.increase_date'}, + org_decrease_date = {'org_mappings.decrease_date'} } } -- org_agenda_goto_date = 'j', -- TODO diff --git a/lua/orgmode/config/org_mappings.lua b/lua/orgmode/config/org_mappings.lua new file mode 100644 index 000000000..360a8606a --- /dev/null +++ b/lua/orgmode/config/org_mappings.lua @@ -0,0 +1,58 @@ +---@class OrgMappings +---@field agenda Agenda +local OrgMappings = {} +local Date = require('orgmode.objects.date') +local utils = require('orgmode.utils') + +---@param data table +function OrgMappings:new(data) + local opts = {} + opts.agenda = data.agenda + setmetatable(opts, self) + self.__index = self + return opts +end + +function OrgMappings:adjust_date(adjustment, fallback) + local line = vim.fn.getline('.') + local last_col = vim.fn.col('$') + local start = vim.fn.col('.') + local finish = vim.fn.col('.') + while start > 0 do + local c = line:sub(start, start) + if c == '<' or c == '[' then + start = start + 1 + break + end + start = start - 1 + end + + while finish < last_col do + local c = line:sub(finish, finish) + if c == '>' or c == ']' then + finish = finish - 1 + break + end + finish = finish + 1 + end + + if start == 0 or finish == last_col then + return vim.api.nvim_feedkeys(utils.esc(fallback), 'n', true) + end + local selection = line:sub(start, finish) + if not Date.is_valid_date(selection) then return end + local date = Date.from_string(selection):adjust(adjustment):to_string() + local view = vim.fn.winsaveview() + vim.fn.setline(vim.fn.line('.'), string.format('%s%s%s', line:sub(1, start - 1), date, line:sub(finish + 1))) + vim.fn.winrestview(view) +end + +function OrgMappings:increase_date() + return self:adjust_date('+1d', '') +end + +function OrgMappings:decrease_date() + return self:adjust_date('-1d','') +end + +return OrgMappings diff --git a/lua/orgmode/init.lua b/lua/orgmode/init.lua index 6af12ebc5..c56298927 100644 --- a/lua/orgmode/init.lua +++ b/lua/orgmode/init.lua @@ -2,6 +2,7 @@ _G.org = _G.org or {} local Config = require('orgmode.config') local Agenda = require('orgmode.agenda') local Capture = require('orgmode.capture') +local OrgMappings = require('orgmode.config.org_mappings') local instance = nil ---@class Org @@ -22,6 +23,7 @@ function Org:init() if self.initialized then return end self.agenda = Agenda:new() self.capture = Capture:new({ agenda = self.agenda }) + self.org_mappings = OrgMappings:new({ agenda = self.agenda }) self.initialized = true end @@ -36,6 +38,7 @@ function Org:setup_autocmds() vim.cmd[[augroup orgmode_nvim]] vim.cmd[[autocmd!]] vim.cmd[[autocmd BufWritePost *.org call luaeval('require("orgmode").reload(_A)', expand(':p'))]] + vim.cmd[[autocmd FileType org call luaeval('require("orgmode").reload(_A)', expand(':p'))]] vim.cmd[[augroup END]] end diff --git a/lua/orgmode/objects/date.lua b/lua/orgmode/objects/date.lua index c57b43792..244fcd24b 100644 --- a/lua/orgmode/objects/date.lua +++ b/lua/orgmode/objects/date.lua @@ -52,10 +52,9 @@ function Date:new(data) opts.timestamp = os.time() local date = os.date('*t', opts.timestamp) opts = set_date_opts(date, opts) - opts.dayname = os.date('%a', opts.timestamp) end opts.date_only = date_only - opts.dayname = opts.dayname or data.dayname + opts.dayname = os.date('%a', opts.timestamp) opts.adjustments = data.adjustments or {} setmetatable(opts, self) self.__index = self @@ -137,11 +136,15 @@ local function parse_date(date, dayname, adjustments, data) return Date:new(opts) end +local function is_valid_date(datestr) + return datestr:match('^%d%d%d%d%-%d%d%-%d%d%s+') or datestr:match('^%d%d%d%d%-%d%d%-%d%d$') +end + ---@param datestr string ---@param opts table ---@return Date local function from_string(datestr, opts) - if not datestr:match('^%d%d%d%d%-%d%d%-%d%d$') and not datestr:match('^%d%d%d%d%-%d%d%-%d%d%s+') then + if not is_valid_date(datestr) then return Date:new(opts) end local parts = vim.split(datestr, '%s+') @@ -607,6 +610,7 @@ return { now = now, today = today, parse_all_from_line = parse_all_from_line, + is_valid_date = is_valid_date, from_match = from_match, pattern = pattern } diff --git a/lua/orgmode/utils.lua b/lua/orgmode/utils.lua index 44e42ca75..196fe274f 100644 --- a/lua/orgmode/utils.lua +++ b/lua/orgmode/utils.lua @@ -164,4 +164,8 @@ function utils.buf_keymap(buf, mode, lhs, rhs, opts) })) end +function utils.esc(cmd) + return vim.api.nvim_replace_termcodes(cmd, true, false, true) +end + return utils diff --git a/syntax/orgagenda.vim b/syntax/orgagenda.vim index 5ba85f05d..ede972331 100644 --- a/syntax/orgagenda.vim +++ b/syntax/orgagenda.vim @@ -1,4 +1,6 @@ lua require('orgmode.agenda.highlights').define_agenda_colors() syn match OrgAgendaDay /^\w\+\s\d\+\s\w\+\s\d\d\d\d$/ +syn match OrgAgendaTags /:[^\s]*:$/ hi OrgBold gui=bold hi default link OrgAgendaDay Statement +hi default link OrgAgendaTags OrgBold diff --git a/tests/plenary/object/date_spec.lua b/tests/plenary/object/date_spec.lua index 41af0f7ed..e2777404f 100644 --- a/tests/plenary/object/date_spec.lua +++ b/tests/plenary/object/date_spec.lua @@ -9,10 +9,10 @@ describe('Date object', function() assert.are.same(10, result.day) assert.are.same(0, result.hour) assert.are.same(0, result.min) - assert.is.Nil(result.dayname) + assert.are.same('Thu', result.dayname) assert.are.same(true, result.date_only) assert.are.same(1623276000, result.timestamp) - assert.are.same(date, result:to_string()) + assert.are.same('2021-06-10 Thu', result:to_string()) assert.are.same({}, result.adjustments) local date_with_dayname = '2021-06-10 Thu' @@ -39,7 +39,7 @@ describe('Date object', function() assert.are.same(0, result.min) assert.are.same(false, result.date_only) assert.are.same(1625468400, result.timestamp) - assert.are.same(date, result:to_string()) + assert.are.same('2021-07-05 Mon 09:00', result:to_string()) assert.are.same({}, result.adjustments) local date_with_dayname = '2021-07-05 Mon 09:00' @@ -133,10 +133,10 @@ describe('Date object', function() assert.are.same(10, result.day) assert.are.same(0, result.hour) assert.are.same(0, result.min) - assert.is.Nil(result.dayname) + assert.are.same('Thu', result.dayname) assert.are.same(true, result.date_only) assert.are.same(1623276000, result.timestamp) - assert.are.same(date, result:to_string()) + assert.are.same('2021-06-10 Thu', result:to_string()) assert.are.same({}, result.adjustments) result = result:adjust('+1d') @@ -145,10 +145,10 @@ describe('Date object', function() assert.are.same(11, result.day) assert.are.same(0, result.hour) assert.are.same(0, result.min) - assert.is.Nil(result.dayname) + assert.are.same('Fri', result.dayname) assert.are.same(true, result.date_only) assert.are.same(1623362400, result.timestamp) - assert.are.same('2021-06-11', result:to_string()) + assert.are.same('2021-06-11 Fri', result:to_string()) assert.are.same({}, result.adjustments) result = result:adjust('+3m') @@ -157,10 +157,10 @@ describe('Date object', function() assert.are.same(11, result.day) assert.are.same(0, result.hour) assert.are.same(0, result.min) - assert.is.Nil(result.dayname) + assert.are.same('Sat', result.dayname) assert.are.same(true, result.date_only) assert.are.same(1631311200, result.timestamp) - assert.are.same('2021-09-11', result:to_string()) + assert.are.same('2021-09-11 Sat', result:to_string()) assert.are.same({}, result.adjustments) result = result:adjust('-1w') @@ -169,10 +169,10 @@ describe('Date object', function() assert.are.same(4, result.day) assert.are.same(0, result.hour) assert.are.same(0, result.min) - assert.is.Nil(result.dayname) + assert.are.same('Sat', result.dayname) assert.are.same(true, result.date_only) assert.are.same(1630706400, result.timestamp) - assert.are.same('2021-09-04', result:to_string()) + assert.are.same('2021-09-04 Sat', result:to_string()) assert.are.same({}, result.adjustments) result = result:adjust('+2y') @@ -181,10 +181,10 @@ describe('Date object', function() assert.are.same(4, result.day) assert.are.same(0, result.hour) assert.are.same(0, result.min) - assert.is.Nil(result.dayname) + assert.are.same('Mon', result.dayname) assert.are.same(true, result.date_only) assert.are.same(1693778400, result.timestamp) - assert.are.same('2023-09-04', result:to_string()) + assert.are.same('2023-09-04 Mon', result:to_string()) assert.are.same({}, result.adjustments) result = result:adjust('+2') @@ -193,10 +193,10 @@ describe('Date object', function() assert.are.same(6, result.day) assert.are.same(0, result.hour) assert.are.same(0, result.min) - assert.is.Nil(result.dayname) + assert.are.same('Wed', result.dayname) assert.are.same(true, result.date_only) assert.are.same(1693951200, result.timestamp) - assert.are.same('2023-09-06', result:to_string()) + assert.are.same('2023-09-06 Wed', result:to_string()) assert.are.same({}, result.adjustments) end) @@ -272,49 +272,49 @@ describe('Date object', function() it('should get start of specific range', function() local date = Date.from_string('2021-05-12 10:30') date = date:start_of('day') - assert.are.same('2021-05-12 00:00', date:to_string()) + assert.are.same('2021-05-12 Wed 00:00', date:to_string()) date = date:start_of('week') - assert.are.same('2021-05-10 00:00', date:to_string()) + assert.are.same('2021-05-10 Mon 00:00', date:to_string()) date = date:start_of('month') - assert.are.same('2021-05-01 00:00', date:to_string()) + assert.are.same('2021-05-01 Sat 00:00', date:to_string()) date = date:start_of('year') - assert.are.same('2021-01-01 00:00', date:to_string()) + assert.are.same('2021-01-01 Fri 00:00', date:to_string()) date = Date.from_string('2021-05-12 10:30') date = date:start_of('month') - assert.are.same('2021-05-01 00:00', date:to_string()) + assert.are.same('2021-05-01 Sat 00:00', date:to_string()) end) it('should get end of specific range', function() local date = Date.from_string('2021-05-12 09:00') date = date:end_of('day') - assert.are.same('2021-05-12 23:59', date:to_string()) + assert.are.same('2021-05-12 Wed 23:59', date:to_string()) date = date:end_of('week') - assert.are.same('2021-05-16 23:59', date:to_string()) + assert.are.same('2021-05-16 Sun 23:59', date:to_string()) date = date:end_of('month') - assert.are.same('2021-05-31 23:59', date:to_string()) + assert.are.same('2021-05-31 Mon 23:59', date:to_string()) date = date:end_of('year') - assert.are.same('2021-12-31 23:59', date:to_string()) + assert.are.same('2021-12-31 Fri 23:59', date:to_string()) date = Date.from_string('2021-05-12 09:00') date = date:end_of('month') - assert.are.same('2021-05-31 23:59', date:to_string()) + assert.are.same('2021-05-31 Mon 23:59', date:to_string()) end) it('should add/subtract/set date', function() local date = Date.from_string('2021-05-12 14:00') date = date:add({ week = 2 }) - assert.are.same('2021-05-26 14:00', date:to_string()) + assert.are.same('2021-05-26 Wed 14:00', date:to_string()) date = date:add({ month = 2 }) - assert.are.same('2021-07-26 14:00', date:to_string()) + assert.are.same('2021-07-26 Mon 14:00', date:to_string()) date = date:add({ year = 1 }) - assert.are.same('2022-07-26 14:00', date:to_string()) + assert.are.same('2022-07-26 Tue 14:00', date:to_string()) date = date:subtract({ hour = 1 }) - assert.are.same('2022-07-26 13:00', date:to_string()) + assert.are.same('2022-07-26 Tue 13:00', date:to_string()) date = date:subtract({ min = 30 }) - assert.are.same('2022-07-26 12:30', date:to_string()) + assert.are.same('2022-07-26 Tue 12:30', date:to_string()) date = date:subtract({ month = 4 }) - assert.are.same('2022-03-26 12:30', date:to_string()) + assert.are.same('2022-03-26 Sat 12:30', date:to_string()) date = date:subtract({ year = 2 }) - assert.are.same('2020-03-26 12:30', date:to_string()) + assert.are.same('2020-03-26 Thu 12:30', date:to_string()) end) it('should compare dates', function() @@ -503,13 +503,13 @@ describe('Date object', function() monday = monday:set_isoweekday(1) assert.are.same(1, monday:get_isoweekday()) - assert.are.same('2021-05-17', monday:to_string()) + assert.are.same('2021-05-17 Mon', monday:to_string()) local thursday = monday:set_isoweekday(4, true) assert.are.same(4, thursday:get_isoweekday()) - assert.are.same('2021-05-20', thursday:to_string()) + assert.are.same('2021-05-20 Thu', thursday:to_string()) local previous_saturday = monday:set_isoweekday(6) assert.are.same(6, previous_saturday:get_isoweekday()) - assert.are.same('2021-05-15', previous_saturday:to_string()) + assert.are.same('2021-05-15 Sat', previous_saturday:to_string()) end) it('should handle repeater', function()