Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2de01d8
Diff old read+eval and read-kinds read+eval
onbreath Nov 27, 2025
b3d462b
Add one difference example
onbreath Nov 27, 2025
bfc0f8b
Moved to scicloj.clay.v2.util.diff, refactored, fixed
onbreath Nov 28, 2025
4c7092b
Add pre read-kinds notebook.clj as notebook_old.clj
onbreath Nov 28, 2025
d09dc8b
Revert read_old.clj
onbreath Nov 28, 2025
44f7813
Diff on old and new notebooks
onbreath Nov 28, 2025
c322416
Print with Clay:
onbreath Nov 28, 2025
b3428a3
Take out some keys unique to new/old notes
onbreath Nov 28, 2025
442c970
Tricked by seqs
onbreath Nov 28, 2025
a3dfe9e
Copy current diff to diffs-folder toplevel
onbreath Nov 28, 2025
ea1003d
Print convenience
onbreath Nov 28, 2025
b83eaad
Include notebook path in diff folder name
onbreath Nov 28, 2025
a1710f3
complete not needed for read-kinds
onbreath Nov 28, 2025
8c481f0
out and err captured by read-kinds
onbreath Nov 28, 2025
5682928
Collapse comments and whitespace notes from read-kinds
onbreath Nov 28, 2025
14e0d28
read missing require
onbreath Nov 29, 2025
5a399ef
Improve comment/whitespace collapse a bit
onbreath Nov 29, 2025
ef4f35a
Simplified, added no-diff case, informative printing
onbreath Nov 29, 2025
7c4c390
Attempt to dodge some datasets before they blow up diffing
onbreath Nov 29, 2025
0bc482a
Diff only clojure- and java-datastructures for now
onbreath Nov 30, 2025
16a65eb
vector is list
onbreath Nov 30, 2025
a7a0274
Added ReplacedValue type for diffing, wraps replaced value
onbreath Nov 30, 2025
008e89a
Just replace unsupported collections for now
onbreath Dec 1, 2025
24fcbad
Fix folder to delete in should exist first
onbreath Dec 1, 2025
5108531
Fixed future handler in deep-diff2 printer
onbreath Dec 1, 2025
a88d93c
Make old and new comments equal for diff
onbreath Dec 2, 2025
41c81f2
read/eval split in read-kinds
onbreath Dec 4, 2025
e27dee4
Merge branch 'integrate-read-kinds' of github.com:scicloj/clay into o…
onbreath Dec 10, 2025
13b9b87
Started cleaning up scicloj.clay.v2.notebook for read-kinds
onbreath Dec 10, 2025
d26952b
Added format :edn
onbreath Dec 25, 2025
405f32e
Merge branch 'edn-format' of github.com:scicloj/clay into old-read-re…
onbreath Dec 25, 2025
e2c5819
Move diffing to local "old" clay and use kindly with :merge-options
onbreath Dec 26, 2025
37cf562
Notebooks use kindly v4 again
onbreath Dec 27, 2025
08fc458
Add fn-replacement for diffing
onbreath Dec 28, 2025
34a83eb
Adjust to function name change in read-kinds
onbreath Dec 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@
docs/*qmd
_quarto.yml
book
/read-kinds-diffs
9 changes: 6 additions & 3 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.12.0"}
:deps {org.clojure/clojure {:mvn/version "1.12.4"}
org.clojure/tools.cli {:mvn/version "1.1.230"}
nrepl/nrepl {:mvn/version "1.3.1"}
com.cnuernber/charred {:mvn/version "1.037"}
read-kinds/read-kinds {:local/root "../read-kinds"}
;; TODO back to lambdaisland/deep-diff2 once fix merged
io.github.onbreath/deep-diff2 {:git/sha "1f969521b68ce9dd9feed9b51a99a4569482b6ad"}
org.antlr/antlr4-runtime {:mvn/version "4.7.1"}
http-kit/http-kit {:mvn/version "2.8.0"}
ring/ring-core {:mvn/version "1.14.1"}
io.github.nextjournal/markdown {:mvn/version "0.6.157"}
hiccup/hiccup {:mvn/version "2.0.0-RC5"}
clj-commons/clj-yaml {:mvn/version "1.0.29"}
org.scicloj/kindly {:mvn/version "4-beta21"}
org.scicloj/kindly-advice {:mvn/version "1-beta14"}
org.scicloj/clay-old {:local/root "../clay-old"}
io.github.scicloj/kindly {:git/sha "2863a8e08c39b1ec50a2ffde2d0874942a113d4b"}
io.github.scicloj/kindly-advice {:git/sha "17f506f169ac09b2c2d90625f1a31246e0b87360"}
org.scicloj/tempfiles {:mvn/version "1-beta1"}
org.scicloj/kind-portal {:mvn/version "1-beta3"}
org.clojure/tools.reader {:mvn/version "1.5.2"}
Expand Down
19 changes: 17 additions & 2 deletions src/scicloj/clay/v2/make.clj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
[clojure.pprint :as pp]
[scicloj.kindly-render.notes.to-html-page :as to-html-page]
;; [hashp.preload]
[scicloj.kindly.v4.api :as kindly]))
[scicloj.kindly.v4.api :as kindly])
(:import java.time.LocalDateTime
java.time.format.DateTimeFormatter))

(defn spec->source-type [{:keys [source-path]}]
(some-> source-path (fs/extension)))
Expand Down Expand Up @@ -366,6 +368,11 @@
:items items
:exception exception)]
[(case (first format)
:edn {:spec spec
:notes notes
:items items
:test-forms test-forms
:exception exception}
:hiccup (page/hiccup spec-with-items)
:html (do (-> spec-with-items
(config/add-field :page (if post-process
Expand Down Expand Up @@ -471,8 +478,12 @@
(fs/delete-tree target))
(util.fs/copy-tree-no-clj subdir target)))))))

(defn ts []
(.format (LocalDateTime/now)
(DateTimeFormatter/ofPattern "yyyy-MM-dd-HH-mm-ss~N")))

(defn make! [spec]
(let [config (config/config spec)
(let [config (config/config (assoc spec :diff/timestamp (ts)))
{:keys [single-form single-value]} spec
{:keys [main-spec single-ns-specs]} (extract-specs config spec)
{:keys [ide browse show book base-target-path clean-up-target-dir live-reload]} main-spec
Expand Down Expand Up @@ -511,4 +522,8 @@
,
(make! {:source-path ["notebooks/index.clj"]
:format [:gfm]
:show false})

(make! {:source-path ["notebooks/demo.clj"]
:format [:edn]
:show false}))
235 changes: 124 additions & 111 deletions src/scicloj/clay/v2/notebook.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
[scicloj.clay.v2.util.path :as path]
[scicloj.clay.v2.item :as item]
[scicloj.clay.v2.prepare :as prepare]
[scicloj.clay.v2.old.notebook :as notebook-old]
[scicloj.clay.v2.old.make :as make-old]
[scicloj.clay.v2.read :as read]
[scicloj.kindly.v4.api :as kindly]
[scicloj.kindly-advice.v1.api :as kindly-advice])
(:import (java.io StringWriter)))
[scicloj.kindly.v5.api :as kindly-v5]
[scicloj.kindly-advice.v1.completion :as ka-completion]
[scicloj.kindly-advice.v2.completion :as ka-completion-v2]
[scicloj.clay.v2.util.diff :as diff]))

(set! *warn-on-reflection* true)

Expand Down Expand Up @@ -42,29 +46,6 @@
(and (sequential? form)
(-> form first (= 'ns))))

(defn str-and-reset! [w]
(when (instance? StringWriter *out*)
(locking w
(let [s (str w)]
(.setLength (.getBuffer ^StringWriter w) 0)
s))))

(def ^:dynamic *out-orig* *out*)

(defn maybe-println-orig [s]
(when (seq s)
(binding [*out* *out-orig*]
(print s)
(flush))))

(def ^:dynamic *err-orig* *err*)

(defn maybe-err-orig [s]
(when (seq s)
(binding [*out* *err-orig*]
(print s)
(flush))))

;; Babashka
;; - Make Clay runnable in Babashka
;; - The way Clay reads - dependency of `carocad/parcera`, maybe we just remove it.
Expand Down Expand Up @@ -94,56 +75,6 @@
;; - Can we frame the stack around eval?
;; - Is output being done right?

(defn read-eval-capture
"Captures stdout and stderr while evaluating a note"
[{:as note
:keys [code form]}]
note
#_
(let [out (StringWriter.)
err (StringWriter.)
note (try
(let [x (binding [*out* out
*err* err]
(cond form (-> form
eval
deref-if-needed)
code (-> code
read-string
eval
deref-if-needed)))]
(assoc note :value x))
(catch Throwable ex
(assoc note :exception ex)))
out-str (str out)
err-str (str err)
;; A notebook may have also printed from a thread,
;; *out* and *err* are replaced with StringWriters in with-out-err-capture
global-out (str-and-reset! *out*)
global-err (str-and-reset! *err*)
;; Don't show output from requiring other namespaces
show (not (ns-form? form))]
(maybe-println-orig out-str)
(maybe-err-orig err-str)
(maybe-println-orig global-out)
(maybe-err-orig global-err)
(if show
(cond-> note
(seq out-str) (assoc :out out-str)
(seq err-str) (assoc :err err-str)
(seq global-out) (assoc :global-out global-out)
(seq global-err) (assoc :global-err global-err))
note)))

(defn complete [{:as note
:keys [comment?]}]
(let [completed (cond-> note
(not (or comment? (contains? note :value)))
(read-eval-capture))]
(cond-> completed
(and (not comment?) (contains? completed :value))
(kindly-advice/advise))))

(defn comment->item [comment]
(-> comment
(str/split #"\n")
Expand Down Expand Up @@ -323,22 +254,6 @@
code new-code)})))
(@*path->last path))

(defmacro with-out-err-captured
"Evaluates and computes the items for a notebook of notes"
[& body]
;; For a notebook, we capture output globally, and per note.
;; see read-eval-capture for why this is relevant.
`(let [out# (StringWriter.)
err# (StringWriter.)]
;; Threads may inherit only the root binding
(with-redefs [*out* out#
*err* err#]
;; Futures will inherit the current binding,
;; which was not affected by altering the root.
(binding [*out* out#
*err* err#]
~@body))))

(defn itemize-notes
"Evaluates and computes the items for a notebook of notes"
[relevant-notes some-narrowed options]
Expand Down Expand Up @@ -409,22 +324,18 @@
:format])]
(doall
(for [note notes]
(complete (kindly/deep-merge opts note))))))
(kindly/deep-merge opts note)))))

(defn relevant-notes [{:keys [full-source-path
single-form
single-value
smart-sync
pprint-margin]
:or {pprint-margin pp/*print-right-margin*}}]
(let [{:keys [code first-line-of-change]} (some-> full-source-path slurp-and-compare)
notes (->> (cond single-value (conj (when code
[{:form (read/read-ns-form code)}])
{:value single-value})
single-form (conj (when code
[{:form (read/read-ns-form code)}])
{:form single-form})
:else (read/->notes code))
single-form
single-value
smart-sync
pprint-margin]
:or {pprint-margin pp/*print-right-margin*}
:as spec}]
(let [{:keys [code first-line-of-change]} (some-> full-source-path
slurp-and-compare)
notes (->> (read/->notes (assoc spec :code code))
(map-indexed (fn [i {:as note
:keys [code]}]
(merge note
Expand Down Expand Up @@ -464,19 +375,121 @@
"seconds")
result#))

(defn ->old-comment [note]
(let [comment-item (-> note :code notebook-old/comment->item)]
(-> note
(assoc :value (str/replace (:md comment-item)
;; TODO stripping extra space added
;; in front of headline Do we want
;; to add this for read-kinds?
#"\n#" "#")
:kind :kind/md)
(dissoc :code :comment? :region))))

(defn ->note-approx [note]
(dissoc note :format))

;; TODO Decide on whether we want to remove options form the notebook
(defn old-kindly-options? [note]
(not (empty? (into [] (comp (mapcat (fn [x] (if (coll? x) x [x])))
(filter #{'kindly/set-options! 'kindly/merge-options!})
(take 1))
(:form note)))))

(defn ->old-notes-approx [notes]
(->> notes
(into []
(comp (map #(-> %
(cond-> (and (:comment? %)
(:code %))
->old-comment)
(dissoc :gen)
->note-approx))
(remove old-kindly-options?)))))

(defn new-kindly-options? [note]
(contains? (some-> note :value meta) :kindly/merge-options))

(defn ->new-notes-approx [notes]
(->> notes
(into []
(comp (map #(-> %
(dissoc :line :column)
->note-approx
(cond-> (-> % :narrowed nil?)
(dissoc :narrowed)
(-> % :narrower nil?)
(dissoc :narrower))))
(remove new-kindly-options?)))))


(defn old-spec-notes [spec]
(-> (make-old/make! {:source-path (:full-source-path spec)
:format [:edn]
:show false})
:info
ffirst
first
:notes
->old-notes-approx))

(defn new-spec-notes [{:as spec
:keys [ns-form full-source-path]}]
(with-redefs [;; See kindly-advice branch with v2-namespace for TODO on this
ka-completion/complete-options ka-completion-v2/complete-options
kindly/get-options (constantly nil)
kindly/set-options! kindly-v5/set-options!
kindly/merge-options! kindly-v5/merge-options!]
(-> (assoc spec :collapse-comments-ws? true)
(relevant-notes)
(complete-notes spec)
(log-time (str "Evaluated notebook with read-kinds "
(or (some-> ns-form second name)
(some-> full-source-path fs/file-name)))))))

(defn spec-notes [{:as spec
:keys [pprint-margin ns-form full-source-path]
:or {pprint-margin pp/*print-right-margin*}}]
(binding [*ns* *ns*
*warn-on-reflection* *warn-on-reflection*
*unchecked-math* *unchecked-math*
pp/*print-right-margin* pprint-margin]
(-> (relevant-notes spec)
(complete-notes spec)
(with-out-err-captured)
(log-time (str "Evaluated "
(or (some-> ns-form second name)
(some-> full-source-path fs/file-name)))))))
;; TODO this just works for one notebook without a base-source-path etc.
(let [old (old-spec-notes spec)
new-ret (new-spec-notes spec)
new (->new-notes-approx new-ret)]
;; We can print the plain new and old notes..
#_(diff/notes old new
:diff/to-repl :clojure/pprint
spec)
;; ..or only differences
(diff/notes old new
:diff/to-repl :deep-diff2/minimal
spec)
;; ..or only one difference
#_(diff/notes (take 1 old) (take 1 new)
:diff/to-repl :deep-diff2/minimal
spec)
;; ..or write old and new files
#_(diff/notes old new
:diff/to-files :clojure/pprint
spec)
;; ..or old, new and full diff files
#_(diff/notes old new
:diff/to-files :deep-diff2/full
spec)
;; ..or old, new and minimal diffs, keeping only the last three runs
#_(diff/notes old new
:diff/to-files :deep-diff2/minimal
:diff/keep-dirs 3
spec)
;; ..or any combination of the above
#_(diff/notes old new
:diff/to-repl :deep-diff2/minimal
:diff/to-files :deep-diff2/full
:diff/keep-dirs 3
spec)
new-ret)))

(defn items-and-test-forms
[notes spec]
Expand Down
Loading