emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Thorsten Jolitz <tjolitz@gmail.com>
To: emacs-orgmode@gnu.org
Subject: Re: org-export: how to copy the parsed tree?
Date: Sat, 01 Mar 2014 11:21:37 +0100	[thread overview]
Message-ID: <878usu43ta.fsf@gmail.com> (raw)
In-Reply-To: 87r46m489o.fsf@gmail.com

Thorsten Jolitz <tjolitz@gmail.com> writes:

> Vitalie Spinu <spinuvit@gmail.com> writes:
>
>> Is there an easy way to copy org sub-tree in :filter-parse-tree?
>>
>> The structure of the parsed tree is somewhat complicated with recursive
>> references to parents in multiple places. So, copy-tree infloops.
>
> You will get a better answer most likely, but with (org-no-properties
> contents) you can get the original Org-syntax of a parse-tree element,
> e.g. applied to all sections (untested):
>
> ,----------------------------------------------------------------
> | (defun org-myexp-section (section contents info)
> |   "Transcode SECTION element into myexp syntax.
> | CONTENTS is its contents, as a string or nil. INFO is ignored."
> |   (if (and contents (stringp contents) (> (length contents) 0))
> |       (format "%S"
> |               (org-no-properties contents))
> |     ""))
> `----------------------------------------------------------------

I probably misunderstood your question. I don't know if there is an easy
way to copy a subtree, but I do know about the problems with the
recursive references, so I found a way to replace them with simple
numeric :org-elem-id and :parent-id attributes:

,--------------------------------------------
| :filters-alist '((:filter-parse-tree
|     . org-myexp-filter-parse-tree-function)
`--------------------------------------------

#+begin_src emacs-lisp
(defun org-myexp-filter-parse-tree-function (tree backend info)
  "Filter complete parsed TREE ignoring BACKEND and INFO."
   ;; optional
   (org-myexp-add-children
    (org-myexp-add-parent-ids
     (org-myexp-add-ids tree backend info)
     backend info)
    backend info))


(defun org-myexp-add-ids (tree backend info)
  "Add ':org-elem-id' property to each element of parse TREE."
  (let ((counter 1)
        (structure 1))
    (org-element-map tree myexp-default-map-types
      (lambda (--elem)
          (org-element-put-property --elem :org-elem-id counter)
          (setq counter (1+ counter))
          (and (eq (org-element-type --elem) 'plain-list)
               (org-element-put-property --elem :structure-id structure)
               (setq structure (1+ structure))))))
  tree)

(defun org-myexp--collect-children (tree)
  "Return alist with '(org-elem-id . parent-id)' pairs.
The data is collected from parse TREE."
  (let (child-lst)
    (org-element-map tree 'headline
      (lambda (--headline)
        (push (cons (org-element-property :org-elem-id --headline)
                    (org-element-property :parent-id --headline))
              child-lst)))
    child-lst))

;; optional
(defun org-myexp-add-children (tree backend info)
  "Add `:children' property to each headline in parse TREE.
Assumes that all headlines are tagged with an `:org-elem-id' property
and that the circular-list read-syntax of the `:parent' attribute
has been replaced with simple integer values (the :org-elem-id of the
elements parent)."
  (let ((pairs (org-myexp--collect-children tree)))
    (org-element-map tree 'headline
      (lambda (--elem)
        (org-element-put-property
         --elem :children
         (reverse
          (delq nil
                (mapcar
                 (lambda (--pair)
                   (and (eq (cdr --pair)
                            (org-element-property :org-elem-id --elem))
                        (car --pair)))
                 pairs)))))))
  tree)

(defun org-myexp-add-parent-ids (tree backend info)
  "Add `:parent-id' and `:parent-structure-id' to parse-tree TREE."
  (org-element-map tree myexp-all-map-types
    (lambda (--elem)
      (let ((par (org-element-property :parent --elem)))
        (and (eq (org-element-type --elem) 'item)
             (eq (org-element-type par) 'plain-list)
             (org-element-put-property
              --elem :parent-structure-id
              (org-element-property :structure-id par)))
        (org-element-put-property
         --elem :parent-id
         (if (eq (org-element-type par) 'org-data)
             0
           (org-element-property :org-elem-id par)))))
    nil nil nil 'WITH-AFFILIATED)
  tree)
#+end_src

Then in the transcode functions I build the parse-tree again without
the circular :parent attribut, but with the information contained in it
now contained in :org-elem-id and :parent-id:

#+begin_src emacs-lisp
(defun org-myexp-headline (headline contents info)
  "Transcode HEADLINE element into myexp syntax.
CONTENTS is its contents, as a string or nil.  INFO is ignored."
  (let ((props org-myexp-node-properties))
    (setq org-myexp-node-properties nil)
    (format "(headline %S %s) "
            (list
             'org-elem-id
             (org-element-property :org-elem-id headline)
             'parent-id
             (org-element-property :parent-id headline)
             [...])
            (org-no-properties contents))))
#+end_src

Not really an easy way, and I needed it for a very special purpose so it
might not fit your needs. However, this can be used to convert the
circular parse-tree to a non-circular nested list that all the usual
list processing functions can digest.

But I must say that I simply transformed all the SECTIONS to Org-syntax
(with no circular refs at all), so I ended up with only a handful
transcode functions.

Doing the above on the whole parse-tree with all its circular references
might be a tedious exercise ...

-- 
cheers,
Thorsten

  reply	other threads:[~2014-03-01 10:21 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-01  1:20 org-export: how to copy the parsed tree? Vitalie Spinu
2014-03-01  8:45 ` Thorsten Jolitz
2014-03-01 10:21   ` Thorsten Jolitz [this message]
2014-03-01 11:36 ` Nicolas Goaziou
2014-03-01 18:24   ` Vitalie Spinu
2014-03-01 21:02     ` Nicolas Goaziou
2014-03-01 21:21       ` Vitalie Spinu
2014-03-02  9:13         ` Nicolas Goaziou

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=878usu43ta.fsf@gmail.com \
    --to=tjolitz@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    /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
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).