Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transclusion of last entry of subtree only #247

Open
ddhendriks opened this issue May 14, 2024 · 6 comments
Open

Transclusion of last entry of subtree only #247

ddhendriks opened this issue May 14, 2024 · 6 comments

Comments

@ddhendriks
Copy link

LS,

My usecase is a technical report/overview of projects and I would like to transclude the last subtree of a particular tree. For each project I keep a journal and in a particular overview node I want to automatically transclude all the most recent project journal-entries. I have looked around in the documentation, but it did not become entirely clear to me whether this is actually possible and how I would do this.

MWE:

when pointing to a tree

* journal
** 2024-05-13
example
** 2024-05-14
example 2

I want the transclusion to show me only

** 2024-05-14
example 2

optionally without the subheader

Is this possible? sounds like it fits the usecase listed in the docs.

Kind regards,

David

@akashpal-21
Copy link

akashpal-21 commented May 14, 2024

One trivial way I could suggest is using the #+transclude: [[file:<filepath>::*2024-05-14]] :only-contents

@ddhendriks
Copy link
Author

Hi @akashpal-21 ,

Thank you for your suggestion, but I am looking for a solution that dynamically finds the last entry (perhaps triggered by some refresh, turning org-transclude-mode on and off, or something).

For example, if I update my above example file to

* journal
** 2024-05-13
example
** 2024-05-14
example 2
** 2024-15-21
example 3

I want the transclude to pick that up automatically and display

** 2024-15-21
example 3

I have attempted some solutions with custom functions that find the last subtree in a given heading, and then generate the entire transclude statement (including the last header, hardcoded), but that still required a lot of manual work (i.e. removing the previously generated ones).

I think this has to be some function within org-transclude to work nicely, but i may be wrong here.

@nobiot
Copy link
Owner

nobiot commented May 21, 2024

@ddhendriks

I think this has to be some function within org-transclude to work nicely, but i may be wrong here.

I think you are right. We don't have an easy way within Org-transclusion at the moment as far as I remember/tried. What's the function you use to dynamically find the last tree in a given heading?

I don't think I can do much until mid-late June, but I am considering something that may help with this.

@ddhendriks
Copy link
Author

ddhendriks commented May 22, 2024

hi @nobiot

With the help of chatGPT I created a function that given a header, finds the last subheader (optionally given a maximum allowed depth). A second function then builds up the transclude statement. The two functions are as follows

(defun my/find-last-entry-in-subtree (file subtree-heading &optional max-depth)
  "Find the last entry in the subtree under SUBTREE-HEADING from FILE.
Print and return the heading of the last entry. If MAX-DEPTH is provided,
limit the search to that depth."
  (let ((last-heading nil)
        (max-depth (or max-depth most-positive-fixnum)))
    (with-current-buffer (find-file-noselect file)
      (goto-char (point-min))
      (if (re-search-forward (format "^\\*+ %s" (regexp-quote subtree-heading)) nil t)
          (let ((start-level (org-current-level)))
            (message "Subtree '%s' found at level %d." subtree-heading start-level)
            (forward-line)  ; Move to the next line to start checking for headings
            (while (and (re-search-forward org-heading-regexp nil t)
                        (> (org-current-level) start-level))  ; Ensure we stay within the subtree
              (let ((current-level (org-current-level)))
                (when (and (<= current-level (+ start-level max-depth))
                           (> current-level start-level))
                  (setq last-heading (org-element-property :raw-value (org-element-at-point)))
                  (message "Updated last heading to: %s at level %d" last-heading current-level))))
            (if last-heading
                (message "Last entry heading within depth %d: %s" max-depth last-heading)
              (message "No entry found within depth %d under subtree '%s'." max-depth subtree-heading)))
        (message "Subtree '%s' not found." subtree-heading)))
    last-heading))

(defun my/org-transclude-last-entry (file subtree-heading &optional max-depth)
  "Transclude the last entry of a subtree under SUBTREE-HEADING from FILE.
If MAX-DEPTH is provided, limit the search to that depth."
  (let ((last-heading (my/find-last-entry-in-subtree file subtree-heading max-depth)))
    (if last-heading
        (let ((transclude-command (format "#+transclude: [[file:%s::*%s]]\n" file last-heading)))
          (message "Transclude command: %s" transclude-command)
          (insert transclude-command))
      (message "No last entry found in subtree '%s' within depth %d." subtree-heading max-depth))))

I suppose that first function could be used somewhere in org-transclusion.

I should say, my lisp knowledge is little and there may be things wrong with this function, so beware using it blindly.

@nobiot
Copy link
Owner

nobiot commented May 22, 2024

@ddhendriks

What I had in mind and tested a little is simple. I assume that the structure of the journal in your example above is fixed -- ie the date entry is always level 2.

Then you can simply evaluate this function and add a custom org link.

(defun my/org-last-entry (path arg)
  (org-link-open-as-file path arg)
  (goto-char (car (last (org-map-entries #'point "level=2" 'file)))))

(org-link-set-parameters "last-entry" :follow #'my/org-last-entry)

It enables this last-entry custom link, which navigate to the "last entry" of the tree in FILE.org.

[[last-entry:FILE.org]]

I wanted to create a new wrapper function within Org-transclusion that can transclude an arbitary link like this. The idea is, if the link can navigate to the target, then it can also be turned into a transclusion by simply adding #+transclude keyword.

Would any part of the idea above work for your case?

I am not yet certain if enabling transclusion for any arbitrary link will actually work technically -- but this is something I am thinking of trying in late June (in addition to continuation of some bug fixes).

@ddhendriks
Copy link
Author

Hi @nobiot, apologies for the late reply. Thank you for looking into this a bit already and thinking along.

I assume that the structure of the journal in your #247 (comment) is fixed -- ie the date entry is always level 2.

the situation is not entirely like this but:

  • in a given file/node the depth of the journal entries are consistently the same, but not necessarily at a depth of 2 relative to the root of the file.
  • a file containing a tree with journal entries can also contain other text

Given the above considerations, if we would be able to:

  • provide a header in which to look for the entries
  • provide a depth of the entries.

The code I shared did more or less that.

In your example,

[[last-entry:FILE.org]]

it doesnt look like it's easy to provide additional configurations, whereas there already exists some things that look relevant and maybe have a better way to provide these configurations?

#+transclude: [[file:path/to/file.org::*Headline]] :level 2

if we could just add something like :latest-only to this then that would be a clean syntax and flexible.

I have no clue if there is anything preventing something like this, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants