nobiot / org-transclusion

Emacs package to enable transclusion with Org Mode
https://nobiot.github.io/org-transclusion/
GNU General Public License v3.0
902 stars 43 forks source link

get the line numbers from the property values #248

Open sazam0 opened 1 month ago

sazam0 commented 1 month ago

Hi, I am wondering if the following is possible:

* example heading
:PROPERTIES:
:LINES:    3-5
:END:

#+transclude: [[file:test.txt]] :lines (org-entry-get nil "LINES")

Thank you.

nobiot commented 1 month ago

I suggest you try it and see if it works. My guess is it does not…

sazam0 commented 1 month ago

I have, it ignores the lines: .... and transcludes the whole file. I am asking if is there any way (emacs hacks) possible?

Please excuse me, if I am wrong, I am thinking a pre-hook that will translate to the original format.

Thank you for your time.

akashpal-21 commented 3 weeks ago

@sazam0 Hi - I was just passing by and noticed your request -

I think it would be possible - but it is very dangerous and shouldn't be done - org takes lisp code execution very seriously - a malicious actor may exploit it. It would add some complexity but it can be done, all org-transclusion does is it establishes a protocol to dynamically yank contents from another file. But my intuition is, a lot of consideration must be taken before enabling such code execution - we would have to over-ride the security measures put by org.

akashpal-21 commented 3 weeks ago
* h1
:PROPERTIES:
:LINES: 8-10
:END:

#+begin_src elisp
(insert (format "\n#+transclude: \[\[file:test.txt\]\] :lines %s" (org-entry-get (point) "LINES")))
#+end_src

Try something like this

sazam0 commented 3 days ago

Hi,

@akashpal-21 Thank you for the solution, here I tried to keep the same syntax, otherwise so many regular expressions make the editing more painful.

The following code does what I wanted. As a noob, I do not know if it raises any security issues. However, when the transclusion is removed it returns the line numbers 3-5, not the property name. If you could please suggest which function to look at that would be helpful.

Note, that my target use case is for source codes, so I only looked at org-transclusion-src-lines.el

+transclude: [[file:test.py]] :lines #PLINES

(defun transclusion-get-property-line-numbers (fn-name string)
    (if (string-match ":lines +\\(\"?#\\w*\"?\\)" string)
      (let*(
            (str (match-string 1 string))
            (property-name (substring str 1 (length str)))
            (line-number (org-entry-get (point) property-name))
            (new-string (string-replace str line-number string))
            )
      (funcall fn-name new-string)
        )
      (funcall fn-name string)
      )

)

(advice-add 'org-transclusion-keyword-value-lines :around #'transclusion-get-property-line-numbers)
akashpal-21 commented 3 days ago

@sazam0

study this function

(defun org-transclusion-keyword-plist-to-string-src-lines (plist)
  "Convert a keyword PLIST to a string.
This function is meant to be used as an extension for function
`org-transclusion-keyword-plist-to-string'.  Add it to the
abnormal hook
`org-transclusion-keyword-plist-to-string-functions'."
  (let ((lines (plist-get plist :lines))
        (src (plist-get plist :src))
        (rest (plist-get plist :rest))
        (end (plist-get plist :end))
        (thing-at-point (plist-get plist :thing-at-point)))
    (concat
     (when lines (format ":lines %s" lines))
     (when src (format " :src %s" src))
     (when rest (format " :rest \"%s\"" rest))
     (when end (format " :end \"%s\"" end))
     (when thing-at-point (format " %s" thing-at-point)))))

This function is responsible for placing the :lines in the #+transclude when you remove the transclusion content. If you want such that the absolute line numbers are not returned but whatever you placed when doing the transclusion you have to modify the function in some way.

I am sorry - I haven't coded in elisp for some time because of want of time and accumulation of other responsibilities, but I would if I were modify your advice #'transclusion-get-property-line-numbers such that the plist is properly prepared and create another advice to catch it and put it back in.

Please try to see if you can come up with a way to do this - if not, ping me - I will try to create a solution for you.

sazam0 commented 2 days ago

@akashpal-21 , Thank you for your guideline. The following code works for me:

(setq property-key-file  "PFILE")
(setq property-key-line  "PLINES")

(defun transclusion-get-property-line-numbers(fn-name string)
  "
   around advice function for 'org-transclusion-keyword-value-lines'
   translate the ':lines #<property key>' as line numbers for org-transclusion
  "
  (let*(
       (line-txt (format ":lines #%s" property-key-line))
       (line-number (org-entry-get (point) property-key-line))
       (msg-error (format "'%s' property is required for transclusion with '%s' " property-key-line line-txt))
       )
    (progn
       (if (string-match line-txt string)
          (if (stringp line-number)
            (let*(
                    (line-number-txt (format ":lines %s" line-number))
                    (new-string (string-replace line-txt line-number-txt string)))
                (funcall fn-name new-string))
            (user-error (format "%s" msg-error)))
            (funcall fn-name string)
            ))
))
(advice-add 'org-transclusion-keyword-value-lines :around #'transclusion-get-property-line-numbers)

(defun transclusion-detach-src-lines(fn-name plist)
  "
   around advice function for 'org-transclusion-keyword-plist-to-string-src-lines '
   reformat the ':lines' keys for as line numbers for org-transclusion
  "
  (let*(
        (filename (org-entry-get (point) property-key-file))
        (link (plist-get plist :link))
        (link-path (substring link  2 (- (length link) 2)))
        (plines (org-entry-get (point) property-key-line))
        (lines (plist-get plist :lines)))
        (if (and (stringp filename) (stringp plines) (string= plines lines) (string-match filename link-path))
            (funcall fn-name (plist-put plist :lines (format "#%s" property-key-line)))
            (funcall fn-name plist))
))

(advice-add 'org-transclusion-keyword-plist-to-string-src-lines :around #'transclusion-detach-src-lines)

org file: