From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp11.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms9.migadu.com with LMTPS id /NyqApHcdWR4GwAASxT56A (envelope-from ) for ; Tue, 30 May 2023 13:22:57 +0200 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp11.migadu.com with LMTPS id mHOsAZHcdWQC0AAA9RJhRA (envelope-from ) for ; Tue, 30 May 2023 13:22:57 +0200 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 46AA42C892 for ; Tue, 30 May 2023 13:22:56 +0200 (CEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1q3xQR-0007xj-LV; Tue, 30 May 2023 07:22:03 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q3xQM-0007xW-Kh for emacs-orgmode@gnu.org; Tue, 30 May 2023 07:21:59 -0400 Received: from mout01.posteo.de ([185.67.36.65]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1q3xQH-0005Cu-Ia for emacs-orgmode@gnu.org; Tue, 30 May 2023 07:21:58 -0400 Received: from submission (posteo.de [185.67.36.169]) by mout01.posteo.de (Postfix) with ESMTPS id 983F1240028 for ; Tue, 30 May 2023 13:21:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1685445708; bh=pZPjOK/kj//YfDcXKzQunCFLAXGhDLow2MH+rh2Bn38=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:From; b=YwYidgSVJ6ZNydnAYderDYuaGjMj9ohKxztkPYf9ZA/HkY9VMRgr7dUvxRxyzI5E+ pHrzqJ0NrTjuk77Sm5/nKtu4zVKRwPzBnfPD8iJt/au1HaydWo/lpNXuLZMoHK5ihJ q/xwhRkE9vXy1jJskTCXvfKisA9Xmsj5JsYSFWbWvjaEbBr4lmYWH7LEj4J9UavOSq UWImqWMtaC7IEVIicIS3EZbs9lpEQ3NBmjVzw5SrmaSIxOsD0eMZr1CGvqEhH/Yp+C i2Z/5pLPfHOksrvnbsFRbe3kKrACG8P+58mlCWm1DeQ4AovEOeq9IstCCD7zb9izMh l+6vEvJR5DN1g== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4QVqjC2XGlz6twD; Tue, 30 May 2023 13:21:35 +0200 (CEST) From: Ihor Radchenko To: Ihor Radchenko Cc: emacs-orgmode@gnu.org Subject: [RFC] Refactoring org-element API (was: [DISCUSSION] Refactoring fontification system) In-Reply-To: <87k09ycc7n.fsf@localhost> References: <87ee7c9quk.fsf@localhost> <87k09ycc7n.fsf@localhost> Date: Tue, 30 May 2023 11:25:46 +0000 Message-ID: <874jnudps5.fsf@localhost> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=185.67.36.65; envelope-from=yantar92@posteo.net; helo=mout01.posteo.de X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: emacs-orgmode-bounces+larch=yhetil.org@gnu.org X-Migadu-Country: US X-Migadu-Flow: FLOW_IN ARC-Seal: i=1; s=key1; d=yhetil.org; t=1685445776; a=rsa-sha256; cv=none; b=eH7C+y+cGKt0UehOt8FybMDpW6C1vSjdYECQ6p7kq5asQ4ivSmQDadUAo/GwbHAQNLHcRO VbcazXIrvzyD5ZusET1JazaOh3oui2Y7M3IqzDWhaaE8QYaBbVeuWnOflRL9eUr8nS/X0T qssusJ6n5d3dcH5TQVzEjskW6zEoVepeEean4E+Mk0k3vvAGLjzJpvvezhbysbr9qGeOsS 6i+pJ44HB4hYqdiSB49zOKZ9qCTiD2Mc2tkZLgTjoLH/u9ydY5QR9AgVXSqnxPttaSp3gq phP4La7Lp0MUAFaq+OLDDoGSjUqaLvuTIajR4OUNhWqiWKaJKR3+oydZXLWFbA== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=posteo.net header.s=2017 header.b=YwYidgSV; dmarc=pass (policy=none) header.from=posteo.net; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1685445776; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=xzOwW7SD0fHQbdrczXt26UklzwTAF98qtL5Q086nlNQ=; b=W7hjQnWBqhkQCPbcPutbL5omsXrWL6nA3JUSodeboDFzQkVUsN74CnC13brxweq0YKZF6e V83q1kCknxvDbBrJEmH8pTBVyrlV9ufoLh+pLPHSu9lqhQQHFg48lUvi1TpXLt3345FFY2 2O90kbnnr5qKyB7dtYFsS0f+WIzfnKL26egPgpkr5uHBPt9dZ+VEY0edUKViZl+Z1rRQBw Ro87sH/Cd9MtIPht3Lks6K6OFHL1DMe6wJAR3E+vtlth877BbUsuuKeuplmJJzJVe61R07 fW/hXJHllYTDv9Sht8ektiMwsCZ1swgsst62e/FYudVpECIQHLHsU8TInf9Egg== X-Migadu-Spam-Score: -9.41 X-Spam-Score: -9.41 X-Migadu-Queue-Id: 46AA42C892 X-Migadu-Scanner: scn0.migadu.com Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=posteo.net header.s=2017 header.b=YwYidgSV; dmarc=pass (policy=none) header.from=posteo.net; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-TUID: UXzLk6ozH/Ww --=-=-= Content-Type: text/plain Ihor Radchenko writes: > Ihor Radchenko writes: > >> Instead of fontifying elements individually via regexps, we can leverage >> org-element-map, org-element-parse-buffer, org-element-cache, and >> jit-lock-mode. Each type of Org element/object can be assigned with a >> fontification function accepting a single argument - the element datum. > > I have been working on the new fontification library for the last > several months and I have noticed several confusing things in the > current fontification settings. It has been a while since the last update on the fontification... for a reason. As the fontification should be very tightly optimized to avoid Emacs freezes, I stumbled upon a need to improve the performance of Org parser further than we already have. This triggered a number of significant changes in listp/org-element.el. So many that the current logic of the library becomes a mess. In order not to turn org-element into another org-agenda, I am proposing to factor out Org syntax tree API into a separate file org-element-ast.el and add a number of breaking changes how the syntax tree is structured. The most important changes are the following: 1. Frequently used element properties will no longer be stored directly in the property list. Instead, they will be placed inside a special vector that is much faster to access. `org-element-property' and other accessor functions are changed accordingly to inline the property queries into `aref' calls, when possible. This is a major breaking change. 2. Org parser will now be able to parse elements partially, with some parts of the parser executed later, only when necessary. The downside is relying upon the original buffer to be live even after parsing. This is also a major breaking change. 3. The order of multiple affiliated keywords in Org parse tree will be reversed. The main purpose here is to avoid special cases when fine details of Org syntax had to be accounted for when traversing Org parse trees. This is a breaking change. 4. Org cache will be available even when `org-element-use-cache' is non-nil. This is not a breaking change and simplifies Org code greatly without compromising performance. 5. The usage of regular expressions is by Org parser is now tightly optimized. See the discussion in https://debbugs.gnu.org/cgi/bugreport.cgi?bug=63225 This is also not a breaking change. 6. Memory footprint is reduced for Org AST. This is achieved using shared string objects in Org parser. With low probability, this might cause problems if third-party code modifies these string objects by side effect. This refactoring is large, spanning >80 commits. The full commit log can be found at https://git.sr.ht/~yantar92/org-mode/log/feature/org-element-ast-tidy Here, I am attaching ORG-NEWS diff, summarizing important changes. I am also adding the commentary section of org-element-ast.el with more details about the new syntax tree structure and about the new concept of deferred parsed values. I am sure that I missed things, so comments are welcome. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=ORG-NEWS.diff diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index ddf1e9110..396935283 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -13,6 +13,187 @@ Please send Org bug reports to mailto:emacs-orgmode@gnu.org. * Version 9.7 (not released yet) ** Important announcements and breaking changes +*** Major changes and additions to Org API +**** New term: "syntax node" + +To reduce confusion with "element" referring to both "syntax element" +and "element/object" class, we now prefer using "syntax node" when +referring to generic Org syntax elements. "Elements" and "objects" +now refer to different syntax node classes of paragraph-like nodes and +markup-like nodes. + +**** New element type ~anonymous~ + +Secondary strings can now be recognized as ~anonymous~ type to +distinguish from non-elements. With a new optional argument for +~org-element-type~ will return ~anonymous~ for secondary strings +instead of nil. + +The new element type can be used in ~org-element-lineage~, +~org-element-map~, and other functions that filter by element type. +**** Internal structure of Org parse tree has been changed + +The code relying upon the previously used =(TYPE PROPERTIES-PLIST CONTENTS-LIST)= +structure may no longer work. Please use ~org-element-create~, +~org-element-property~, and other Org element API functions to work +with Org syntax trees. + +Some syntax node properties are no longer stored as property list elements. +Instead, they are kept in a special vector value of a new +=:standard-properties= property. This is done to improve performance. + +Properties and their values can now be deferred to avoid overheads when +parsing. They are calculated lazily, when the value/property is +requested by getters. + +New special property =:secondary= is used internally to record which +properties store secondary objects. + +New special property =:deferred= is used to keep information how to +calculate property names lazily. + +See the commentary in =lisp/org-element-ast.el= for more details. + +**** Multiple affiliated keyword values are now stored in the order they appear in buffer + +Previously, + +: #+caption: foo +: #+caption: bar +: Paragraph + +would have its =:caption= property set to ~(("bar") ("foo"))~ in reverse order. + +Now, the order is not reversed: ~(("foo") ("bar"))~. + +**** Some property values may now be calculated lazily and require original Org buffer to be live + +~org-element-at-point~, ~org-element-context~, and +~org-element-at-point-no-context~ may now not calculate all the +property values at the call time. Instead, the calculation will be +deferred until ~org-element-property~ or the equivalent getter +function is called. The property names may not all be calculated as +well. + +It may often be necessary to have the original Org buffer open when +resolving the deferred values. + +One can ensure that all the deferred values are resolved using new +function ~org-element-resolve-deferred~ and new optional argument for +~org-element-property~. + +~org-element-parse-buffer~ and ~org-element-parse-secondary-string~ +will resolve all the deferred values by default. No adjustment is +needed for their users. + +**** New API functions and macros +***** New property accessors and setters + +New functions to retrieve and set (via ~setf~) commonly used element properties: +- =:begin= :: ~org-element-begin~ +- =:end= :: ~org-element-end~ +- =:contents-begin= :: ~org-element-contents-begin~ +- =:contents-end= :: ~org-element-contents-end~ +- =:contents-post-affiliated= :: ~org-element-post-affiliated~ +- =:contents-post-blank= :: ~org-element-post-blank~ +- =:parent= :: ~org-element-parent~ + +***** New macro ~org-element-with-enabled-cache~ + +The macro arranges the element cache to be active during =BODY= execution. +When cache is enabled, the macro is identical to ~progn~. When cache +is disabled, the macro arranges a new fresh cache that is discarded +upon completion of =BODY=. + +***** New function ~org-element-property-1~ + +This function is like ~org-element-property~ but does not try to +resolve deferred properties. + +~org-element-property-1~ can be used with ~setf~. + +***** New function ~org-element-put-property-2~ + +Like ~org-element-put-property~, but the argument list is changed to have +=NODE= as the last argument. Useful with threading macros like +~thread-last~. + +***** New function ~org-element-properties-resolve~ + +This function resolves all the deferred values in a =NODE=, modifying +the =NODE= for side effect. + +***** New functions ~org-element-properties-map~ and ~org-element-properties-mapc~ + +New functions to map over =NODE= properties. + +***** New function ~org-element-ast-map~ + +This is a more general equivalent of ~org-element-map~. It allows +more precise control over recursion into secondary strings. + +***** New function ~org-element-lineage-map~ + +Traverse syntax tree ancestor list, applying arbitrary function to +each ancestor. + +***** New function ~org-element-property-inherited~ + +Like ~org-element-property~, but can be used to retrieve and combine +multiple different properties for a given =NODE= and its parents. + +**** ~org-element-cache-map~ can now be used even when element cache is disabled +**** =org-element= API functions and macros can now accept syntax elements as =POM= argument + +The following functions are updated: +- ~org-agenda-entry-get-agenda-timestamp~ +- ~org-element-at-point~ +- ~org-is-habit-p~ +- ~org-id-get~ +- ~org-with-point-at~ +- ~org-entry-properties~ +- ~org-entry-get~ +- ~org-entry-delete~ +- ~org-entry-add-to-multivalued-property~ +- ~org-entry-remove-from-multivalued-property~ +- ~org-entry-member-in-multivalued-property~ +- ~org-entry-put-multivalued-property~ +- ~org-entry-get-with-inheritance~ +- ~org-entry-put~ +- ~org-read-property-value~ +- ~org-property-get-allowed-values~ + +**** ~org-element-map~ now traverses main value in dual keywords before the secondary value + +The traverse order for dual keywords is reversed. The main value is +now traversed first, followed by the secondary value. + +**** Org parse tree is now non-printable + +Org parser now assigns a new property =:buffer= that holds +non-printable buffer object. This makes syntax tree non-printable. +Using ~print~/~read~ is no longer safe. + +**** Some Org API functions no longer preserve match data + +~org-element-at-point~, ~org-element-context~, ~org-get-category~, ~org-get-tags~ + +The relevant function docstrings now explicitly mention that match +data may be modified. +**** ~org-element-create~ now treats a single ~anonymous~ =CHILDREN= argument as a list of child nodes + +When =CHILDREN= is a single anonymous node, use its contents as children +nodes. This way, + +: (org-element-create 'section nil (org-element-contents node)) + +will yield expected results with contents of another node adopted into +a newly created one. + +Previously, one had to use + +: (apply #'org-element-create 'section nil (org-element-contents node)) + *** "Priority" used to sort items in agenda is renamed to "urgency" Previously, ~priority-up~ and ~priority-down~ in @@ -225,7 +406,64 @@ editing with Emacs while a ~:session~ block executes. When ~org-return-follows-link~ is non-nil and cursor is over an org-cite citation, ~org-return~ will call ~org-open-at-point~. +** New functions and changes in function arguments +*** =TYPES= argument in ~org-element-lineage~ can now be a symbol + +When =TYPES= is symbol, only check syntax nodes of that type. + +*** New optional argument =KEEP-CONTENTS= for ~org-element-copy~ + +With the new argument, the contents is copied recursively. + +*** ~org-element-property~ can now be used with ~setf~ +*** New optional arguments for ~org-element-property~ + +The value of the new optional argument =DFLT= is returned if the +property with given name is not present. Same as =DEFAULT= argument +for ~alist-get~. + +New optional argument =FORCE-UNDEFER= modifies the =NODE=, storing the +resolved deferred values. + +*** New optional argument =NO-UNDEFER= in ~org-element-map~ and changed argument conventions + +New optional argument =NO-UNDEFER=, when non-nil, will make +~org-element-map~ keep deferred secondary string values in their raw form. + +=TYPES= argument can now be set to ~t~. This will match all the +syntax nodes when traversing the tree. + +~FUN~ can now be a lisp form that will be evaluated with symbol ~node~ +assigned to the current syntax node. + +~FUN~ can now throw ~:org-element-skip~ signal to skip recursing into +current element children and secondary strings. + +*** New optional argument =KEEP-DEFERRED= in ~org-element-parse-buffer~ + +When non-nil, the deferred values and properties will not be resolved. + +*** New optional argument =ANONYMOUS= for ~org-element-type~ + +When the new argument is non-nil, return symbol ~anonymous~ for anonymous elements. + +*** ~org-element-adopt-elements~ is renamed to ~org-element-adopt~ + +The old name is kept as an alias. The new name creates less confusion +as the function can also act on objects. + +*** ~org-element-extract-element~ is renamed to ~org-element-extract~ + +The old name is kept as an alias. The new name creates less confusion +as the function can also act on objects. + +*** ~org-element-set-element~ is renamed to ~org-element-set~ + +The old name is kept as an alias. The new name creates less confusion +as the function can also act on objects. +*** ~org-export-get-parent~ is renamed to ~org-element-parent~ and moved to =lisp/org-element.el= +*** ~org-export-get-parent-element~ is renamed to ~org-element-parent-element~ and moved to =lisp/org-element.el= ** Miscellaneous *** =org-crypt.el= now applies initial visibility settings to decrypted entries --=-=-= Content-Type: text/plain ;;; org-element-ast.el --- Abstract syntax tree for Org -*- lexical-binding: t; -*- ;; ... ;; This file implements Org abstract syntax tree (AST) data structure. ;; ;; Only the most generic aspect of the syntax tree are considered ;; below. The fine details of Org syntax are implemented elsewhere. ;; ;; Org AST is composed of nested syntax nodes. ;; Within actual Org syntax, the nodes can be either headings, ;; elements, or objects. However, historically, we often call syntax ;; nodes simply "elements", unless the context requires clarification ;; about the node type. In particular, many functions below will have ;; naming pattern `org-element-X', implying `org-element-node-X' -- ;; they will apply to all the node types, not just to elements. ;; ;; 1. Syntax nodes ;; ------------------ ;; Each Org syntax node can be represented as a string or list. ;; ;; The main node representation follows the pattern ;; (TYPE PROPERTIES CONTENTS), where ;; TYPE is a symbol describing the node type. ;; PROPERTIES is the property list attached to it. ;; CONTENTS is a list of child syntax nodes contained within the ;; current node, when applicable. ;; ;;; For example, "*bold text* " node can be represented as ;; ;; (bold (:begin 1 :end 14 :post-blank 2 ...) "bold text") ;; ;; TYPE can be any symbol, including symbol not explicitly defined by ;; Org syntax. If TYPE is not a part of the syntax, the syntax ;; node is called "pseudo element/object", but otherwise considered a ;; valid part of Org syntax tree. Search "Pseudo objects and ;; elements" in lisp/ox-latex.el for an example of using pseudo ;; elements. ;; ;; PROPERTIES is a property list (:property1 value1 :property2 value2 ...) ;; holding properties and value. ;; ;; `:standard-properties', `:parent', `:deferred', and `:secondary' ;; properties are treated specially in the code below. ;; ;; `:standard-properties' holds an array with ;; `org-element--standard-properties' values, in the same order. The ;; values in the array have priority over the same properties ;; specified in the property list. You should not rely on the value ;; of `org-element--standard-propreties' in the code. ;; `:standard-properties' may or may not be actually present in ;; PROPERTIES. It is mostly used to speed up property access in ;; performance-critical code, as most of the code requesting property ;; values by constant name is inlined. ;; ;; The previous example can also be presented in more compact form as: ;; ;; (bold (:standard-properties [1 10 ... 2 ...]) "bold text") ;; ;; Using an array allows faster access to frequently used properties. ;; ;; `:parent' holds the containing node, for a child node within the ;; AST. It may or may not be present in PROPERTIES. ;; ;; `:secondary' holds a list of properties that may contain extra AST ;; nodes, in addition to the node contents. ;; ;; `deferred' property describes how to update not-yet-calculated ;; properties on request. ;; ;; ;; Syntax node can also be represented by a string. Strings always ;; represent syntax node of `plain-text' type with contents being nil ;; and properties represented as string properties at position 0. ;; `:standard-properties' are not considered for `plain-text' nodes as ;; `plain-text' nodes tend to hold much fewer properties. ;; ;; In the above example, `plain-text' node "bold text" is more ;; accurately represented as ;; ;; #("bold text" 0 9 (:parent (bold ...))) ;; ;; with :parent property value pointing back to the containing `bold' ;; node. ;; ;; `anonymous' syntax node is represented as a list with `car' ;; containing another syntax node. Such node has nil type, does not ;; have properties, and its contents is a list of the contained syntax ;; node. `:parent' property of the contained nodes point back to the ;; list itself, except when `anonymous' node holds secondary value ;; (see below), in which case the `:parent' property is set to be the ;; containing node in the AST. ;; ;; Any node representation other then described above is not ;; considered as Org syntax node. ;; ;; 2. Deferred values ;; ------------------ ;; Sometimes, it is computationally expensive or even not possible to ;; calculate property values when creating an AST node. The value ;; calculation can be deferred to the time the value is requested. ;; ;; Property values and contained nodes may have a special value of ;; `org-element-deferred' type. Such values are computed dynamically. ;; Either every time the property value is requested or just the first ;; time. In the latter case, the `org-element-deferred' property ;; value is auto-replaced with the dynamically computed result. ;; ;; Sometimes, even property names (not just property values) cannot, or ;; should not be computed in advance. If a special property ;; `:deferred' has the value of `org-element-deferred-type', it is ;; first resolved for side effects of setting the missing properties. ;; The resolved value is re-assigned to the `:deferred' property. ;; ;; Note that `org-element-copy' unconditionally resolves deferred ;; properties. This is useful to generate pure (in functional sense) ;; AST. ;; ;; The properties listed in `org-element--standard-properties', except ;; `:deferred' and `:parent' are never considered to have deferred value. ;; This constraint makes org-element API significantly faster. ;; ;; 3. Org document representation ;; ------------------------------ ;; Document AST is represented by nested Org syntax nodes. ;; ;; Each node in the AST can hold the contained node in its CONTENTS or ;; as values of properties. ;; ;; For example, (bold (...) "bold text") `bold' node contains ;; `plain-text' node in CONTENTS. ;; ;; The containing node is called "parent node". ;; ;; The contained nodes held inside CONTENTS are called "child nodes". ;; They must have their `:parent' property set to the containing ;; parent node. ;; ;; The contained nodes can also be held as property values. Such ;; nodes are called "secondary nodes". Only certain properties ;; can contribute to AST - the property names listed as the value of ;; special property `:secondary' ;; ;; For example, ;; ;; (headline ((:secondary (:title) ;; :title (#("text" 0 4 (:parent (headline ...))))))) ;; ;; is a parent headline node containing "text" secondary string node ;; inside `:title' property. Note that `:title' is listed in ;; `:secondary' value. ;; ;; The following example illustrates an example AST for Org document: ;; ;; ---- Org document -------- ;; * Heading with *bold* text ;; Paragraph. ;; ---- end ----------------- ;; ;; (org-data (...) ; `org-data' node. ;; (headline ;; ( ;; ;; `:secondary' property lists property names that contain other ;; ;; syntax tree nodes. ;; ;; :secondary (:title) ;; ;; ;; `:title' property is set to anonymous node containing: ;; ;; `plain-text', `bold', `plain-text'. ;; ;; :title ("Heading with " (bold (:post-blank 1 ...) "bold") "text")) ;; ;; ;; `headline' contents ;; (section (...) ;; (paragraph ;; ;; `:parent' property set to the containing section. ;; (:parent (section ...)) ;; ;; paragraph contents is a `plain-text' node. ;; "Paragraph1.")))) ;; ;; Try calling M-: (org-element-parse-buffer) on the above example Org ;; document to explore a more complete version of Org AST. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at . Support Org development at , or support my work at --=-=-=--