From 356351142d8ff4d39896f309199528f80bfe91ce Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Sat, 24 Jun 2023 01:37:34 -0400 Subject: [PATCH 01/10] Factor logging logic out of search parser --- lua/orgmode/parser/search.lua | 93 +++++++---------------------------- lua/orgmode/utils/parsing.lua | 69 ++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 76 deletions(-) create mode 100644 lua/orgmode/utils/parsing.lua diff --git a/lua/orgmode/parser/search.lua b/lua/orgmode/parser/search.lua index 755a241cc..3401db38d 100644 --- a/lua/orgmode/parser/search.lua +++ b/lua/orgmode/parser/search.lua @@ -1,6 +1,7 @@ --TODO: Support regex search local Date = require('orgmode.objects.date') +local parsing = require('orgmode.utils.parsing') ---@class Search ---@field term string @@ -88,66 +89,6 @@ local OPERATORS = { end, } ----Parses a pattern from the beginning of an input using Lua's pattern syntax ----@param input string ----@param pattern string ----@return string?, string -local function parse_pattern(input, pattern) - local value = input:match('^' .. pattern) - if value then - return value, input:sub(#value + 1) - else - return nil, input - end -end - ----Parses the first of a sequence of patterns ----@param input string The input to parse ----@param ... string The patterns to accept ----@return string?, string -local function parse_pattern_choice(input, ...) - for _, pattern in ipairs({ ... }) do - local value, remaining = parse_pattern(input, pattern) - if value then - return value, remaining - end - end - - return nil, input -end - ----@generic T ----@param input string ----@param item_parser fun(input: string): (T?, string) ----@param delimiter_pattern string ----@return (T[])?, string -local function parse_delimited_sequence(input, item_parser, delimiter_pattern) - local sequence, item, delimiter = {}, nil, nil - local original_input = input - - -- Parse the first item - item, input = item_parser(input) - if not item then - return sequence, input - end - table.insert(sequence, item) - - -- Continue parsing items while there's a trailing delimiter - delimiter, input = parse_pattern(input, delimiter_pattern) - while delimiter do - item, input = item_parser(input) - if not item then - return nil, original_input - end - - table.insert(sequence, item) - - delimiter, input = parse_pattern(input, delimiter_pattern) - end - - return sequence, input -end - ---@param term string ---@return Search function Search:new(term) @@ -190,7 +131,7 @@ end function Search:_parse() local input = self.term -- Parse the sequence of ORs - self.or_items, input = parse_delimited_sequence(input, function(i) + self.or_items, input = parsing.parse_delimited_sequence(input, function(i) return OrItem:parse(i) end, '%|') @@ -220,7 +161,7 @@ function OrItem:parse(input) local and_items local original_input = input - and_items, input = parse_delimited_sequence(input, function(i) + and_items, input = parsing.parse_delimited_sequence(input, function(i) return AndItem:parse(i) end, '%&') @@ -269,7 +210,7 @@ function AndItem:parse(input) local operator local original_input = input - operator, input = parse_pattern(input, '[%+%-]?') + operator, input = parsing.parse_pattern(input, '[%+%-]?') -- A '+' operator is implied if none is present if operator == '' then @@ -300,7 +241,7 @@ function AndItem:parse(input) end -- Attempt to parse the next operator - operator, input = parse_pattern(input, '[%+%-]') + operator, input = parsing.parse_pattern(input, '[%+%-]') end return and_item, input @@ -339,7 +280,7 @@ end ---@return TagMatch?, string function TagMatch:parse(input) local tag - tag, input = parse_pattern(input, '[%w_@#%%]+') + tag, input = parsing.parse_pattern(input, '[%w_@#%%]+') if not tag then return nil, input end @@ -371,7 +312,7 @@ function PropertyMatch:parse(input) local name, operator, string_str, number_str, date_str local original_input = input - name, input = parse_pattern(input, '[^=<>]+') + name, input = parsing.parse_pattern(input, '[^=<>]+') if not name then return nil, original_input end @@ -383,14 +324,14 @@ function PropertyMatch:parse(input) end -- Number property - number_str, input = parse_pattern(input, '%d+') + number_str, input = parsing.parse_pattern(input, '%d+') if number_str then local number = tonumber(number_str) --[[@as number]] return PropertyNumberMatch:new(name, operator, number), input end -- Date property - date_str, input = parse_pattern(input, '"(<[^>]+>)"') + date_str, input = parsing.parse_pattern(input, '"(<[^>]+>)"') if date_str then ---@type string?, Date? local date_content, date_value @@ -422,7 +363,7 @@ function PropertyMatch:parse(input) end -- String property - string_str, input = parse_pattern(input, '"[^"]+"') + string_str, input = parsing.parse_pattern(input, '"[^"]+"') if string_str then ---@type string local unquote_string = string_str:match('^"([^"]+)"$') @@ -437,7 +378,7 @@ end ---@param input string ---@return PropertyMatchOperator, string function PropertyMatch:_parse_operator(input) - return parse_pattern_choice(input, '%=', '%<%>', '%<%=', '%<', '%>%=', '%>') --[[@as PropertyMatchOperator]] + return parsing.parse_pattern_choice(input, '%=', '%<%>', '%<%=', '%<', '%>%=', '%>') --[[@as PropertyMatchOperator]] end ---Constructs a PropertyNumberMatch @@ -559,7 +500,7 @@ function TodoMatch:parse(input) -- Parse the '/' or '/!' prefix that indicates a TodoMatch ---@type string? local prefix - prefix, input = parse_pattern(input, '%/[%!]?') + prefix, input = parsing.parse_pattern(input, '%/[%!]?') if not prefix then return nil, original_input end @@ -567,8 +508,8 @@ function TodoMatch:parse(input) -- Parse a whitelist of keywords --- @type string[]? local anyOf - anyOf, input = parse_delimited_sequence(input, function(i) - return parse_pattern(i, '%w+') + anyOf, input = parsing.parse_delimited_sequence(input, function(i) + return parsing.parse_pattern(i, '%w+') end, '%|') if anyOf and #anyOf > 0 then -- Successfully parsed the whitelist, return it @@ -580,11 +521,11 @@ function TodoMatch:parse(input) -- Parse a blacklist of keywords ---@type string? local negation - negation, input = parse_pattern(input, '-') + negation, input = parsing.parse_pattern(input, '-') if negation then local negative_items - negative_items, input = parse_delimited_sequence(input, function(i) - return parse_pattern(i, '%w+') + negative_items, input = parsing.parse_delimited_sequence(input, function(i) + return parsing.parse_pattern(i, '%w+') end, '%-') if negative_items then diff --git a/lua/orgmode/utils/parsing.lua b/lua/orgmode/utils/parsing.lua new file mode 100644 index 000000000..56a7615df --- /dev/null +++ b/lua/orgmode/utils/parsing.lua @@ -0,0 +1,69 @@ +local M = {} + +---Parses a pattern from the beginning of an input using Lua's pattern syntax +---@param input string +---@param pattern string +---@return string?, string +function M.parse_pattern(input, pattern) + local value = input:match('^' .. pattern) + if value then + return value, input:sub(#value + 1) + else + return nil, input + end +end + +---Parses the first of a sequence of patterns +---@param input string The input to parse +---@param ... string The patterns to accept +---@return string?, string +function M.parse_pattern_choice(input, ...) + for _, pattern in ipairs({ ... }) do + local value, remaining = M.parse_pattern(input, pattern) + if value then + return value, remaining + end + end + + return nil, input +end + +---@generic T +---@param input string +---@param item_parser fun(input: string): (T?, string) +---@param delimiter_pattern string +---@return (T[])?, string +function M.parse_delimited_sequence(input, item_parser, delimiter_pattern) + local sequence, item, delimiter = {}, nil, nil + local original_input = input + + -- Parse the first item + item, input = item_parser(input) + if not item then + return sequence, input + end + table.insert(sequence, item) + + --- @type string + local snapshot = input + + -- Continue parsing items while there's a trailing delimiter + delimiter, input = M.parse_pattern(input, delimiter_pattern) + while delimiter do + item, input = item_parser(input) + + -- If not another element, eturn the previously parsed items + if not item then + return sequence, snapshot + end + + table.insert(sequence, item) + snapshot = input + + delimiter, input = M.parse_pattern(input, delimiter_pattern) + end + + return sequence, input +end + +return M From 213281d87193da4c084872c16ca77d4e0f3e0abb Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Sat, 24 Jun 2023 02:31:39 -0400 Subject: [PATCH 02/10] Initial todo config parser definition --- lua/orgmode/parser/todo-config.lua | 158 +++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 lua/orgmode/parser/todo-config.lua diff --git a/lua/orgmode/parser/todo-config.lua b/lua/orgmode/parser/todo-config.lua new file mode 100644 index 000000000..c8c5bbd7c --- /dev/null +++ b/lua/orgmode/parser/todo-config.lua @@ -0,0 +1,158 @@ +local parsing = require('orgmode.utils.parsing') + +--- @class TodoConfig +--- @field words TodoConfigWord[] +local TodoConfig = {} +TodoConfig.__index = TodoConfig + +--- @alias TodoConfigRecordBehavior 'time' | 'note' | false + +--- @class TodoConfigWord +--- @field name string +--- @field is_active boolean +--- @field hotkey string +--- @field on_enter TodoConfigRecordBehavior +--- @field on_leave TodoConfigRecordBehavior +local TodoConfigWord = {} + +--- @param words TodoConfigWord[] +--- @return TodoConfig +function TodoConfig:_new(words) + --- @type TodoConfig + local instance = {} + setmetatable(instance, TodoConfig) + + instance.words = words + + return instance +end + +--- @param input string +--- @return TodoConfig?, string +function TodoConfig:parse(input) + local original = input + + --- @type TodoConfigWord[] + local active + active, input = parsing.parse_delimited_sequence(input, function(inner_input) + return TodoConfigWord:parse(inner_input, true) + end, '%s+') + + if #active == 0 then + return nil, original + end + + local pipe + pipe, input = parsing.parse_pattern(input, '%s*%|%s*') + if pipe == nil then + return nil, original + end + + --- @type TodoConfigWord[] + local inactive + inactive, input = parsing.parse_delimited_sequence(input, function(inner_input) + return TodoConfigWord:parse(inner_input, false) + end, '%s+') + + if #inactive == 0 then + return nil, original + end + + --- @type TodoConfigWord[] + local words = {} + for _, x in ipairs(active) do + table.insert(words, x) + end + for _, x in ipairs(inactive) do + table.insert(words, x) + end + + return TodoConfig:_new(words), input +end +end + +--- @param name string +--- @param hotkey string +--- @param is_active boolean +--- @param on_enter TodoConfigRecordBehavior +--- @param on_leave TodoConfigRecordBehavior +--- @return TodoConfigWord +function TodoConfigWord:_new(name, is_active, hotkey, on_enter, on_leave) + --- @type TodoConfigWord + local instance = {} + setmetatable(instance, TodoConfigWord) + + instance.name = name + instance.is_active = is_active + instance.hotkey = hotkey + instance.on_enter = on_enter + instance.on_leave = on_leave + + return instance +end + +--- @param input string +--- @param is_active boolean +--- @return TodoConfigWord?, string +function TodoConfigWord:parse(input, is_active) + local original = input + + --- @type string?, string?, string?, string? + local name, open, hotkey, enter, slash, leave, close + + name, input = parsing.parse_pattern(input, '%w+') + if name == nil then + return nil, original + end + + open, input = parsing.parse_pattern(input, '%(') + if open == nil then + return nil, original + end + + hotkey, input = parsing.parse_pattern(input, '%w') + if hotkey == nil then + return nil, original + end + + ---@type TodoConfigRecordBehavior + local on_enter = false + enter, input = parsing.parse_pattern_choice(input, '%@', '%!') + if enter ~= nil then + if enter == '!' then + on_enter = 'time' + elseif enter == '@' then + on_enter = 'note' + else + return nil, original + end + end + + --- @type TodoConfigRecordBehavior + local on_leave = false + slash, input = parsing.parse_pattern(input, '%/') + if slash ~= nil then + leave, input = parsing.parse_pattern_choice(input, '%@', '%!') + if leave == nil then + return nil, original + end + + if leave == '!' then + on_leave = 'time' + elseif leave == '@' then + on_leave = 'note' + else + return nil, original + end + end + + close, input = parsing.parse_pattern(input, '%)') + if close == nil then + return nil, original + end + + local word = TodoConfigWord:_new(name, is_active, hotkey, on_enter, on_leave) + return word, input +end + +return TodoConfig From 35134c79a93e2d6de47ceb600f5f1c883da87025 Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Sun, 25 Jun 2023 14:55:18 -0400 Subject: [PATCH 03/10] Add a Lua type annotation for `org_log_done` Updates the type annotation for the `DefaultConfig` type to specify the allowed values of org_log_done for the Lua LSP. The values that are specified are based on the currently documented values for `org_log_done`. --- lua/orgmode/config/defaults.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/lua/orgmode/config/defaults.lua b/lua/orgmode/config/defaults.lua index 49334e387..b17bf3d5b 100644 --- a/lua/orgmode/config/defaults.lua +++ b/lua/orgmode/config/defaults.lua @@ -1,4 +1,5 @@ ---@class DefaultConfig +---@field org_log_done 'time' | 'note' | false local DefaultConfig = { org_agenda_files = '', org_default_notes_file = '', From 5fc272f6a67c3efeafc4e8ea70f492f99cfed577 Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Sun, 25 Jun 2023 14:57:28 -0400 Subject: [PATCH 04/10] Add get_logging_behavior to `TodoConfig` Adds a method to the `TodoConfig` type to make determining whether to log a time, note, or not log at all for a give TodoConfig easier. --- lua/orgmode/parser/todo-config.lua | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lua/orgmode/parser/todo-config.lua b/lua/orgmode/parser/todo-config.lua index c8c5bbd7c..3e2f800ef 100644 --- a/lua/orgmode/parser/todo-config.lua +++ b/lua/orgmode/parser/todo-config.lua @@ -69,6 +69,35 @@ function TodoConfig:parse(input) return TodoConfig:_new(words), input end + +--- @param from string +--- @param to string +--- @return TodoConfigRecordBehavior +function TodoConfig:get_logging_behavior(from, to) + --- Find the from config + local from_config = self:_find_word(from) + local to_config = self:_find_word(to) + + -- Ensure the described transition is valid + if from_config == nil or to_config == nil then + return false + end + + return to_config.on_enter or from_config.on_leave +end + +--- Finds the word config with the associated name +--- @private +--- @param name string +--- @return TodoConfigWord? +function TodoConfig:_find_word(name) + for _, x in ipairs(self.words) do + if x.name == name then + return x + end + end + + return nil end --- @param name string From 67f4447310eeacc0e9de79cf989c3afd56205500 Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Sun, 25 Jun 2023 15:40:52 -0400 Subject: [PATCH 05/10] Correct the luadoc for `Headline:todo` --- lua/orgmode/treesitter/headline.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lua/orgmode/treesitter/headline.lua b/lua/orgmode/treesitter/headline.lua index 48df63637..cf1b67b3c 100644 --- a/lua/orgmode/treesitter/headline.lua +++ b/lua/orgmode/treesitter/headline.lua @@ -217,9 +217,8 @@ function Headline:item() return self.headline:field('item')[1] end --- Returns the headlines todo node, it's keyword, --- and if it's in done state --- @return Node, string, boolean +--- Returns the headlines todo node, it's keyword, and if it's in done state +--- @return Node? node, string? word, boolean? isDone function Headline:todo() local todo_keywords = config:get_todo_keywords() local keywords = todo_keywords.ALL From 7a93ffe57a0bd217a197f3f49e9b56aeff78daed Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Sun, 25 Jun 2023 17:01:23 -0400 Subject: [PATCH 06/10] Add support for `LOGGING` property --- lua/orgmode/org/mappings.lua | 58 ++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/lua/orgmode/org/mappings.lua b/lua/orgmode/org/mappings.lua index 12f2e8585..79121f462 100644 --- a/lua/orgmode/org/mappings.lua +++ b/lua/orgmode/org/mappings.lua @@ -15,6 +15,7 @@ local ts_org = require('orgmode.treesitter') local ts_table = require('orgmode.treesitter.table') local EventManager = require('orgmode.events') local Promise = require('orgmode.utils.promise') +local TodoConfig = require('orgmode.parser.todo-config') local events = EventManager.event local Link = require('orgmode.objects.link') @@ -386,6 +387,8 @@ end function OrgMappings:_todo_change_state(direction) local headline = ts_org.closest_headline() local _, old_state, was_done = headline:todo() + --- @cast old_state -nil + --- @cast was_done -nil local changed = self:_change_todo_state(direction, true) if not changed then return @@ -403,9 +406,37 @@ function OrgMappings:_todo_change_state(direction) return dispatchEvent() end - local log_note = config.org_log_done == 'note' - local log_time = config.org_log_done == 'time' - local should_log_time = log_note or log_time + local new_state = item.todo_keyword.value + + -- Determine which configuration to use + local global_config = config.org_log_done + + --- @type nil | false | 'time' | 'note' + local section_config + local logging_prop = item.properties.items.logging + if logging_prop == 'nil' then + section_config = false + elseif logging_prop ~= nil then + local todoConfig = TodoConfig:parse(logging_prop) + if todoConfig ~= nil then + section_config = todoConfig:get_logging_behavior(old_state, new_state) + else + -- TODO: Report invalid config? + section_config = nil + end + else + section_config = nil + end + + -- Use the most locally available log config + --- @type false | 'time' | 'note' + local log_config + if section_config ~= nil then + log_config = section_config + else + log_config = global_config + end + local indent = config:get_indent(headline:level() + 1) local get_note = function(note) @@ -423,11 +454,12 @@ function OrgMappings:_todo_change_state(direction) local repeater_dates = item:get_repeater_dates() if #repeater_dates == 0 then - if should_log_time and item:is_done() and not was_done then + -- If going from "not done" to "done", set the closed date and add the note/time + if log_config ~= false and item:is_done() and not was_done then headline:set_closed_date() item = Files.get_closest_headline() - if log_note then + if log_config == 'note' then dispatchEvent() return self.capture.closing_note:open():next(function(note) local valid_note = get_note(note) @@ -438,7 +470,9 @@ function OrgMappings:_todo_change_state(direction) end) end end - if should_log_time and not item:is_done() and was_done then + + -- If going from "done" to "not done", remove the close date + if log_config ~= false and not item:is_done() and was_done then headline:remove_closed_date() end return dispatchEvent() @@ -450,19 +484,19 @@ function OrgMappings:_todo_change_state(direction) self:_change_todo_state('reset') local state_change = { - string.format('%s- State "%s" from "%s" [%s]', indent, item.todo_keyword.value, old_state, Date.now():to_string()), + string.format('%s- State "%s" from "%s" [%s]', indent, new_state, old_state, Date.now():to_string()), } dispatchEvent() return Promise.resolve() :next(function() - if not log_note then + if log_config == 'time' then return state_change + elseif log_config == 'note' then + return self.capture.closing_note:open():next(function(closing_note) + return get_note(closing_note) + end) end - - return self.capture.closing_note:open():next(function(closing_note) - return get_note(closing_note) - end) end) :next(function(note) headline:set_property('LAST_REPEAT', Date.now():to_wrapped_string(false)) From 54ffa49ec1142f1096c9c434285fba2c3b50615e Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Tue, 27 Jun 2023 18:39:54 -0400 Subject: [PATCH 07/10] Check `org_toggle_archive` for note/time config --- lua/orgmode/org/mappings.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lua/orgmode/org/mappings.lua b/lua/orgmode/org/mappings.lua index 79121f462..ea3fee428 100644 --- a/lua/orgmode/org/mappings.lua +++ b/lua/orgmode/org/mappings.lua @@ -428,11 +428,27 @@ function OrgMappings:_todo_change_state(direction) section_config = nil end + -- @type nil | false | 'time' | 'note' + local user_config + if config.org_todo_keywords ~= nil then + local todoConfig = TodoConfig:parse(table.concat(config.org_todo_keywords, ' ')) + if todoConfig ~= nil then + user_config = todoConfig:get_logging_behavior(old_state, new_state) + else + -- TODO: Report invalid config? + user_config = nil + end + else + user_config = nil + end + -- Use the most locally available log config --- @type false | 'time' | 'note' local log_config if section_config ~= nil then log_config = section_config + elseif user_config ~= nil then + log_config = user_config else log_config = global_config end From 4595195ce16619636c2e2d945003c2c986661aa2 Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Sun, 29 Oct 2023 19:53:11 -0400 Subject: [PATCH 08/10] Move the parsing utils file --- lua/orgmode/parser/search.lua | 2 +- lua/orgmode/parser/todo-config.lua | 2 +- lua/orgmode/{utils/parsing.lua => parser/utils.lua} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename lua/orgmode/{utils/parsing.lua => parser/utils.lua} (100%) diff --git a/lua/orgmode/parser/search.lua b/lua/orgmode/parser/search.lua index 3401db38d..8de8e19c2 100644 --- a/lua/orgmode/parser/search.lua +++ b/lua/orgmode/parser/search.lua @@ -1,7 +1,7 @@ --TODO: Support regex search local Date = require('orgmode.objects.date') -local parsing = require('orgmode.utils.parsing') +local parsing = require('orgmode.parsers.utils') ---@class Search ---@field term string diff --git a/lua/orgmode/parser/todo-config.lua b/lua/orgmode/parser/todo-config.lua index 3e2f800ef..b26cec18e 100644 --- a/lua/orgmode/parser/todo-config.lua +++ b/lua/orgmode/parser/todo-config.lua @@ -1,4 +1,4 @@ -local parsing = require('orgmode.utils.parsing') +local parsing = require('orgmode.parsers.utils') --- @class TodoConfig --- @field words TodoConfigWord[] diff --git a/lua/orgmode/utils/parsing.lua b/lua/orgmode/parser/utils.lua similarity index 100% rename from lua/orgmode/utils/parsing.lua rename to lua/orgmode/parser/utils.lua From 0e9437d3b8582844c4d5bcd109013e261b0cec0b Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Sun, 29 Oct 2023 19:57:08 -0400 Subject: [PATCH 09/10] Remove the LOGGING property logic Remove the LOGGING property logic from the sections and the file-level. --- lua/orgmode/org/mappings.lua | 74 ++++++------------------------------ 1 file changed, 12 insertions(+), 62 deletions(-) diff --git a/lua/orgmode/org/mappings.lua b/lua/orgmode/org/mappings.lua index ea3fee428..12f2e8585 100644 --- a/lua/orgmode/org/mappings.lua +++ b/lua/orgmode/org/mappings.lua @@ -15,7 +15,6 @@ local ts_org = require('orgmode.treesitter') local ts_table = require('orgmode.treesitter.table') local EventManager = require('orgmode.events') local Promise = require('orgmode.utils.promise') -local TodoConfig = require('orgmode.parser.todo-config') local events = EventManager.event local Link = require('orgmode.objects.link') @@ -387,8 +386,6 @@ end function OrgMappings:_todo_change_state(direction) local headline = ts_org.closest_headline() local _, old_state, was_done = headline:todo() - --- @cast old_state -nil - --- @cast was_done -nil local changed = self:_change_todo_state(direction, true) if not changed then return @@ -406,53 +403,9 @@ function OrgMappings:_todo_change_state(direction) return dispatchEvent() end - local new_state = item.todo_keyword.value - - -- Determine which configuration to use - local global_config = config.org_log_done - - --- @type nil | false | 'time' | 'note' - local section_config - local logging_prop = item.properties.items.logging - if logging_prop == 'nil' then - section_config = false - elseif logging_prop ~= nil then - local todoConfig = TodoConfig:parse(logging_prop) - if todoConfig ~= nil then - section_config = todoConfig:get_logging_behavior(old_state, new_state) - else - -- TODO: Report invalid config? - section_config = nil - end - else - section_config = nil - end - - -- @type nil | false | 'time' | 'note' - local user_config - if config.org_todo_keywords ~= nil then - local todoConfig = TodoConfig:parse(table.concat(config.org_todo_keywords, ' ')) - if todoConfig ~= nil then - user_config = todoConfig:get_logging_behavior(old_state, new_state) - else - -- TODO: Report invalid config? - user_config = nil - end - else - user_config = nil - end - - -- Use the most locally available log config - --- @type false | 'time' | 'note' - local log_config - if section_config ~= nil then - log_config = section_config - elseif user_config ~= nil then - log_config = user_config - else - log_config = global_config - end - + local log_note = config.org_log_done == 'note' + local log_time = config.org_log_done == 'time' + local should_log_time = log_note or log_time local indent = config:get_indent(headline:level() + 1) local get_note = function(note) @@ -470,12 +423,11 @@ function OrgMappings:_todo_change_state(direction) local repeater_dates = item:get_repeater_dates() if #repeater_dates == 0 then - -- If going from "not done" to "done", set the closed date and add the note/time - if log_config ~= false and item:is_done() and not was_done then + if should_log_time and item:is_done() and not was_done then headline:set_closed_date() item = Files.get_closest_headline() - if log_config == 'note' then + if log_note then dispatchEvent() return self.capture.closing_note:open():next(function(note) local valid_note = get_note(note) @@ -486,9 +438,7 @@ function OrgMappings:_todo_change_state(direction) end) end end - - -- If going from "done" to "not done", remove the close date - if log_config ~= false and not item:is_done() and was_done then + if should_log_time and not item:is_done() and was_done then headline:remove_closed_date() end return dispatchEvent() @@ -500,19 +450,19 @@ function OrgMappings:_todo_change_state(direction) self:_change_todo_state('reset') local state_change = { - string.format('%s- State "%s" from "%s" [%s]', indent, new_state, old_state, Date.now():to_string()), + string.format('%s- State "%s" from "%s" [%s]', indent, item.todo_keyword.value, old_state, Date.now():to_string()), } dispatchEvent() return Promise.resolve() :next(function() - if log_config == 'time' then + if not log_note then return state_change - elseif log_config == 'note' then - return self.capture.closing_note:open():next(function(closing_note) - return get_note(closing_note) - end) end + + return self.capture.closing_note:open():next(function(closing_note) + return get_note(closing_note) + end) end) :next(function(note) headline:set_property('LAST_REPEAT', Date.now():to_wrapped_string(false)) From 2af9a347726d1c4faae5e90e18811bf7d859ddd8 Mon Sep 17 00:00:00 2001 From: Chuck Flowers Date: Wed, 10 Jan 2024 08:00:21 -0500 Subject: [PATCH 10/10] Fix issues with misnamed imports --- lua/orgmode/parser/search.lua | 2 +- lua/orgmode/parser/todo-config.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lua/orgmode/parser/search.lua b/lua/orgmode/parser/search.lua index 8de8e19c2..1baef8d19 100644 --- a/lua/orgmode/parser/search.lua +++ b/lua/orgmode/parser/search.lua @@ -1,7 +1,7 @@ --TODO: Support regex search local Date = require('orgmode.objects.date') -local parsing = require('orgmode.parsers.utils') +local parsing = require('orgmode.parser.utils') ---@class Search ---@field term string diff --git a/lua/orgmode/parser/todo-config.lua b/lua/orgmode/parser/todo-config.lua index b26cec18e..d73820cf0 100644 --- a/lua/orgmode/parser/todo-config.lua +++ b/lua/orgmode/parser/todo-config.lua @@ -1,4 +1,4 @@ -local parsing = require('orgmode.parsers.utils') +local parsing = require('orgmode.parser.utils') --- @class TodoConfig --- @field words TodoConfigWord[]