Building upon the awesome org-parser, org-parser-tree
provides utilities to create a Clojure tree structure from an org file
Currently only the following line types of org-parser are implemented:
:head-line
:content-line
:list-item-line
:drawer-begin-item
org-parser-tree
is extensible can add missing implementations or edit the existing ones
CLI/deps.edn dependency information:
rollacaster/org-parser-tree {:git/url "https://github.com/rollacaster/org-parser-tree" :sha "e7510a6b3bc6abebfd4428c236e0e449c7be6ee1"}
(ns hello-world.core
(:require [tech.thomas-sojka.org-parser-tree.core :refer [parse-tree]]))
(parse-tree "
* 2019
** Unordered
*** Sometime
**** Clojure Spec basics :LEARN:TUTORIAL:
** 2019-01 January
*** KW01
**** Build a snowman :SOCIAL:
**** Game night :SOCIAL:")
{:title "root",
:level 0,
:children
({:title "2019",
:type :head-line,
:level 1,
:tags #{},
:children
({:title "Unordered",
:type :head-line,
:level 2,
:tags #{},
:children
({:title "Sometime",
:type :head-line,
:level 3,
:tags #{},
:children
({:title "Clojure Spec basics",
:type :head-line,
:level 4,
:tags #{"LEARN" "TUTORIAL"},
:children []})})}
{:title "2019-01 January",
:type :head-line,
:level 2,
:tags #{},
:children
({:title "KW01",
:type :head-line,
:level 3,
:tags #{},
:children
({:title "Build a snowman",
:type :head-line,
:level 4,
:tags #{"SOCIAL"},
:children []}
{:title "Game night",
:type :head-line,
:level 4,
:tags #{"SOCIAL"},
:children []})})})})}
During the creation of the tree structure three functions are called for each line type of org-parser:
transform
: Transform a line of org-parser to another Clojure data-structurepost-transform
: Transform a line oforg-parser-tree
to another Clojure data-structurestratify
: Place a transformed line into the tree structure by using clojure.zip
It’s possible to extend any part of the tree creation.
By using Multimethods it’s possible to extend the generated data structure or add missing implementations dynamically
You can extend how a parsed line from org-parser-tree
is transformed
(ns hello-world.core
(:require [clojure.string :as str]
[tech.thomas-sojka.org-parser-tree.core :refer [parse-tree]]
[tech.thomas-sojka.org-parser-tree.transform
:refer
[post-transform]]))
(defn transform-link [{:keys [title] :as headline}]
(let [re-org-link #"\[\[(.*)\]\[(.*)\]\]"]
(if (str/includes? title "[[")
(let [[link description]
(drop 1 (re-find (re-matcher re-org-link title)))]
(-> headline
(assoc :link link)
(assoc :title (str/replace title re-org-link description))))
headline)))
(defmethod post-transform :head-line [head-line]
(transform-link head-line))
(parse-tree "
* KW01
** Build a [[https://en.wikipedia.org/wiki/Snowman][snowman]]")
{:title "root",
:level 0,
:children ({:title "KW01",
:type :head-line,
:level 1,
:tags #{},
:children
({:title "Build a snowman",
:type :head-line,
:level 2,
:tags #{},
:link "https://en.wikipedia.org/wiki/Snowman",
:children []})})}
You can extend how org-parser-tree
builds the tree using the clojure.zip API
(ns hello-world.core
(:require [clojure.zip :as z]
[tech.thomas-sojka.org-parser-tree.core :refer [parse-tree]]
[tech.thomas-sojka.org-parser-tree.stratify :refer [stratify]]))
(defmethod stratify :list-item-line [org-tree list-item-line]
(z/edit org-tree update :content str (:list-item list-item-line) "\n"))
(parse-tree "
**** Learned new clojure tricks :LEARN:
After reading the Clojure style guide I learned:
- Use sets as function
- Use =list*= for nested cons
- Use =Constructor.= instead of =new=")
{:title "root",
:level 0,
:children
({:title "Learned new clojure tricks",
:type :head-line,
:level 4,
:tags #{"LEARN"},
:children [],
:content
"After reading the Clojure style guide I learned:Use sets as function\nUse =list*= for nested cons\nUse =Constructor.= instead of =new=\n"})}
You can add missing implementations of line types from org-parser or replace existing ones
(ns hello-word.core
(:require [clojure.zip :as z]
[tech.thomas-sojka.org-parser-tree.core :refer [parse-tree]]
[tech.thomas-sojka.org-parser-tree.stratify :refer [stratify]]
[tech.thomas-sojka.org-parser-tree.transform :refer [transform]]))
(defmethod transform :keyword-line [[_ [_ keyword-key] [_ keyword-value]]]
{:type :keyword-line
:key keyword-key
:value keyword-value})
(defmethod stratify :keyword-line [org-tree {:keys [key value]}]
(z/replace org-tree (assoc (z/node org-tree) :keywords {(keyword key) value})))
(parse-tree "#+TAGS: WORK(w)
* 2021")
{:children
({:tags #{}, :type :head-line, :title "2021", :level 1, :children []}),
:title "root",
:level 0,
:keywords {:TAGS "WORK(w)"}}