@@ -15,6 +15,7 @@ local ts = require('orgmode.treesitter.compat')
1515local ts_table = require (' orgmode.treesitter.table' )
1616local EventManager = require (' orgmode.events' )
1717local Promise = require (' orgmode.utils.promise' )
18+ local TodoConfig = require (' orgmode.parser.todo-config' )
1819local events = EventManager .event
1920
2021--- @class OrgMappings
377378function OrgMappings :_todo_change_state (direction )
378379 local headline = ts_org .closest_headline ()
379380 local _ , old_state , was_done = headline :todo ()
381+ --- @cast old_state - nil
382+ --- @cast was_done - nil
380383 local changed = self :_change_todo_state (direction , true )
381384 if not changed then
382385 return
@@ -394,9 +397,37 @@ function OrgMappings:_todo_change_state(direction)
394397 return dispatchEvent ()
395398 end
396399
397- local log_note = config .org_log_done == ' note'
398- local log_time = config .org_log_done == ' time'
399- local should_log_time = log_note or log_time
400+ local new_state = item .todo_keyword .value
401+
402+ -- Determine which configuration to use
403+ local global_config = config .org_log_done
404+
405+ --- @type nil | false | ' time' | ' note'
406+ local section_config
407+ local logging_prop = item .properties .items .logging
408+ if logging_prop == ' nil' then
409+ section_config = false
410+ elseif logging_prop ~= nil then
411+ local todoConfig = TodoConfig :parse (logging_prop )
412+ if todoConfig ~= nil then
413+ section_config = todoConfig :get_logging_behavior (old_state , new_state )
414+ else
415+ -- TODO: Report invalid config?
416+ section_config = nil
417+ end
418+ else
419+ section_config = nil
420+ end
421+
422+ -- Use the most locally available log config
423+ --- @type false | ' time' | ' note'
424+ local log_config
425+ if section_config ~= nil then
426+ log_config = section_config
427+ else
428+ log_config = global_config
429+ end
430+
400431 local indent = config :get_indent (headline :level () + 1 )
401432
402433 local get_note = function (note )
@@ -414,11 +445,12 @@ function OrgMappings:_todo_change_state(direction)
414445
415446 local repeater_dates = item :get_repeater_dates ()
416447 if # repeater_dates == 0 then
417- if should_log_time and item :is_done () and not was_done then
448+ -- If going from "not done" to "done", set the closed date and add the note/time
449+ if log_config ~= false and item :is_done () and not was_done then
418450 headline :set_closed_date ()
419451 item = Files .get_closest_headline ()
420452
421- if log_note then
453+ if log_config == ' note ' then
422454 dispatchEvent ()
423455 return self .capture .closing_note :open ():next (function (note )
424456 local valid_note = get_note (note )
@@ -429,7 +461,9 @@ function OrgMappings:_todo_change_state(direction)
429461 end )
430462 end
431463 end
432- if should_log_time and not item :is_done () and was_done then
464+
465+ -- If going from "done" to "not done", remove the close date
466+ if log_config ~= false and not item :is_done () and was_done then
433467 headline :remove_closed_date ()
434468 end
435469 return dispatchEvent ()
@@ -441,19 +475,19 @@ function OrgMappings:_todo_change_state(direction)
441475
442476 self :_change_todo_state (' reset' )
443477 local state_change = {
444- string.format (' %s- State "%s" from "%s" [%s]' , indent , item . todo_keyword . value , old_state , Date .now ():to_string ()),
478+ string.format (' %s- State "%s" from "%s" [%s]' , indent , new_state , old_state , Date .now ():to_string ()),
445479 }
446480
447481 dispatchEvent ()
448482 return Promise .resolve ()
449483 :next (function ()
450- if not log_note then
484+ if log_config == ' time ' then
451485 return state_change
486+ elseif log_config == ' note' then
487+ return self .capture .closing_note :open ():next (function (closing_note )
488+ return get_note (closing_note )
489+ end )
452490 end
453-
454- return self .capture .closing_note :open ():next (function (closing_note )
455- return get_note (closing_note )
456- end )
457491 end )
458492 :next (function (note )
459493 headline :set_property (' LAST_REPEAT' , Date .now ():to_wrapped_string (false ))
0 commit comments