1

I coded a function that accesses lines in a folded drawer:

(defun org-try-merging-last-clock-out ()
  "Try to merge the latest clock-out, and catch the error if the discrepancy is not zero."
  (save-restriction
    (save-excursion
      (org-clock-goto)
      (search-forward org-last-inserted-timestamp)
      (condition-case nil
      (org-clock-merge t)
    (error)))))

The function org-clock-merge is an interactive function that I defined in this other thread that merges two clock lines. It is long and I can copy it here if needed.

My clock lines are in a LOGBOOK drawer. The headline initially looks like this:

** DONE Some task...

After calling the function programmatically through the org-clock-out-hook, it looks like this:

** DONE Some task
CLOSED: [2019-09-24 Tue 15:56] SCHEDULED: <2019-10-07 Mon>
:PROPERTIES:
:CREATED:  [2019-09-23 Mon]
:END:
:LOGBOOK:...

I confirm that my org-clock-merge function ran and merged the clock stamps. I would like the headline appearance not to change after running the command.

Does a function similar to save-restriction for narrowing exist for org-mode cycling?

  • 1
    Is your question about save-excursion or save-restriction? You say "similar to save-excursion for narrowing", but save-excursion is not about narrowing. – Drew Sep 24 at 21:40
  • Sorry for the confusion. My question was about save-restriction and I updated the question. – miguelmorin Sep 27 at 13:20
  • 1
    Do you mean that you'd like to keep the headline collapsed? @miguelmorin because to me (at first sight at least) you're calling org-cycle inside the LOGBOOK drawer, so it cycles the drawer not the subtree. – Muihlinn Sep 27 at 15:09
  • @Muihlinn Well spotted! One solution is to call (outline-hide-subtree) outside of save-excursion. It does not maintain the current cycle visibility, but it works for me for now. Do you want to write an answer? Or do you know how to maintain the current cycle visibility state? – miguelmorin Sep 27 at 15:24
1

You might try org-save-outline-visibility. It sounds like it should do what you want. From the documentation (C-h f org-save-outline-visibility RET):

Save and restore outline visibility around BODY.
If USE-MARKERS is non-nil, use markers for the positions.  This
means that the buffer may change while running BODY, but it also
means that the buffer should stay alive during the operation,
because otherwise all these markers will point to nowhere.

Update from original poster: This is indeed what I wanted, and here is some example code:

(defun org-try-merging-last-clock-out ()
  "Try to merge the latest clock-out, and catch the error if the discrepancy is not zero."
  (save-excursion
    (org-save-outline-visibility t
      (progn
        (org-clock-goto)
        (search-forward org-last-inserted-timestamp)
        (condition-case nil
            (org-clock-merge t)
          (error))))))

It saves visibility of the heading and also any drawers in the heading.

1

You might be looking for org-narrow-to-subtree and/or org-toggle-narrow-to-subtree

Anyway, in your code it looks like you're calling org-cycle over the LOGBOOK, cycling will only affect it, not the subtree.

This code snippet will help you keeping the folding state:

(defun org-try-merging-last-clock-out ()
  "Try to merge the latest clock-out, and catch the error if the discrepancy is not zero."
  (org-back-to-heading) ;; Move to heading line to check if folded
  (let (folded (invisible-p (point-at-eol))) ; is subtree folded?
    (save-restriction
      (save-excursion
    (org-narrow-to-subtree)
    (when folded (org-cycle))    ; cycle if folded
    ;; do whatever you need
    (goto-char (point-max))
    (insert "whatever")
    ;; end of task
    (org-back-to-heading)
    (when folded (org-cycle))   ; cycle again if it was folded
)))
  • 1
    Indeed, the problem was calling org-cycle inside the LOGBOOK. I solved it by calling (outline-hide-subtree) after performing the operations. Calling org-narrow-to-subtree before my operations and (goto-char (point-min)), (org-cycle), and (widen) does not maintain the same visibility if the starting point is the headline with properties such as SCHEDULED and CLOSED showing below it. Because it doesn't maintain visibility, I'm not yet accepting the answer. – miguelmorin Oct 6 at 16:22
  • @miguelmorin I've added a code example based on yours to show how to keep subtree folding state, hope it helps.Apologies for the delay, I'm rather busy this week. – Muihlinn Oct 8 at 19:37
  • No worries, and thanks! That new code works well if I do back-to-heading before setting folded because org-clock-out moves point. I edited the answer, and will accept it and delete the comments if the edit is accepted. – miguelmorin Oct 9 at 17:44
  • I was trying to put up an example of operation. The point of org-narrow-to-subtree is to restrict operation to current subtree avoiding searching go beyond limits. For your particular case, calling org-back-to-heading before doing anything makes sense, if not I'd check the return value of org-at-heading-p before moving the point. – Muihlinn Oct 9 at 17:54
  • Thanks! In the meantime, another poster added an answer with exactly what I was looking for, which is shorter, and also maintains the visibility of the drawers in the heading, so I will accept that one instead. – miguelmorin Oct 10 at 11:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.