emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Refiling All 'Terminal TODO State' Entries to a Particular Heading
@ 2021-05-06 14:23 Tim Visher
  2021-05-11  4:56 ` Ihor Radchenko
  2021-05-12 13:35 ` Tim Visher
  0 siblings, 2 replies; 4+ messages in thread
From: Tim Visher @ 2021-05-06 14:23 UTC (permalink / raw)
  To: Emacs Org Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 2310 bytes --]

Hi Everyone,

Partly because I think it's neat and partly to ask for ways that I could
improve it I figured I'd share my latest little snippet of org elisp with
the list.

I maintain my primary TODO list as an org file with top-level headings like *
This Week, * Delegated, * Scheduled, * Deferred, etc. These all contain
TODOs or potential TODOs.

Anything I intend to work on near term I refile into * This Week and that's
then the primary heading that I'm burning down throughout my day.

I do weekly reflection/projections and 6 week reflection/projections. When
I do a weekly reflection I go through another heading * Done to remind
myself what I accomplished in the past week. When I do a 6 week
reflection/projection I review the Done heading one more time and then I
refile all the entries currently there into an * Archive heading. Then
every now and then I actually archive entries in Archive into an
*.org_archive file. * Done and * Archive are both tagged with ARCHIVE.

In an effort to start automating some of this effort I wrote the following
elisp to refile all the Level 2 entries to the Done heading:

(defun timvisher-org-refile-done-entry-position
    ()
  (save-excursion
    (goto-char (point-min))
    (re-search-forward "^\\* Done")))

(defun timvisher-org-refile-done-entry
    ()
  (org-refile nil
              (current-buffer)
              (list "* Done"
                    (buffer-file-name)
                    nil
                    (timvisher-org-refile-done-entry-position))))

(defun timvisher-org-refile-done-entries
    ()
  (interactive)
  (length
   (org-map-entries #'timvisher-org-refile-done-entry
                    "LEVEL=2/+DONE|+CANCELLED"
                    nil
                    'archive)))

I'm doing Level 2 only because for long running projects I tend to have a
single Level 2 heading with many subheadings representing the project's
breakdown and I don't want them to be refiled out of the project.

Opportunities for improvement would be:

   1. Is there a better way to find the * Done entry than searching for it
   every time?
   2. Am I using org-refile correctly there? It's functional but it also
   seems needlessly complicated.

Hope this finds you all well. :)

--

In Christ,

Timmy V.

https://blog.twonegatives.com
http://five.sentenc.es

[-- Attachment #2: Type: text/html, Size: 4030 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Refiling All 'Terminal TODO State' Entries to a Particular Heading
  2021-05-06 14:23 Refiling All 'Terminal TODO State' Entries to a Particular Heading Tim Visher
@ 2021-05-11  4:56 ` Ihor Radchenko
  2021-05-12 13:35 ` Tim Visher
  1 sibling, 0 replies; 4+ messages in thread
From: Ihor Radchenko @ 2021-05-11  4:56 UTC (permalink / raw)
  To: Tim Visher; +Cc: Emacs Org Mode mailing list

Tim Visher <tim.visher@gmail.com> writes:

> I maintain my primary TODO list as an org file with top-level headings like *
> This Week, * Delegated, * Scheduled, * Deferred, etc. These all contain
> TODOs or potential TODOs.

FYI. You can also read [1] for alternative approaches.

[1] https://orgmode.org/list/76f7cd71190bcff68e57e71d163fe49f@science.uva.nl/

>    1. Is there a better way to find the * Done entry than searching for it
>    every time?

You can assign a custom ID to that entry and use org-link-search.

>    2. Am I using org-refile correctly there? It's functional but it also
>    seems needlessly complicated.

Seems fine. I do not know any better way to do it.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Refiling All 'Terminal TODO State' Entries to a Particular Heading
  2021-05-06 14:23 Refiling All 'Terminal TODO State' Entries to a Particular Heading Tim Visher
  2021-05-11  4:56 ` Ihor Radchenko
@ 2021-05-12 13:35 ` Tim Visher
  2021-05-12 14:54   ` Ihor Radchenko
  1 sibling, 1 reply; 4+ messages in thread
From: Tim Visher @ 2021-05-12 13:35 UTC (permalink / raw)
  To: Emacs Org Mode mailing list

[-- Attachment #1: Type: text/plain, Size: 4817 bytes --]

Hi Everyone,

I found that my timvisher-org-refile-done-entries had a bug where it could
skip entries if the org buffer had consecutive DONE/CANCELLED entries. I
believe this is because of this quote from the manual:

After evaluation, Org moves point to the end of the line that was just
processed. Search continues from that point forward. This may not always
work as expected under some conditions, such as if the current sub-tree was
removed by a previous archiving operation. In such rare circumstances, Org
skips the next entry entirely when it should not. To stop Org from such
skips, make FUNC set the variable ‘org-map-continue-from’ to a specific
buffer position.

I've been doing some experimentation around how to fix this:
Attempt 1

This feels like the simplest and most naive approach:

(defun timvisher-org-refile-done-entry-position
    ()
  (save-excursion
    (goto-char (point-min))
    (- (re-search-forward "^\\* Done") 6)))

(defun timvisher-org-refile-done-entry
    ()
  (org-refile nil
              (current-buffer)
              (list "* Done"
                    (buffer-file-name)
                    nil
                    (timvisher-org-refile-done-entry-position))))

(defun timvisher-org-refile-done-entries
    ()
  (interactive)
  (while (< 0 (length (org-map-entries #'timvisher-org-refile-done-entry
                                       "LEVEL=2/+DONE|+CANCELLED"
                                       nil
                                       'archive)))))

Here we're literally just doing the org-map-entries operation forever until
the operation finds nothing to operate on.

I worry about infinite loops and all that here though. It also just seems,
well, a little brute force.
Attempt 2

(defun timvisher-org-refile-done-entry
    (point)
  (let ((done-entry-position (timvisher-org-refile-done-entry-position)))
    (when (< done-entry-position point)
      (error (concat "Refile target at %d is located after the Done "
                     "entry at %d. Move the Done entry to the bottom "
                     "of the file.")
             point
             done-entry-position))
    (goto-char point)
    (org-refile nil
                (current-buffer)
                (list "* Done"
                      (buffer-file-name)
                      nil
                      (timvisher-org-refile-done-entry-position)))))

(defun timvisher-org-refile-done-entries
    ()
  (interactive)
  (seq-map #'timvisher-org-refile-done-entry
           (reverse (org-map-entries #'point
                                     "LEVEL=2/+DONE|+CANCELLED"
                                     nil
                                     'archive))))

Here we're recognizing that if we could process the entries in reverse then
we'd never have to worry about an entry moving from underneath us as we
refile.

This also seems silly:

   1. I'm sure there's a function already that just returns me the matching
   entries for a given match search. Using the mapping API for seems incorrect.
   2. It requires that the Done entry be below all possible targets which
   I'd rather not require. My Done entry is typically above my deferred
   entries and I want to be able to mark deferred entries as cancelled or done
   and have this work properly.

Overall I actually like this attempt less than the first one.
Attempt 3

I'm convinced that there must be something I can do with the
org-map-continue-from var but I'm having a lot of trouble grokking how to
use it properly.

My initial attempt looks like this:

(defun timvisher-org-refile-done-entry
    ()
  (let ((entry-begin-point (point)))
    (org-refile nil
                (current-buffer)
                (list "* Done"
                      (buffer-file-name)
                      nil
                      (timvisher-org-refile-done-entry-position)))
    (setq org-map-continue-from entry-begin-point)))

(defun timvisher-org-refile-done-entries
    ()
  (interactive)
  (org-map-entries #'timvisher-org-refile-done-entry
                   "LEVEL=2/+DONE|+CANCELLED"
                   nil
                   'archive))

The idea being that if I do in fact refile an entry I'd actually like the
'search to continue' from where it just was. This 'works' in that it
successfully refiles all the entries even if they're consecutive but it
also manages to get into an infinite loop because, AFAICT, it ignores the
'archive skipping somehow. I've spent some time in the debugger and I can't
figure out yet why it does that.

Any tips on how I might use this variable to achieve my goals?

Thanks in advance!

--

In Christ,

Timmy V.

https://blog.twonegatives.com
http://five.sentenc.es

[-- Attachment #2: Type: text/html, Size: 8140 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Refiling All 'Terminal TODO State' Entries to a Particular Heading
  2021-05-12 13:35 ` Tim Visher
@ 2021-05-12 14:54   ` Ihor Radchenko
  0 siblings, 0 replies; 4+ messages in thread
From: Ihor Radchenko @ 2021-05-12 14:54 UTC (permalink / raw)
  To: Tim Visher; +Cc: Emacs Org Mode mailing list

Tim Visher <tim.visher@gmail.com> writes:
>
> I found that my timvisher-org-refile-done-entries had a bug where it could
> skip entries if the org buffer had consecutive DONE/CANCELLED entries. I
> believe this is because of this quote from the manual:
>
> After evaluation, Org moves point to the end of the line that was just
> processed. Search continues from that point forward. This may not always
> work as expected under some conditions, such as if the current sub-tree was
> removed by a previous archiving operation. In such rare circumstances, Org
> skips the next entry entirely when it should not. To stop Org from such
> skips, make FUNC set the variable ‘org-map-continue-from’ to a specific
> buffer position.

I think the easiest would be using markers. You can collect the list of
headline markers in org-map-entries without modifying buffer. Then, you
mapc over the list of markers and refile the corresponding headings. You
will not need to worry about point moving due to changes in buffer as
markers will not be affected by buffer changes.

Hope it helps.

Best,
Ihor


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-05-12 14:51 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-06 14:23 Refiling All 'Terminal TODO State' Entries to a Particular Heading Tim Visher
2021-05-11  4:56 ` Ihor Radchenko
2021-05-12 13:35 ` Tim Visher
2021-05-12 14:54   ` Ihor Radchenko

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).