Skip to content

Repository files navigation

* org-parser-tree
Building upon the awesome [[https://github.com/200ok-ch/org-parser][org-parser]], =org-parser-tree= provides utilities to create a Clojure tree structure from an org file
** Alpha-Status
Currently only the following [[https://github.com/200ok-ch/org-parser/blob/master/resources/org.ebnf][line types]] of [[https://github.com/200ok-ch/org-parser][org-parser]] are implemented:
- =:head-line=
- =:content-line=
- =:list-item-line=
- =:drawer-begin-item=

=org-parser-tree= is [[https://github.com/rollacaster/org-parser-tree#extensibility][extensible]] can add missing implementations or edit the existing ones
** [[https://clojure.org/reference/deps_and_cli][CLI/deps.edn]] dependency information:
 #+BEGIN_SRC clojurescript
rollacaster/org-parser-tree {:git/url "https://github.com/rollacaster/org-parser-tree" :sha "e7510a6b3bc6abebfd4428c236e0e449c7be6ee1"}
 #+END_SRC
** Usage
#+BEGIN_SRC clojurescript
  (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:")
#+END_SRC
*** Result
#+BEGIN_SRC clojurescript
  {: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 []})})})})}
#+END_SRC

#+DOWNLOADED: screenshot @ 2020-12-22 12:37:32
[[file:resources/org-parser-tree/2020-12-22_12-37-32_screenshot.png]]
** How it works
During the creation of the tree structure three functions are called for each [[https://github.com/200ok-ch/org-parser/blob/master/resources/org.ebnf][line type]] of [[https://github.com/200ok-ch/org-parser][org-parser]]:

- =transform=: Transform a line of [[https://github.com/200ok-ch/org-parser][org-parser]] to another Clojure data-structure
- =post-transform=: Transform a line of =org-parser-tree= to another Clojure data-structure
- =stratify=: Place a transformed line into the tree structure by using [[https://clojure.github.io/clojure/clojure.zip-api.html][clojure.zip]]

It's possible to extend any part of the tree creation.
** Extensibility
By using [[https://clojure.org/reference/multimethods][Multimethods]] it's possible to extend the generated data structure or add missing implementations dynamically
*** post-transform
You can extend how a parsed line from =org-parser-tree= is transformed
#+BEGIN_SRC clojure
  (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]]")
#+END_SRC

**** Result
#+BEGIN_SRC clojurescript
  {: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 []})})}
#+END_SRC
*** stratify
You can extend how =org-parser-tree= builds the tree using the [[https://clojure.github.io/clojure/clojure.zip-api.html][clojure.zip API]]
#+BEGIN_SRC clojurescript
  (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=")

#+END_SRC
**** Result
#+BEGIN_SRC clojurescript
{: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"})}
#+END_SRC
*** transform
You can add missing implementations of [[https://github.com/200ok-ch/org-parser/blob/master/resources/org.ebnf][line types]] from [[https://github.com/200ok-ch/org-parser][org-parser]] or replace existing ones
#+BEGIN_SRC clojurescript
  (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")
#+END_SRC
**** Result
#+BEGIN_SRC clojurescript
  {:children
   ({:tags #{}, :type :head-line, :title "2021", :level 1, :children []}),
   :title "root",
   :level 0,
   :keywords {:TAGS "WORK(w)"}}
#+END_SRC

About

Create a Clojure tree structure from an org file

Topics

Resources

Stars

10 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages