Building upon the awesome org-parser, org-parser-tree
provides utilities to create a tree structure in clojure from an org file
Currently only the following line types of org-parser are implemented:
:head-line
:content-line
:list-item-line
But you can add missing implementations or edit the existing ones by using the Customizations
CLI/deps.edn dependency information:
rollacaster/org-parser-tree {:git/url "https://github.com/rollacaster/org-parser-tree" :sha "e7f0876fbb4b7793081bcdf7f94df39c440f9c1f"}
(ns hello-world.core
(:require [tech.thomas-sojka.org-parser-tree.core :refer [parse-tree]]))
(let [journal "
* 2019
** Unordered
*** Sometime
**** Clojure Spec basics :LEARN:TUTORIAL:
** 2019-01 January
*** KW01
**** Build a snowman :SOCIAL:
**** Game night :SOCIAL:"]
(parse-tree journal))
{: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 []})})})})}
By using Multimethods it’s possible to customize the generated data structure or add missing implementations dynamically
You can customise 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))
(let [journal "
* KW01
** Build a [[https://en.wikipedia.org/wiki/Snowman][snowman]]"]
(parse-tree journal))
{: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 customise 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"))
(let [journal "
**** 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="]
(parse-tree journal))
{: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-world.core
(:require [clojure.string :as str]
[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 :drawer-begin-line [[_ [_ drawer-name]]]
{:type :drawer-begin-line
:drawer (keyword (str/lower-case drawer-name))})
(defmethod stratify :drawer-begin-line [org-tree drawer-begin-line]
(z/replace org-tree (assoc (z/node org-tree) (:drawer drawer-begin-line) [])))
(parse-tree "
* Test
:MY-DRAWER:
:END:")
{:children
({:tags #{},
:type :head-line,
:title "Test",
:level 1,
:children [],
:my-drawer [],
:end []}),
:title "root",
:level 0}