diff --git a/lua/orgmode/api/headline.lua b/lua/orgmode/api/headline.lua index 9d01952ca..716899591 100644 --- a/lua/orgmode/api/headline.lua +++ b/lua/orgmode/api/headline.lua @@ -113,7 +113,8 @@ function OrgHeadline:priority_up() local headline = org.files:get_closest_headline() local current_priority = headline:get_priority() local prio_range = config:get_priority_range() - local priority_state = PriorityState:new(current_priority, prio_range) + local start_with_default = config.org_priority_start_cycle_with_default + local priority_state = PriorityState:new(current_priority, prio_range, start_with_default) return headline:set_priority(priority_state:increase()) end) end @@ -125,7 +126,8 @@ function OrgHeadline:priority_down() local headline = org.files:get_closest_headline() local current_priority = headline:get_priority() local prio_range = config:get_priority_range() - local priority_state = PriorityState:new(current_priority, prio_range) + local start_with_default = config.org_priority_start_cycle_with_default + local priority_state = PriorityState:new(current_priority, prio_range, start_with_default) return headline:set_priority(priority_state:decrease()) end) end diff --git a/lua/orgmode/capture/init.lua b/lua/orgmode/capture/init.lua index 24c1335ba..f968fb1cd 100644 --- a/lua/orgmode/capture/init.lua +++ b/lua/orgmode/capture/init.lua @@ -408,19 +408,17 @@ end ---@param arg_lead string ---@return string[] function Capture:autocomplete_refile(arg_lead) - local valid_filenames = self:_get_autocompletion_files(true) + local valid_files = self:_get_autocompletion_files(true) - if not arg_lead then - return vim.tbl_keys(valid_filenames) + if not arg_lead or #arg_lead == 0 then + return vim.tbl_keys(valid_files) end - local parts = vim.split(arg_lead, '/', { plain = true }) - local selected_file = valid_filenames[parts[1] .. '/'] + local filename = vim.split(arg_lead, '/', { plain = true })[1] + local selected_file = valid_files[filename .. '/'] if not selected_file then - return vim.tbl_filter(function(file) - return file:match('^' .. vim.pesc(parts[1])) - end, vim.tbl_keys(valid_filenames)) + return vim.fn.matchfuzzy(vim.tbl_keys(valid_files), filename) end local headlines = selected_file:get_opened_unfinished_headlines() diff --git a/lua/orgmode/config/defaults.lua b/lua/orgmode/config/defaults.lua index d877bcfcc..f2c18d9a4 100644 --- a/lua/orgmode/config/defaults.lua +++ b/lua/orgmode/config/defaults.lua @@ -32,6 +32,7 @@ local DefaultConfig = { org_priority_highest = 'A', org_priority_default = 'B', org_priority_lowest = 'C', + org_priority_start_cycle_with_default = true, org_archive_location = '%s_archive::', org_tags_column = -80, org_use_tag_inheritance = true, diff --git a/lua/orgmode/config/init.lua b/lua/orgmode/config/init.lua index bd10a8d95..ab18a5630 100644 --- a/lua/orgmode/config/init.lua +++ b/lua/orgmode/config/init.lua @@ -345,7 +345,11 @@ function Config:get_priorities() [self.opts.org_priority_highest] = { type = 'highest', hl_group = '@org.priority.highest' }, } - local current_prio = PriorityState:new(self.opts.org_priority_highest, self:get_priority_range()) + local current_prio = PriorityState:new( + self.opts.org_priority_highest, + self:get_priority_range(), + self.org_priority_start_cycle_with_default + ) while current_prio:as_num() < current_prio:default_as_num() do current_prio:decrease() priorities[current_prio.priority] = { type = 'high', hl_group = '@org.priority.high' } diff --git a/lua/orgmode/files/init.lua b/lua/orgmode/files/init.lua index 4686ff229..e3c8da330 100644 --- a/lua/orgmode/files/init.lua +++ b/lua/orgmode/files/init.lua @@ -206,7 +206,15 @@ function OrgFiles:get_closest_headline(cursor) end function OrgFiles:get_closest_listitem() - local node = ts_utils.closest_node(ts_utils.get_node_at_cursor(), 'listitem') + local get_listitem_node = function() + local node_at_cursor = ts_utils.get_node_at_cursor() + if node_at_cursor and node_at_cursor:type() == 'list' then + return node_at_cursor:named_child(0) + end + return ts_utils.closest_node(node_at_cursor, 'listitem') + end + + local node = get_listitem_node() if node then return Listitem:new(node, self:get_current_file()) end diff --git a/lua/orgmode/objects/priority_state.lua b/lua/orgmode/objects/priority_state.lua index ca21fa5cc..ef60d452a 100644 --- a/lua/orgmode/objects/priority_state.lua +++ b/lua/orgmode/objects/priority_state.lua @@ -4,18 +4,20 @@ local utils = require('orgmode.utils') ---@field high_priority string ---@field low_priority string ---@field priority string +---@field start_with_default boolean ---@field default_priority string local PriorityState = {} ---@param priority string ---@param prio_range { highest: string, lowest: string, default: string } -function PriorityState:new(priority, prio_range) +function PriorityState:new(priority, prio_range, start_with_default) local o = {} o.high_priority = tostring(prio_range.highest) o.low_priority = tostring(prio_range.lowest) o.default_priority = tostring(prio_range.default) o.priority = tostring(priority or o.default_priority) + o.start_with_default = start_with_default setmetatable(o, self) self.__index = self @@ -54,9 +56,12 @@ end ---@return string function PriorityState:increase() - if self.priority == self.high_priority then - self.priority = '' - elseif self.priority == '' then + if self.priority == '' then + self.priority = self.default_priority + if not self.start_with_default then + self.priority = self:_apply(-1) + end + elseif self.priority == self.high_priority then self.priority = self.low_priority else self.priority = self:_apply(-1) @@ -67,9 +72,12 @@ end ---@return string function PriorityState:decrease() - if self.priority == self.low_priority then - self.priority = '' - elseif self.priority == '' then + if self.priority == '' then + self.priority = self.default_priority + if not self.start_with_default then + self.priority = self:_apply(1) + end + elseif self.priority == self.low_priority then self.priority = self.high_priority else self.priority = self:_apply(1) diff --git a/lua/orgmode/org/mappings.lua b/lua/orgmode/org/mappings.lua index f1f03d72c..52fc770f5 100644 --- a/lua/orgmode/org/mappings.lua +++ b/lua/orgmode/org/mappings.lua @@ -323,7 +323,7 @@ function OrgMappings:set_priority(direction) local headline = self.files:get_closest_headline() local current_priority = headline:get_priority() local prio_range = config:get_priority_range() - local priority_state = PriorityState:new(current_priority, prio_range) + local priority_state = PriorityState:new(current_priority, prio_range, config.org_priority_start_cycle_with_default) local new_priority = direction if direction == 'up' then diff --git a/tests/plenary/api/api_spec.lua b/tests/plenary/api/api_spec.lua index 7745376c2..38667c57d 100644 --- a/tests/plenary/api/api_spec.lua +++ b/tests/plenary/api/api_spec.lua @@ -3,6 +3,7 @@ local api = require('orgmode.api') local Date = require('orgmode.objects.date') local OrgId = require('orgmode.org.id') local orgmode = require('orgmode') +local config = require('orgmode.config') describe('Api', function() ---@return OrgApiFile @@ -109,7 +110,7 @@ describe('Api', function() assert.is.True(vim.fn.getline(5):match(':PERSONAL:HEALTH:$') ~= nil) end) - it('should toggle priority up and down', function() + it('should cycle upwards through priorities, starting with default', function() helpers.create_file({ '#TITLE: First file', '', @@ -125,9 +126,9 @@ describe('Api', function() local current_file = cur_file() local headline = current_file.headlines[2] assert.are.same('', headline.priority) - headline:priority_up():wait() - assert.are.same('C', cur_file().headlines[2].priority) - assert.is.True(vim.fn.getline(5):match('%[#C%]') ~= nil) + assert.are.same(true, config.org_priority_start_cycle_with_default) + assert.are.same('B', config.org_priority_default) + headline:priority_up():wait() assert.are.same('B', cur_file().headlines[2].priority) assert.is.True(vim.fn.getline(5):match('%[#B%]') ~= nil) @@ -135,14 +136,113 @@ describe('Api', function() assert.are.same('A', cur_file().headlines[2].priority) assert.is.True(vim.fn.getline(5):match('%[#A%]') ~= nil) headline:priority_up():wait() - assert.are.same('', cur_file().headlines[2].priority) - assert.is.True(vim.fn.getline(5):match('%[.*%]') == nil) + assert.are.same('C', cur_file().headlines[2].priority) + assert.is.True(vim.fn.getline(5):match('%[#C%]') ~= nil) + headline:priority_up():wait() + assert.are.same('B', cur_file().headlines[2].priority) + assert.is.True(vim.fn.getline(5):match('%[#B%]') ~= nil) + end) + + it('should cycle downwards through priorities, starting with default', function() + helpers.create_file({ + '#TITLE: First file', + '', + '* TODO Test orgmode :WORK:OFFICE:', + ' DEADLINE: <2021-07-21 Wed 22:02>', + '** TODO Second level :NESTEDTAG:', + ' DEADLINE: <2021-07-21 Wed 22:02>', + '* DONE Some task', + ' DEADLINE: <2021-07-21 Wed 22:02>', + }) + + assert.is.True(#api.load() > 1) + local current_file = cur_file() + local headline = current_file.headlines[2] + assert.are.same('', headline.priority) + assert.are.same(true, config.org_priority_start_cycle_with_default) + assert.are.same('B', config.org_priority_default) + + headline:priority_down():wait() + assert.are.same('B', cur_file().headlines[2].priority) + assert.is.True(vim.fn.getline(5):match('%[#B%]') ~= nil) + headline:priority_down():wait() + assert.are.same('C', cur_file().headlines[2].priority) + assert.is.True(vim.fn.getline(5):match('%[#C%]') ~= nil) headline:priority_down():wait() assert.are.same('A', cur_file().headlines[2].priority) assert.is.True(vim.fn.getline(5):match('%[#A%]') ~= nil) headline:priority_down():wait() assert.are.same('B', cur_file().headlines[2].priority) assert.is.True(vim.fn.getline(5):match('%[#B%]') ~= nil) + end) + + it('should enable priority at default + 1', function() + helpers.create_file({ + '#TITLE: First file', + '', + '* TODO Test orgmode :WORK:OFFICE:', + ' DEADLINE: <2021-07-21 Wed 22:02>', + '** TODO Second level :NESTEDTAG:', + ' DEADLINE: <2021-07-21 Wed 22:02>', + '* DONE Some task', + ' DEADLINE: <2021-07-21 Wed 22:02>', + }) + + assert.is.True(#api.load() > 1) + local current_file = cur_file() + local headline = current_file.headlines[2] + assert.are.same('', headline.priority) + assert.are.same('B', config.org_priority_default) + config.org_priority_start_cycle_with_default = false + + headline:priority_up():wait() + assert.are.same('A', cur_file().headlines[2].priority) + assert.is.True(vim.fn.getline(5):match('%[#A%]') ~= nil) + end) + + it('should enable priority at default + 1', function() + helpers.create_file({ + '#TITLE: First file', + '', + '* TODO Test orgmode :WORK:OFFICE:', + ' DEADLINE: <2021-07-21 Wed 22:02>', + '** TODO Second level :NESTEDTAG:', + ' DEADLINE: <2021-07-21 Wed 22:02>', + '* DONE Some task', + ' DEADLINE: <2021-07-21 Wed 22:02>', + }) + + assert.is.True(#api.load() > 1) + local current_file = cur_file() + local headline = current_file.headlines[2] + assert.are.same('', headline.priority) + assert.are.same('B', config.org_priority_default) + config.org_priority_start_cycle_with_default = false + + headline:priority_down():wait() + assert.are.same('C', cur_file().headlines[2].priority) + assert.is.True(vim.fn.getline(5):match('%[#C%]') ~= nil) + end) + + it('should set/unset priorities', function() + helpers.create_file({ + '#TITLE: First file', + '', + '* TODO Test orgmode :WORK:OFFICE:', + ' DEADLINE: <2021-07-21 Wed 22:02>', + '** TODO Second level :NESTEDTAG:', + ' DEADLINE: <2021-07-21 Wed 22:02>', + '* DONE Some task', + ' DEADLINE: <2021-07-21 Wed 22:02>', + }) + + assert.is.True(#api.load() > 1) + local current_file = cur_file() + local headline = current_file.headlines[2] + assert.are.same('', headline.priority) + + cur_file().headlines[2]:set_priority('B'):wait() + assert.is.True(vim.fn.getline(5):match('%[#B%]') ~= nil) cur_file().headlines[2]:set_priority('C'):wait() assert.is.True(vim.fn.getline(5):match('%[#C%]') ~= nil) cur_file().headlines[2]:set_priority('A'):wait() diff --git a/tests/plenary/object/priority_state_spec.lua b/tests/plenary/object/priority_state_spec.lua index 4dfd93e50..f9713bded 100644 --- a/tests/plenary/object/priority_state_spec.lua +++ b/tests/plenary/object/priority_state_spec.lua @@ -19,7 +19,11 @@ describe('Priority state', function() end local create_priority = function(prio) - return PriorityState:new(prio, config:get_priority_range()) + return PriorityState:new(prio, config:get_priority_range(), true) + end + + local create_priority_non_default = function(prio) + return PriorityState:new(prio, config:get_priority_range(), false) end it('should increase single numeric priority', function() @@ -48,28 +52,28 @@ describe('Priority state', function() assert.are.same('C', priority:decrease()) end) - it('should change to empty priority when numeric increased beyond highest', function() + it('should change to lowest priority when numeric increased beyond highest', function() numeric_config() local priority = create_priority('1') - assert.are.same('', priority:increase()) + assert.are.same('15', priority:increase()) end) - it('should change to empty priority when numeric decreased beyond lowest', function() + it('should change to highest priority when numeric decreased beyond lowest', function() numeric_config() local priority = create_priority('15') - assert.are.same('', priority:decrease()) + assert.are.same('1', priority:decrease()) end) - it('should change to empty priority when alpha increased beyond highest', function() + it('should change to lowest priority when alpha increased beyond highest', function() alpha_config() local priority = create_priority('A') - assert.are.same('', priority:increase()) + assert.are.same('D', priority:increase()) end) - it('should change to empty priority when alpha decreased beyond lowest', function() + it('should change to highest priority when alpha decreased beyond lowest', function() alpha_config() local priority = create_priority('D') - assert.are.same('', priority:decrease()) + assert.are.same('A', priority:decrease()) end) it('should convert numeric priorities to a string for comparison', function() @@ -100,25 +104,37 @@ describe('Priority state', function() alpha_config() local higher = create_priority('A') local lower = create_priority('B') - assert.Is.True(higher:get_sort_value() > lower:get_sort_value()) + assert.is.True(higher:get_sort_value() > lower:get_sort_value()) end) it('should compare numeric priorities correctly', function() numeric_config() local higher = create_priority(1) local lower = create_priority(2) - assert.Is.True(higher:get_sort_value() > lower:get_sort_value()) + assert.is.True(higher:get_sort_value() > lower:get_sort_value()) end) - it('should change to highest priority if priority increased and currently empty', function() + it('should change to default priority if priority increased and currently empty', function() alpha_config() local priority = create_priority('') - assert.are.same('D', priority:increase()) + assert.are.same('C', priority:increase()) end) - it('should change to lowest priority if priority decreased and currently empty', function() + it('should change to default priority if priority decreased and currently empty', function() alpha_config() local priority = create_priority('') - assert.are.same('A', priority:decrease()) + assert.are.same('C', priority:decrease()) + end) + + it('should change to default + 1 priority if priority increased and currently empty', function() + alpha_config() + local priority = create_priority_non_default('') + assert.are.same('B', priority:increase()) + end) + + it('should change to default - 1 priority if priority decreased and currently empty', function() + alpha_config() + local priority = create_priority_non_default('') + assert.are.same('D', priority:decrease()) end) end)