overthunk ltd. A Solitary Software Production

3D portrait of a weird little guy

A Brave Start to Athens and re-frame

athens cljs clojurefam fp open source re-frame

Jul 2, 2020


Contents

Athens Issue

Let’s take a quick look at what the issue says -

prevent indent when already a leaf block, prevent unindent when already a top-level child

From my understanding of how Roam Research works, I guessed that when it says “prevent indent of leaf nodes”, a node that doesn’t have any children cannot further indented to the right. Also, if we are at the root node, we cannot unindent it. This also makes intuitive sense since the root node is already at the left most point, and nodes can only be further indented fromt this point.

The relevant code for this issue is found in this code snippet at athens/events.cljs -

;; TODO: no-op when indenting as the right-most child
(reg-event-fx
  :indent
  (fn [_ [_ uid]]
    (let [block (get-block [:block/uid uid])
          parent (get-parent [:block/uid uid])
          older-sib (->> parent
                      :block/children
                      (filter #(= (dec (:block/order block)) (:block/order %)))
                      first
                      :db/id
                      get-block)
          new-block {:db/id (:db/id block) :block/order (count (:block/children older-sib))}
          reindex-blocks (->> (d/q '[:find ?ch ?new-o
                                     :in $ % ?p ?at
                                     :where (dec-after ?p ?at ?ch ?new-o)]
                                @db/dsdb rules (:db/id parent) (:block/order block))
                           (map (fn [[id order]] {:db/id id :block/order order})))]
      {:transact [[:db/retract (:db/id parent) :block/children (:db/id block)]
                  {:db/id (:db/id older-sib) :block/children [new-block]} ;; becomes child of older sibling block — same parent but order-1
                  {:db/id (:db/id parent) :block/children reindex-blocks}]}))) ;; reindex parent

A cursory reading of this seems somewhat understandable given what I know about Clojure. But it largely relies on knowing the re-frame library and how state management and events are handled in this library.

So I set out to get myself familiarized with re-frame and also with Datalog, a declarative query language used in the project. I’m currently doing the exercises on LearnDatalogToday and re-reading the introduction to Re-frame. I feel like I conceptually get the motivations behind re-frame but there’s quite a lot of implementation details to understand.

Other things I worked on Today

I also spent some today doing a few other Clojure related things. Having gotten through Clojure from the Ground Up, I started reading Chapter 3 of CFTBAT again. Chapters 1 and 2 are somewhat irrelevant since they cover setting up Emacs as an environment which I’d already done.

Speaking of environments, I decided to take a peek at Calva and VS Code today and I’m somewhat enjoying the experience. The keybinds for Calva are just dissimilar enough from CIDER that it keeps tripping me up, but from a functional standpoint, Calva seems perfectly adequate for my workflow which mostly just involves evaluating the current s-exp repeatedly.

One productivity benefit I’ve noticed is that using Git has been a lot easier since I like the GitLens extension quite a lot more than I like Magit. Probably because I never got around to seriously learning Magit. It just seems comfortable doing simple things like accessing the terminal, interacting with the file system etc. However, I miss Emacs’s buffer and window system.

While reading CFTBAT, I came across the line - “Strings can only be concatenated. Clojure does not have string interpolation”. I immediately took this as a challenge and decided to attempt implementing a Clojure macro that allows for String Interpolation.

I imagined the syntax for string interpolation to be something similar to Python’s f-strings -

f"Hello my name is {name} and I'm {age} years old"

I got as far as writing some code to perform a regex search and capture the variables between the {}. This looks like -

(re-seq #"\{([a-zA-Z]+)\}" "name is {name} and lang is {lang}")

Unfortunately, that’s about as far as I got. I’ll have to leave the rest of this macro for another day.

Takeaways

I did some quick and dirty dabbling into re-frame and Datalog. re-frame is quite interesting and I definitely need to spend a lot more time getting the mental model for Re-frame into my head. The comparison of re-frame to Redux isn’t exactly a helpful one since I’m not that familiar with State Management in React either. (Just making pretty components).

Anyway, I think this was a very broad learning day rather than one with deep focus. Which in my opinion is ok since it offeres a lot of interesting things to digest. What is crucial is that I follow up on the knowledge from today and keep building on it.