David Schmudde / Jul 30 2019
Nextjournal in Nextjournal
Mount the Nextjournal Repository
nextjournal/nextjournal
Private
How many lines of code are in the core codebase?
cd /nextjournal/journal/src/com/nextjournal git ls-files | xargs wc -l
Look for the function of interest, insert-code-node
.
grep -nri "insert-code-node" /nextjournal
The definition is listed at /nextjournal/journal/src/com/nextjournal/editor/events.cljs:1465: :insert-code-node
. Print that:
sed -n 1463,1475p /nextjournal/journal/src/com/nextjournal/editor/events.cljs
Self Modification of the Nextjournal Notebook
Code from com.nextjournal.editor.operations.tree
necessary to run the notebook update.
Shift+Enter to run
ClojureScript
→
(ns tree) (defn root-id [db] (get-in db [:article :root])) (defn root? [db node-id] (= node-id (root-id db))) (defn parent-by-id [db node-id content-key] (->> db :article :nodes vals (filter (some {node-id} (content-key %))) first)) (defn full-position-by-id "Returns a vector describing the position of the node in the form [parent-id content-key position] E.g [\"abc-123\" :nodes 2] Returns nil if node-id is the root node" [db node-id] (when-not (root? db node-id) (let [[parent content-key] (some (fn [key] (when-let [p (parent-by-id db node-id key)] [p key])) [:content :sections :nodes :inlines]) content-pos (.indexOf (vec (content-key parent)) node-id)] (assert parent) (assert (<= 0 content-pos)) [(:id parent) content-key content-pos]))) (defn split-at-item [v i] (split-with (not= % i) v)) (defn flat ([db] (assert db) (flat (get-in db [:article :nodes]) (get-in db [:article :root]))) ([all-nodes current-node-id] (assert all-nodes) (let [node (all-nodes current-node-id)] (concat [current-node-id] (:content node) (mapcat (partial flat all-nodes) (:sections node)))))) (defn closest-code-cell "Given an `article` and an absolute position `pos`, tries to find a code cell above the given position first. If there's no matching cell found above, it returns the closes below, nil otherwise. Accepts an optional predicate which all code cells considered should satisfy." ([article pos] (closest-code-cell article pos (constantly true))) ([article [section-id content-key idx :as pos] pred] (let [db {:article article} contents (vec (get-in article [:nodes section-id content-key])) node-at-pos (if (contains? contents idx) (get contents idx) (get-in article [:nodes section-id :sections 0])) flat (flat db) [before after] (split-at-item flat node-at-pos) closest-nodes (concat (reverse before) after)] (some (fn [id] (let [node (get-in article [:nodes id])] (when (and (pred node) (= "code" (:kind node))) node))) closest-nodes)))) "[com.nextjournal.editor.operations.tree :as tree]"
The react dispatch :insert-code-node
.
((fn [{:keys [db] :as ctx} [_ node-id attrs]] (let [db (dissoc db :auth-token) [p o s :as pos] (full-position-by-id db node-id) find-closest-lang (comp :language (partial tree/closest-code-cell (:article db))) attrs (update attrs :language (or % (find-closest-lang pos) "julia"))] {:db db :dispatch {:insert-code-node-into p o s "code" attrs}})) {:db re-frame.db/app-db} ["" "b4412f59-a73b-43af-b795-029e41e90852"])
Test the dispatch and update this notebook by inserting lorem ipsum above using the code cell below.
(defn api-call [text id kind] (re-frame.core/dispatch [:insert-after id kind {:content text}])) (defn send-post [text & opts] (let [{:keys [video sound image id kind]} opts] (api-call text id kind))) (send-post "lorem ipsum" :id "b4412f59-a73b-43af-b795-029e41e90852" :kind "paragraph")