emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Tim Visher <tim.visher@gmail.com>
To: Emacs Org Mode mailing list <emacs-orgmode@gnu.org>
Subject: Re: Refiling All 'Terminal TODO State' Entries to a Particular Heading
Date: Wed, 12 May 2021 09:35:54 -0400	[thread overview]
Message-ID: <CAHa53uy1q+PL1NYtahc_8L+TZ38zKQsfGALz5j1Rhzs=G76eXw@mail.gmail.com> (raw)
In-Reply-To: <CAHa53uyAgajfOk4NhovGDJ4f1OVvFf03XxwbgR89jgJ1M0K3Ew@mail.gmail.com>

[-- 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 --]

  parent reply	other threads:[~2021-05-12 13:37 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-06 14:23 Tim Visher
2021-05-11  4:56 ` Ihor Radchenko
2021-05-12 13:35 ` Tim Visher [this message]
2021-05-12 14:54   ` Ihor Radchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAHa53uy1q+PL1NYtahc_8L+TZ38zKQsfGALz5j1Rhzs=G76eXw@mail.gmail.com' \
    --to=tim.visher@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    --subject='Re: Refiling All '\''Terminal TODO State'\'' Entries to a Particular Heading' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Code repositories for project(s) associated with this 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).