The following Elisp code defines a new command
Used interactively it prompts the user for a new TODO state with completion and applies it without modifying the repeater.
The OP Matthew Piziak mentioned that
org-cancel-repeater should save information for restoring the repeater.
That idea is implemented in
It works by temporarily augmenting
replace-match used in
org-cancel-repeater such that it saves the match string, the beginning position, and end position of the match before replacing it.
With this information the repeater is restored after calling
(defun org-todo-keep-repeater (todo)
"Call `org-todo' with TODO keyword but keep repeater."
(interactive (list (completing-read "Set todo state of current headline to:" org-todo-keywords-1)))
(let ((my-marker-b (make-marker))
(cl-letf* ((old-replace-match (symbol-function 'replace-match))
(lambda (&rest args)
(setq my-original-repeater (match-string 0))
(set-marker my-marker-b (match-beginning 0))
(set-marker my-marker-e (match-end 0))
(apply old-replace-match args))))
(delete-region my-marker-b my-marker-e)
(set-marker my-marker-b nil)
(set-marker my-marker-e nil))
Alternatively one could write a new function that works like
org-cancel-repeater saving the original repeater before canceling it.
- temporarily modifying the old
- writing an new function working like
have advantages and disadvantages.
The first approach works as long as
replace-match for the repeater. It follows all other potential future modifications on
org-cancel-repeater. The second approach would make
org-todo-keep-repeater more robust against modifications of
org-cancel-repeater but it would also not follow potential development on