Skip to content

Instantly share code, notes, and snippets.

@stathissideris
Last active September 9, 2020 05:51
Show Gist options
  • Save stathissideris/7eb2d14990d0b23f8edbee53dbb7bc21 to your computer and use it in GitHub Desktop.
Save stathissideris/7eb2d14990d0b23f8edbee53dbb7bc21 to your computer and use it in GitHub Desktop.
An attempt to use Datascript for state management in a Swing app (no React)
(ns not-posh
(:require [clojure.string :as str]
[clojure.data :as data]
[datascript.core :as d]
[clojure.set :as set]
[seesaw.core :as ss]))
(defn- diff [a b]
;;TODO make diff ignore :swing/component key but include it in result
(let [[removed added] (data/diff a b)
removed (zipmap (map :db/id removed) removed)
added (zipmap (map :db/id added) added)
common-keys (set/intersection (set (keys removed))
(set (keys added)))]
{:removed (vals (apply dissoc removed common-keys))
:added (vals (apply dissoc added common-keys))
:edited (not-empty (map #(hash-map :before (get removed %) :after (get added %)) common-keys))}))
(defn listen! [conn k query fun]
(d/listen!
conn k
(fn [{:keys [db-before db-after]}]
(let [before (d/q query db-before)
after (d/q query db-after)
the-diff (diff before after)
datoms (when (some not-empty (vals the-diff))
(fun db-before db-after the-diff))]
(when-not (empty? datoms)
(d/transact! conn datoms)))))) ;;TODO infinite recursion fun!
(defn assoc-component [db {:keys [id] :as record}]
(assoc record :component
(d/q `[:find ?c . :where [~id :swing/component ?c]] db)))
(listen!
conn ::windows
;;the query HAS to return :db/id for editing diff to work
;;optional :swing/component is ignored in diff (TODO)
'[:find ?d ?filename ?edited ?component
:keys db/id filename edited swing/component
:where
[?d :doc/filename ?filename]
[?d :doc/edited ?edited]
[(get-else $ ?d :swing/component :none) ?component]]
(fn [db-before db-after {:keys [removed added edited] :as diffs}]
(prn 'diffs diffs)
;; close windows
(doseq [{:keys [swing/component]} removed]
(ss/dispose! component))
;; rename windows
(let [edited (map :after edited)]
(doseq [{:keys [filename edited swing/component]} edited]
(ss/invoke-later (ss/config! component :title (str filename (when edited "*"))))))
;; open new windows and register the components in the state by returning transact! vectors
(for [{:keys [db/id filename edited]} added]
[:db/add id :swing/component (doto (ss/frame :title (str filename (when edited "*"))
:content (ss/label :text filename)
:on-close :dispose)
(ss/pack!)
(ss/show!))])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment