diff --git a/deps.edn b/deps.edn index 5a1c34a3..c3834cc3 100644 --- a/deps.edn +++ b/deps.edn @@ -3,7 +3,7 @@ org.clojure/tools.cli {:mvn/version "1.1.230"} nrepl/nrepl {:mvn/version "1.3.1"} com.cnuernber/charred {:mvn/version "1.037"} - carocad/parcera {:mvn/version "0.11.6"} + read-kinds/read-kinds {:local/root "../read-kinds"} 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"} diff --git a/src/scicloj/clay/v2/notebook.clj b/src/scicloj/clay/v2/notebook.clj index 59f8a9b5..25447a88 100644 --- a/src/scicloj/clay/v2/notebook.clj +++ b/src/scicloj/clay/v2/notebook.clj @@ -65,10 +65,41 @@ (print s) (flush)))) +;; Babashka +;; - Make Clay runnable in Babashka +;; - The way Clay reads - dependency of `carocad/parcera`, maybe we just remove it. +;; - or make parcera optional... or replace the functionality. +;; - major motivation for `read-kinds` +;; - maybe we can use `read-kinds` or adapt it. +;; +;; - Vs Run Clay in Clojure, and run Babashka as separate process << +;; - still valuable +;; - + +;; Jank +;; - Could we ever run clay in Jank? +;; - If we can't, can we read Jank code in Clojure? +;; - If we can read it, and we can send it to an nREPL, that's interesting. + +;; should we use nREPL for Clojure +;; - We already do in some way -- the integrations are via nREPL +;; - Where should **Clay** run? Same process or different process. +;; - Can we cancel evaluation? + +;; Error messages +;; - Not integrated with the tooling +;; - Problem: we are sending things like `(clay/make! {:single-form "(+ 1 2)"})` +;; but we want our repl to treat it like `(+ 1 2)`... +;; - We want our nREPL to return the result of `(+ 1 2)` (or exception), and with that stack. +;; - 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 diff --git a/src/scicloj/clay/v2/read.clj b/src/scicloj/clay/v2/read.clj index 0a3bea4d..42873097 100644 --- a/src/scicloj/clay/v2/read.clj +++ b/src/scicloj/clay/v2/read.clj @@ -1,8 +1,8 @@ (ns scicloj.clay.v2.read - (:require [clojure.tools.reader] - [clojure.tools.reader.reader-types] - [parcera.core :as parcera] - [clojure.string :as str])) + (:require [scicloj.read-kinds.notes :as notes] + [scicloj.read-kinds.read :as read])) + +;; TODO: not sure if generation is necessary??? (def *generation (atom 0)) @@ -10,6 +10,7 @@ (swap! *generation inc) @*generation) +;; for finding the ns only (defn read-forms [code] (->> code clojure.tools.reader.reader-types/source-logging-push-back-reader @@ -17,7 +18,6 @@ (map #(clojure.tools.reader/read % false ::EOF)) (take-while (partial not= ::EOF)))) - (defn read-ns-form [code] (->> code read-forms @@ -26,105 +26,11 @@ (-> form first (= 'ns))))) first)) -(defn read-by-tools-reader [code] - (-> code - ;; avoiding a tools.reader bug -- see: - ;; https://github.com/scicloj/clay/issues/151#issuecomment-2373488031 - (str/replace #"\r\n" "\n") - (->> read-forms - (map (fn [form] - (let [{:keys [line column - end-line end-column - code]} - (meta form)] - (when line ; skip forms with no location info - {:method :tools-reader - :region [line column - end-line end-column] - :code (-> form meta :source) - :form form})))) - (filter some?)))) - -(defn read-by-parcera [code] - (->> code - parcera/ast - rest - (map (fn [node] - (let [node-type (first node) - node-contents (rest node)] - ;; We use parcera only for specific types of - ;; code blocks, that tools.reader does not - ;; provide location info for. - (some->> (when (#{:number :string :symbol :keyword :comment} - node-type) - {:code (first node-contents)}) - (merge {:method :parcera - :region (->> node - meta - ((juxt :parcera.core/start - :parcera.core/end)) - (mapcat (juxt :row - (comp inc - :column))) - vec)} - (when (= :comment node-type) - {:comment? true})))))) - (filter some?))) - -(defn unified-cleaned-comment-block [comment-blocks-sorted-by-region] - {:region (vec (concat (->> comment-blocks-sorted-by-region - first - :region - (take 2)) - (->> comment-blocks-sorted-by-region - last - :region - (drop 2)))) - :code (->> comment-blocks-sorted-by-region - (reduce (fn [{:keys [generated-string max-line]} - {:keys [region code]}] - {:generated-string (str generated-string - (apply str (-> region - first - (- max-line) - (repeat "\n"))) - code) - :max-line (-> region - (nth 2) - (max max-line))}) - {:generated-string "" - :max-line (->> comment-blocks-sorted-by-region - first - :region - first)}) - :generated-string) - :comment? true}) - (defn ->notes [code] - (->> code - ((juxt read-by-tools-reader read-by-parcera)) - (apply concat) - (group-by :region) - (map (fn [[region results]] - (if (-> results count (= 1)) - (first results) - ;; prefer tools.reader over parcera - (->> results - (filter #(-> % :method (= :tools-reader))) - first)))) - (sort-by :region) - (map #(dissoc % :method)) - (partition-by :comment?) - (mapcat (fn [part] - (if (-> part first :comment?) - [(unified-cleaned-comment-block part)] - part))) - (mapv (let [g (generation)] - (fn [note-data] - (-> note-data - (assoc :gen g))))))) - + (->> (read/read-string-all code) + (into [] notes/notebook-xform))) +;; TODO: Not needed? read-kinds has a safe-notes wrapper already... (defn ->safe-notes [code] (try (->notes code)