From d7590efab86fa4e66da5459fa335ff0e3246c1ea Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 30 Aug 2023 11:43:13 +0200 Subject: [PATCH 01/80] wip --- .bb/tasks.bb | 17 +++++++++++++++++ bb.edn | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 .bb/tasks.bb diff --git a/.bb/tasks.bb b/.bb/tasks.bb new file mode 100644 index 00000000..7536e937 --- /dev/null +++ b/.bb/tasks.bb @@ -0,0 +1,17 @@ +(ns tasks + (:require + [babashka.tasks :refer [shell]] + [clojure.string :as str])) + +(defn watch-cljs [] + (let [watch (requiring-resolve 'pod.babashka.fswatcher/watch) + ret (watch "." + (fn [{:keys [type path]}] + (when (and (#{:write :write|chmod :create} type) + (str/ends-with? path ".cljs")) + (shell {:continue true + :err :inherit + :std :inherit} "yarn squint compile" path))) + {:recursive true})] + (println (str "Started watching: " ret)) + @(promise))) diff --git a/bb.edn b/bb.edn index 1d0bba5f..5ffe3944 100644 --- a/bb.edn +++ b/bb.edn @@ -1,15 +1,43 @@ {:min-bb-version "0.7.6" - :paths ["bb"] + :paths [".bb"] + :pods {org.babashka/fswatcher {:version "0.0.4"}} :tasks {:requires ([clojure.edn :as edn] [clojure.string :as str] [babashka.deps :as deps] [babashka.fs :as fs] - [babashka.process :as p]) + [babashka.process :as p] + [tasks :as t]) :init (do (defn viewer-css-path [] (let [cp (str/trim (with-out-str (deps/clojure ["-A:dev:demo" "-Spath"])))] - (str/trim (:out (shell {:out :string} (str "bb -cp " cp " -e '(println (.getPath (clojure.java.io/resource \"css/viewer.css\")))'"))))))) + (str/trim (:out (shell {:out :string} (str "bb -cp " cp " -e '(println (.getPath (clojure.java.io/resource \"css/viewer.css\")))'")))))) + + (defn get-paths [ext] + (map str (fs/glob "." (str "{demo,src,collab}/**." (name ext)))))) copy-viewer-css {:doc "Copies viewer stylesheet to resources." - :task (fs/copy (viewer-css-path) "resources/stylesheets/viewer.css" #{:replace-existing})}}} + :task (fs/copy (viewer-css-path) "resources/stylesheets/viewer.css" #{:replace-existing})} + + yarn-install (shell "yarn install") + + clean (let [paths (get-paths :mjs)] + (println (apply str (interpose "\n" (cons "removing:" paths)))) + (doseq [path paths] (fs/delete path))) + + compile {:doc "Use squintjs to compile all cljs files recursively" + :depends [yarn-install] + :task (shell {:std :inherit :err :inherit} + (apply str (cons "yarn squint compile " + (interpose " " (get-paths :cljs)))))} + + build {:doc "Compiles cljs files with squint and builds from mjs sources with vite" + :depends [compile] + :task (shell {:std :inherit :err :inherit} + "yarn build")} + + watch-cljs (t/watch-cljs) + + dev {:doc "Compiles all cljs to mjs, runs vite in dev and starts a cherry watcher to recompile changed cljs. When run as `bb dev collab` also starts a Y.js collaboration server." + :depends [compile] + :task (run '-dev)}}} From 0f71e166a30fa683ba64c19cd91873d44a4c26d6 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 4 Sep 2023 20:33:31 +0200 Subject: [PATCH 02/80] wip --- .bb/tasks.bb | 8 +- bb.edn | 4 + package.json | 77 +++--- public/squint/index.html | 241 ++++++++++++++++++ public/squint/js/main.js | 1 + .../nextjournal/clojure_mode/chars.mjs | 43 ++++ .../nextjournal/clojure_mode/chars.cljs | 30 +++ src-squint/nextjournal/clojure_mode/chars.mjs | 43 ++++ vite.config.js | 3 + yarn.lock | 190 ++++++++++++++ 10 files changed, 600 insertions(+), 40 deletions(-) create mode 100644 public/squint/index.html create mode 100644 public/squint/js/main.js create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/chars.mjs create mode 100644 src-squint/nextjournal/clojure_mode/chars.cljs create mode 100644 src-squint/nextjournal/clojure_mode/chars.mjs create mode 100644 vite.config.js diff --git a/.bb/tasks.bb b/.bb/tasks.bb index 7536e937..88fe46cb 100644 --- a/.bb/tasks.bb +++ b/.bb/tasks.bb @@ -5,13 +5,15 @@ (defn watch-cljs [] (let [watch (requiring-resolve 'pod.babashka.fswatcher/watch) - ret (watch "." + ret (watch "src-squint" (fn [{:keys [type path]}] (when (and (#{:write :write|chmod :create} type) - (str/ends-with? path ".cljs")) + (str/ends-with? path ".cljs") + ;; emacs shit: + (not (str/includes? path ".#"))) (shell {:continue true :err :inherit - :std :inherit} "yarn squint compile" path))) + :std :inherit} "yarn squint compile --output-dir public/squint/js" path))) {:recursive true})] (println (str "Started watching: " ret)) @(promise))) diff --git a/bb.edn b/bb.edn index 5ffe3944..d3b4d6f2 100644 --- a/bb.edn +++ b/bb.edn @@ -38,6 +38,10 @@ watch-cljs (t/watch-cljs) + vite-dev {:doc "Launches vite application" + :depends [yarn-install] + :task (shell "yarn dev")} + dev {:doc "Compiles all cljs to mjs, runs vite in dev and starts a cherry watcher to recompile changed cljs. When run as `bb dev collab` also starts a Y.js collaboration server." :depends [compile] :task (run '-dev)}}} diff --git a/package.json b/package.json index 1f5e12ae..e38b2408 100644 --- a/package.json +++ b/package.json @@ -1,39 +1,42 @@ { - "dependencies": { - "@codemirror/autocomplete": "^6.0.2", - "@codemirror/commands": "^6.0.0", - "@codemirror/lang-markdown": "6.0.0", - "@codemirror/language": "^6.1.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.1", - "@codemirror/view": "^6.0.2", - "@lezer/common": "^1.0.0", - "@lezer/generator": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "@nextjournal/lezer-clojure": "1.0.0", - "d3-require": "^1.2.4", - "emoji-regex": "^10.0.0", - "framer-motion": "^6.2.8", - "katex": "^0.12.0", - "markdown-it": "12.3.2", - "markdown-it-block-image": "0.0.3", - "markdown-it-sidenote": "gerwitz/markdown-it-sidenote#aa5de8ce3168b7d41cb33c3aed071a5f41ce0083", - "markdown-it-texmath": "0.9.1", - "markdown-it-toc-done-right": "4.2.0", - "punycode": "2.1.1", - "react": "^17.0.2", - "react-dom": "^17.0.2", - "w3c-keyname": "^2.2.4" - }, - "scripts": { - "watch": "bb copy-viewer-css && shadow-cljs -A:demo watch demo livedoc test", - "build": "shadow-cljs -A:demo release demo livedoc", - "test": "shadow-cljs -A:dev release ci-test && node out/node-tests.js", - "watch2": "git ls-files | entr yarn test" - }, - "devDependencies": { - "shadow-cljs": "2.19.5" - } + "dependencies": { + "@codemirror/autocomplete": "^6.0.2", + "@codemirror/commands": "^6.0.0", + "@codemirror/lang-markdown": "6.0.0", + "@codemirror/language": "^6.1.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.1", + "@codemirror/view": "^6.0.2", + "@lezer/common": "^1.0.0", + "@lezer/generator": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "@nextjournal/lezer-clojure": "1.0.0", + "d3-require": "^1.2.4", + "emoji-regex": "^10.0.0", + "framer-motion": "^6.2.8", + "katex": "^0.12.0", + "markdown-it": "12.3.2", + "markdown-it-block-image": "0.0.3", + "markdown-it-sidenote": "gerwitz/markdown-it-sidenote#aa5de8ce3168b7d41cb33c3aed071a5f41ce0083", + "markdown-it-texmath": "0.9.1", + "markdown-it-toc-done-right": "4.2.0", + "punycode": "2.1.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "squint-cljs": "^0.1.17", + "w3c-keyname": "^2.2.4" + }, + "scripts": { + "watch": "bb copy-viewer-css && shadow-cljs -A:demo watch demo livedoc test", + "build": "shadow-cljs -A:demo release demo livedoc", + "test": "shadow-cljs -A:dev release ci-test && node out/node-tests.js", + "watch2": "git ls-files | entr yarn test", + "dev": "vite --open -l info --config vite.config.js demo" + }, + "devDependencies": { + "shadow-cljs": "2.19.5", + "vite": "^4.4.9" + } } diff --git a/public/squint/index.html b/public/squint/index.html new file mode 100644 index 00000000..1a6083a5 --- /dev/null +++ b/public/squint/index.html @@ -0,0 +1,241 @@ + + + + + + Clojure/Script mode for CodeMirror 6 + + + + + + + + + + + + + + + + + + +
+
+
+

Clojure/Script mode for CodeMirror 6

+

+ Enable a decent Clojure/Script editor experience in the browser.
+ Built for and by Nextjournal. +

+ +
+
+
+
+

+ ๐Ÿคนโ€โ™€๏ธ Try it for yourself +

+
+
+

Try evaluating any of these forms with Alt + โŽ !

+

+ In-browser eval is powered by Sci. +

+
+
+
+
    +
  • + โšก๏ธ +
    + Lightning-fast with lezer incremental parsing
    + + Copy clojure/core.clj into ๐Ÿ‘ˆ to try! + +
    +
  • +
  • + ๐Ÿฅค +
    + Slurping & ๐Ÿคฎ Barfing + + + + + + + + + + + + + +
    forward + Ctrl + โ† / โ†’ + + or Mod + โ‡ง + j / k +
    backward + Ctrl + Alt + โ† / โ†’ +
    +
    +
  • +
  • + ๐Ÿ’— +
    + Semantic Selections + + + + + + + + +
    Expand / Contract + Alt + โ†‘ / โ†“ + + or Mod + 1 / 2 +
    +
    +
  • +
  • + ๐Ÿง™ +
    + Evaluation + + + + + + + + + + + + + + + +
    + At Cursor + + Alt + โŽ +
    + Top-level form + + Alt + โ‡ง + โŽ +
    + Cell + + Mod + โŽ +
    +
    +
  • +
  • + ๐Ÿงน +
    + Autoformatting +

    + following Tonskyโ€™s Better Clojure Formatting +

    +
    +
  • +
+
+
+
+
+ +
+
+
+

+ ๐Ÿ“ฆ Use it in your project +

+
+{:deps {nextjournal/clojure-mode {:git/url "https://github.com/nextjournal/clojure-mode"
+                                  :sha "SHA"}}}
+        
+
+
+ +
+
+
+
ยฉ 2020 Nextjournal GmbH
+ +
+
+
+ + + diff --git a/public/squint/js/main.js b/public/squint/js/main.js new file mode 100644 index 00000000..e921523b --- /dev/null +++ b/public/squint/js/main.js @@ -0,0 +1 @@ +console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/chars.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/chars.mjs new file mode 100644 index 00000000..31b90eb2 --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/chars.mjs @@ -0,0 +1,43 @@ +import * as squint_core from 'squint-cljs/core.js'; +import * as text from '@codemirror/text'; +var pair_lookup = (function (char_pairs, char$) { +let end1 = squint_core.count(char_pairs); +let ch2 = text.codePointAt(char, 0); +let i3 = 0; +while(true){ +if ((i3 >= end1)) { +return text.fromCodePoint(((ch2 < 128)) ? (ch2) : ((ch2 + 1)));} else { +if ((ch2 == char_pairs.charCodeAt(i3))) { +return char_pairs.charAt((i3 + 1));} else { +if ("else") { +let G__4 = (i3 + 2); +i3 = G__4; +continue; +} else { +return null;}}};break; +} + +}) +; +var backspace_QMARK_ = (function (code) { +return (code == 8); +}) +; +var next_char = (function (doc, pos) { +let next5 = doc.sliceString(pos, (pos + 2)); +return next5.slice(0, text.codePointSize(text.codePointAt(next5, 0))); +}) +; +var prev_char = (function (doc, pos) { +if (pos_int_QMARK_(pos)) { +return doc.sliceString((pos - 1), pos);} else { +return "";} +}) +; +var whitespace_QMARK_ = squint_core.set(squint_core.map((function (_PERCENT_1) { +return _PERCENT_1.charCodeAt(0); +}), [" ", "n", "r", ","])) +; +null; + +export { pair_lookup, backspace_QMARK_, next_char, prev_char, whitespace_QMARK_ } diff --git a/src-squint/nextjournal/clojure_mode/chars.cljs b/src-squint/nextjournal/clojure_mode/chars.cljs new file mode 100644 index 00000000..59501559 --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/chars.cljs @@ -0,0 +1,30 @@ +(ns nextjournal.clojure-mode.chars + (:require ["@codemirror/text" :as text])) + +(defn pair-lookup [char-pairs ^string char] + (let [end (count char-pairs) + ch (text/codePointAt char 0)] + (loop [i 0] + (cond (>= i end) (text/fromCodePoint (if (< ch 128) ch (inc ch))) + (== ch (.charCodeAt char-pairs i)) (.charAt char-pairs (inc i)) + :else (recur (+ i 2)))))) + +(defn backspace? [^number code] (== code 8)) + +(defn next-char [^js doc ^number pos] + (let [^string next (.sliceString doc pos (+ pos 2))] + (.slice next 0 (text/codePointSize (text/codePointAt next 0))))) + +(defn prev-char [^js doc ^number pos] + (if (pos-int? pos) + (.sliceString doc (dec pos) pos) + "")) + +(def whitespace? (->> [" " \n \r ","] + (map #(.charCodeAt ^string % 0)) + (set))) + +(comment + ;; is there a way to iterate from a position, character by character? + (defn pos-when [doc dir pred] + )) diff --git a/src-squint/nextjournal/clojure_mode/chars.mjs b/src-squint/nextjournal/clojure_mode/chars.mjs new file mode 100644 index 00000000..31b90eb2 --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/chars.mjs @@ -0,0 +1,43 @@ +import * as squint_core from 'squint-cljs/core.js'; +import * as text from '@codemirror/text'; +var pair_lookup = (function (char_pairs, char$) { +let end1 = squint_core.count(char_pairs); +let ch2 = text.codePointAt(char, 0); +let i3 = 0; +while(true){ +if ((i3 >= end1)) { +return text.fromCodePoint(((ch2 < 128)) ? (ch2) : ((ch2 + 1)));} else { +if ((ch2 == char_pairs.charCodeAt(i3))) { +return char_pairs.charAt((i3 + 1));} else { +if ("else") { +let G__4 = (i3 + 2); +i3 = G__4; +continue; +} else { +return null;}}};break; +} + +}) +; +var backspace_QMARK_ = (function (code) { +return (code == 8); +}) +; +var next_char = (function (doc, pos) { +let next5 = doc.sliceString(pos, (pos + 2)); +return next5.slice(0, text.codePointSize(text.codePointAt(next5, 0))); +}) +; +var prev_char = (function (doc, pos) { +if (pos_int_QMARK_(pos)) { +return doc.sliceString((pos - 1), pos);} else { +return "";} +}) +; +var whitespace_QMARK_ = squint_core.set(squint_core.map((function (_PERCENT_1) { +return _PERCENT_1.charCodeAt(0); +}), [" ", "n", "r", ","])) +; +null; + +export { pair_lookup, backspace_QMARK_, next_char, prev_char, whitespace_QMARK_ } diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 00000000..6d916df1 --- /dev/null +++ b/vite.config.js @@ -0,0 +1,3 @@ +export default { + +}; diff --git a/yarn.lock b/yarn.lock index a55b7a29..8804c8e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -136,6 +136,116 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + "@lezer/common@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.0.0.tgz#1c95ae53ec17706aa3cbcc88b52c23f22ed56096" @@ -455,6 +565,34 @@ entities@~2.1.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== +esbuild@^0.18.10: + version "0.18.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + events@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" @@ -488,6 +626,11 @@ framesync@6.0.1: dependencies: tslib "^2.1.0" +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + hash-base@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" @@ -642,6 +785,11 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -714,6 +862,11 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + popmotion@11.0.3: version "11.0.3" resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-11.0.3.tgz#565c5f6590bbcddab7a33a074bb2ba97e24b0cc9" @@ -724,6 +877,15 @@ popmotion@11.0.3: style-value-types "5.0.0" tslib "^2.1.0" +postcss@^8.4.27: + version "8.4.29" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" + integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -838,6 +1000,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rollup@^3.27.1: + version "3.28.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.28.1.tgz#fb44aa6d5e65c7e13fd5bcfff266d0c4ea9ba433" + integrity sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw== + optionalDependencies: + fsevents "~2.3.2" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -886,6 +1055,11 @@ shadow-cljs@2.19.5: which "^1.3.1" ws "^7.4.6" +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" @@ -898,6 +1072,11 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +squint-cljs@^0.1.17: + version "0.1.17" + resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.1.17.tgz#a23350582a44e18a7a5134bf6f97c0eb1f8585d6" + integrity sha512-U7+sWK+NuzDiS32f26OLzMj4aITsJyFP3X8BRhaSRMabf12p0dt0X7j5FFSI6Hv81hnRNTkVyGBejidP/MRcTA== + stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" @@ -998,6 +1177,17 @@ util@^0.11.0: dependencies: inherits "2.0.3" +vite@^4.4.9: + version "4.4.9" + resolved "https://registry.yarnpkg.com/vite/-/vite-4.4.9.tgz#1402423f1a2f8d66fd8d15e351127c7236d29d3d" + integrity sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA== + dependencies: + esbuild "^0.18.10" + postcss "^8.4.27" + rollup "^3.27.1" + optionalDependencies: + fsevents "~2.3.2" + vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" From 5ff263e8bd6651dcbacf8831672e3edeb903040b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 15:16:24 +0200 Subject: [PATCH 03/80] wip --- public/squint/index.html | 2 +- public/squint/js/main.js | 1 - public/squint/js/main.mjs | 4 + .../extensions/close_brackets.mjs | 102 +++ .../nextjournal/clojure_mode/node.mjs | 711 ++++++++++++++++++ .../nextjournal/clojure_mode/selections.mjs | 42 ++ .../nextjournal/clojure_mode/util.mjs | 266 +++++++ .../extensions/close_brackets.cljs | 166 ++++ src-squint/nextjournal/clojure_mode/node.cljs | 421 +++++++++++ .../nextjournal/clojure_mode/selections.cljs | 12 + src-squint/nextjournal/clojure_mode/util.cljs | 169 +++++ vite.config.js | 6 +- 12 files changed, 1899 insertions(+), 3 deletions(-) delete mode 100644 public/squint/js/main.js create mode 100644 public/squint/js/main.mjs create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/selections.mjs create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs create mode 100644 src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs create mode 100644 src-squint/nextjournal/clojure_mode/node.cljs create mode 100644 src-squint/nextjournal/clojure_mode/selections.cljs create mode 100644 src-squint/nextjournal/clojure_mode/util.cljs diff --git a/public/squint/index.html b/public/squint/index.html index 1a6083a5..30da2298 100644 --- a/public/squint/index.html +++ b/public/squint/index.html @@ -236,6 +236,6 @@

- + diff --git a/public/squint/js/main.js b/public/squint/js/main.js deleted file mode 100644 index e921523b..00000000 --- a/public/squint/js/main.js +++ /dev/null @@ -1 +0,0 @@ -console.log('hello'); diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs new file mode 100644 index 00000000..59450f57 --- /dev/null +++ b/public/squint/js/main.mjs @@ -0,0 +1,4 @@ +import './src-squint/nextjournal/clojure_mode/node.mjs'; + +// import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; +console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs new file mode 100644 index 00000000..280d6821 --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs @@ -0,0 +1,102 @@ +import * as squint_core from 'squint-cljs/core.js'; +import { keyName } from 'w3c-keyname'; +import * as view from '@codemirror/view'; +import { EditorState, EditorSelection, Transaction, CharCategory, Extension, Prec } from '@codemirror/state'; +import * as n from 'nextjournal.clojure-mode.node'; +import * as u from 'nextjournal.clojure-mode.util'; +import { from_to } from 'nextjournal.clojure-mode.util'; +import * as str from 'squint-cljs/string.js'; +var in_string_QMARK_ = (function (state, pos) { +return new Set(["StringContent", "String"])(nextjournal.clojure_mode.node.name(nextjournal.clojure_mode.node.tree(state, pos))); +}) +; +var escaped_QMARK_ = (function (state, pos) { +return ("\\" === state["doc"].slice(max(0, (pos - 1)), pos).toString()); +}) +; +var backspace_backoff = (function (state, from, to) { +if (((function () { + let G__12 = nextjournal.clojure_mode.node.node_BAR_(state, (from - 1)); +if (squint_core.nil_QMARK_(G__12)) { +return null;} else { +return nextjournal.clojure_mode.util.guard(G__12, nextjournal.clojure_mode.node.line_comment_QMARK_);} +})() && !str.blank_QMARK_(nextjournal.clojure_mode.util.line_content_at(state, from)))) { +return ({ "cursor": (from - 1) });} else { +return nextjournal.clojure_mode.util.deletion(from, to);} +}) +; +j.defn(handle_backspace, "- skips over closing brackets\n - when deleting an opening bracket of an empty list, removes both brackets", [({ "as": state, "keys": [doc] })], (((1 === state["selection"]["ranges"]["length"]) && (function () { + let range3 = j.get_in(state, ["selection", "ranges", 0]); +return (range3["empty"] && (0 === range3["from"])); +})())) ? (null) : (nextjournal.clojure_mode.util.update_ranges(state, ({ "annotations": nextjournal.clojure_mode.util.user_event_annotation("delete") }), j.fn([({ "as": squint_core.range, "keys": [head, squint_core.empty, anchor] })], j.let$([({ "as": squint_core.range, "from": "from", "to": "to" }), from_to(head, anchor), node_BAR_, nextjournal.clojure_mode.node.tree(state).resolveInner(from, -1), parent, node_BAR_["parent"]], ((!squint_core.empty || ("StringContent" === nextjournal.clojure_mode.node.name(nextjournal.clojure_mode.node.tree(state, from, -1))) || (parent && !nextjournal.clojure_mode.node.balanced_QMARK_(parent) && nextjournal.clojure_mode.node.left_edge_QMARK_(node_BAR_)))) ? (nextjournal.clojure_mode.util.deletion(from, to)) : (((nextjournal.clojure_mode.node.right_edge_QMARK_(node_BAR_) && (from == nextjournal.clojure_mode.node.end(parent)))) ? (({ "cursor": (from - 1) })) : ((((nextjournal.clojure_mode.node.start_edge_QMARK_(node_BAR_) || nextjournal.clojure_mode.node.same_edge_QMARK_(node_BAR_)) && (nextjournal.clojure_mode.node.start(node_BAR_) == nextjournal.clojure_mode.node.start(parent)))) ? ((nextjournal.clojure_mode.node.empty_QMARK_(nextjournal.clojure_mode.node.up(node_BAR_))) ? (({ "cursor": nextjournal.clojure_mode.node.start(parent), "changes": [from_to(nextjournal.clojure_mode.node.start(parent), nextjournal.clojure_mode.node.end(parent))] })) : (({ "cursor": from }))) : (("else") ? (backspace_backoff(state, from, to)) : (null))))))))); +var coll_pairs = ({ "(": ")", "[": "]", "{": "}", "\"": "\"" }) +; +var handle_open = (function (state, open) { +let close4 = coll_pairs(open); +return nextjournal.clojure_mode.util.update_ranges(state, ({ "annotations": nextjournal.clojure_mode.util.user_event_annotation("input") }), j.fn([({ "keys": [from, to, head, anchor, squint_core.empty] })], (in_string_QMARK_(state, from)) ? (((open === "\"")) ? (nextjournal.clojure_mode.util.insertion(head, "\\\"")) : (nextjournal.clojure_mode.util.insertion(from, to, open))) : ((escaped_QMARK_(state, from)) ? (nextjournal.clojure_mode.util.insertion(from, to, open)) : (("else") ? ((squint_core.empty) ? (({ "changes": ({ "insert": squint_core.str(open, close4), "from": head }), "cursor": (head + squint_core.count(open)) })) : (({ "changes": [({ "insert": open, "from": from }), ({ "insert": close4, "from": to })], "from-to": [(anchor + squint_core.count(open)), (head + squint_core.count(open))] }))) : (null))))); +}) +; +var handle_close = (function (state, key_name) { +return nextjournal.clojure_mode.util.update_ranges(state, ({ "annotations": nextjournal.clojure_mode.util.user_event_annotation("input") }), j.fn([({ "as": squint_core.range, "keys": [squint_core.empty, head, from, to] })], ((in_string_QMARK_(state, from) || escaped_QMARK_(state, from))) ? (nextjournal.clojure_mode.util.insertion(from, to, key_name)) : ((squint_core.empty) ? (((function () { + let unbalanced5 = (function () { + let G__67 = nextjournal.clojure_mode.node.tree(state, head, -1); +let G__68 = (squint_core.nil_QMARK_(G__67)) ? (null) : (nextjournal.clojure_mode.node.ancestors(G__67)); +let G__69 = (squint_core.nil_QMARK_(G__68)) ? (null) : (squint_core.filter(every_pred(nextjournal.clojure_mode.node.coll_QMARK_, squint_core.complement(nextjournal.clojure_mode.node.balanced_QMARK_)), G__68)); +if (squint_core.nil_QMARK_(G__69)) { +return null;} else { +return squint_core.first(G__69);} +})(); +let closing10 = (function () { + let G__1112 = unbalanced5; +let G__1113 = (squint_core.nil_QMARK_(G__1112)) ? (null) : (nextjournal.clojure_mode.node.down(G__1112)); +if (squint_core.nil_QMARK_(G__1113)) { +return null;} else { +return nextjournal.clojure_mode.node.closed_by(G__1113);} +})(); +let pos14 = (function () { + let G__1516 = unbalanced5; +if (squint_core.nil_QMARK_(G__1516)) { +return null;} else { +return nextjournal.clojure_mode.node.end(G__1516);} +})(); +if ((closing10 && (closing10 === key_name))) { +return ({ "changes": ({ "from": pos14, "insert": closing10 }), "cursor": (pos14 + 1) });} +})() || (function () { + let temp__25187__auto__17 = (function () { + let temp__25187__auto__18 = nextjournal.clojure_mode.node.terminal_cursor(nextjournal.clojure_mode.node.tree(state), head, 1); +if (temp__25187__auto__18) { +let cursor19 = temp__25187__auto__18; +while(true){ +if (nextjournal.clojure_mode.node.right_edge_type_QMARK_(cursor19["type"])) { +return nextjournal.clojure_mode.node.end(cursor19);} else { +if (cursor19.next()) { +continue; +}};break; +} +} +})(); +if (temp__25187__auto__17) { +let close_node_end20 = temp__25187__auto__17; +return ({ "cursor": close_node_end20 });} +})() || ({ "cursor": head }))) : (null)))); +}) +; +j.defn(handle_backspace_cmd, [({ "as": view, "keys": [state] })], nextjournal.clojure_mode.util.dispatch_some(view, handle_backspace(state))); +var handle_open_cmd = (function (key_name) { +return j.fn([({ "as": view, "keys": [state] })], nextjournal.clojure_mode.util.dispatch_some(view, handle_open(state, key_name))); +}) +; +var handle_close_cmd = (function (key_name) { +return j.fn([({ "as": view, "keys": [state] })], nextjournal.clojure_mode.util.dispatch_some(view, handle_close(state, key_name))); +}) +; +var guard_scope = (function (cmd) { +return j.fn([({ "as": view, "keys": [state] })], ((nextjournal.clojure_mode.node.embedded_QMARK_(state) || nextjournal.clojure_mode.node.within_program_QMARK_(state))) ? (cmd(view)) : (false)); +}) +; +var extension = (function () { +return Prec.high(view.keymap.of(j.lit([({ "key": "Backspace", "run": guard_scope(j.fn([({ "as": view, "keys": [state] })], nextjournal.clojure_mode.util.dispatch_some(view, handle_backspace(state)))) }), ({ "key": "(", "run": guard_scope(handle_open_cmd("(")) }), ({ "key": "[", "run": guard_scope(handle_open_cmd("[")) }), ({ "key": "{", "run": guard_scope(handle_open_cmd("{")) }), ({ "key": "\"", "run": guard_scope(handle_open_cmd("\"")) }), ({ "key": ")", "run": guard_scope(handle_close_cmd(")")) }), ({ "key": "]", "run": guard_scope(handle_close_cmd("]")) }), ({ "key": "}", "run": guard_scope(handle_close_cmd("}")) })]))); +}) +; + +export { handle_close_cmd, backspace_backoff, escaped_QMARK_, guard_scope, handle_close, handle_open_cmd, extension, in_string_QMARK_, handle_open, coll_pairs } diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs new file mode 100644 index 00000000..f900267e --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs @@ -0,0 +1,711 @@ +import * as squint_core from 'squint-cljs/core.js'; +import * as lz_tree from '@lezer/common'; +import * as lezer_markdown from '@lezer/markdown'; +import * as language from '@codemirror/language'; +import * as lezer_clj from '@nextjournal/lezer-clojure'; +import * as u from './util.mjs'; +import * as sel from './selections.mjs'; +var coll_prop = lezer_clj.props["coll"] +; +var prefix_coll_prop = lezer_clj.props["prefixColl"] +; +var prefix_edge_prop = lezer_clj.props["prefixEdge"] +; +var prefix_container_prop = lezer_clj.props["prefixContainer"] +; +var start_edge_prop = lz_tree.NodeProp["closedBy"] +; +var end_edge_prop = lz_tree.NodeProp["openedBy"] +; +var same_edge_prop = lezer_clj.props["sameEdge"] +; +var node_prop = (function (prop_name) { +let G__12 = prop_name; +switch (G__12) {case "prefixColl": +return prefix_coll_prop; +break; +case "coll": +return coll_prop; +break; +case "prefixEdge": +return prefix_edge_prop; +break; +case "prefixContainer": +return prefix_container_prop; +break; +case "sameEdge": +return same_edge_prop; +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__12))} +}) +; +var type = (function (node) { +return node["type"]; +}) +; +var start = (function (node) { +assert(node["from"]); +return node["from"]; +}) +; +var end = (function (node) { +assert(node["to"]); +return node["to"]; +}) +; +var up = (function (node) { +return node["parent"]; +}) +; +var down = (function (node) { +assert(!fn_QMARK_(node["lastChild"])); +return node["firstChild"]; +}) +; +var down_last = (function (node) { +assert(!fn_QMARK_(node["lastChild"])); +return node["lastChild"]; +}) +; +var depth = (function (node) { +let node4 = node; +let i5 = 0; +while(true){ +let temp__25059__auto__6 = up(node4); +if (squint_core.nil_QMARK_(temp__25059__auto__6)) { +return i5;} else { +let parent7 = temp__25059__auto__6; +let G__8 = parent7; +let G__9 = (i5 + 1); +node4 = G__8; +i5 = G__9; +continue; +};break; +} + +}) +; +var left = (function (node) { +return up(node).childBefore(start(node)); +}) +; +var lefts = (function (node) { +return squint_core.take_while(squint_core.identity, iterate(left, left(node))); +}) +; +var right = (function (node) { +return up(node).childAfter(end(node)); +}) +; +var rights = (function (node) { +return squint_core.take_while(squint_core.identity, iterate(right, right(node))); +}) +; +var coll_type_QMARK_ = (function (node_type) { +return (node_type.prop(coll_prop)); +}) +; +var prefix_type_QMARK_ = (function (node_type) { +return node_type.prop(prefix_coll_prop); +}) +; +var prefix_edge_type_QMARK_ = (function (node_type) { +return node_type.prop(prefix_edge_prop); +}) +; +var prefix_container_type_QMARK_ = (function (node_type) { +return node_type.prop(prefix_container_prop); +}) +; +var same_edge_type_QMARK_ = (function (node_type) { +return node_type.prop(same_edge_prop); +}) +; +var start_edge_type_QMARK_ = (function (node_type) { +return node_type.prop(start_edge_prop); +}) +; +var end_edge_type_QMARK_ = (function (node_type) { +return node_type.prop(end_edge_prop); +}) +; +var top_type_QMARK_ = (function (node_type) { +return node_type["isTop"]; +}) +; +var error_type_QMARK_ = (function (node_type) { +return node_type["isError"]; +}) +; +var prefix_QMARK_ = (function (n) { +return prefix_type_QMARK_(type(n)); +}) +; +var prefix_edge_QMARK_ = (function (n) { +return prefix_edge_type_QMARK_(type(n)); +}) +; +var prefix_container_QMARK_ = (function (n) { +return prefix_container_type_QMARK_(type(n)); +}) +; +var same_edge_QMARK_ = (function (n) { +return same_edge_type_QMARK_(type(n)); +}) +; +var start_edge_QMARK_ = (function (n) { +return start_edge_type_QMARK_(type(n)); +}) +; +var end_edge_QMARK_ = (function (n) { +return end_edge_type_QMARK_(type(n)); +}) +; +var left_edge_type_QMARK_ = (function (t) { +return (start_edge_type_QMARK_(t) || same_edge_type_QMARK_(t) || prefix_edge_type_QMARK_(t)); +}) +; +var left_edge_QMARK_ = (function (n) { +return left_edge_type_QMARK_(type(n)); +}) +; +var right_edge_type_QMARK_ = (function (t) { +return (end_edge_type_QMARK_(t) || same_edge_type_QMARK_(t)); +}) +; +var right_edge_QMARK_ = (function (n) { +return right_edge_type_QMARK_(type(n)); +}) +; +var edge_QMARK_ = (function (n) { +let t10 = type(n); +return (start_edge_type_QMARK_(t10) || end_edge_type_QMARK_(t10) || same_edge_type_QMARK_(t10) || prefix_type_QMARK_(t10)); +}) +; +var closed_by = (function (n) { +let G__1112 = type(n).prop(lz_tree.NodeProp["closedBy"]); +if (squint_core.nil_QMARK_(G__1112)) { +return null;} else { +return G__1112[0];} +}) +; +var opened_by = (function (n) { +let G__1314 = type(n).prop(lz_tree.NodeProp["openedBy"]); +if (squint_core.nil_QMARK_(G__1314)) { +return null;} else { +return G__1314[0];} +}) +; +var name = (function (node) { +return node["name"]; +}) +; +var error_QMARK_ = (function (node) { +return error_type_QMARK_(node); +}) +; +var top_QMARK_ = (function (node) { +return top_type_QMARK_(type(node)); +}) +; +var program_QMARK_ = (function (node) { +return squint_core.identical_QMARK_("Program", name(node)); +}) +; +var string_QMARK_ = (function (node) { +return squint_core.identical_QMARK_("String", name(node)); +}) +; +var regexp_QMARK_ = (function (node) { +return squint_core.identical_QMARK_("RegExp", name(node)); +}) +; +var line_comment_QMARK_ = (function (node) { +return squint_core.identical_QMARK_("LineComment", name(node)); +}) +; +var discard_QMARK_ = (function (node) { +return squint_core.identical_QMARK_("Discard", name(node)); +}) +; +null; +var coll_QMARK_ = (function (node) { +return coll_type_QMARK_(type(node)); +}) +; +var terminal_type_QMARK_ = (function (node_type) { +if (top_type_QMARK_(node_type)) { +return false;} else { +if (node_type.prop(prefix_coll_prop)) { +return false;} else { +if (node_type.prop(coll_prop)) { +return false;} else { +if (squint_core.identical_QMARK_("Meta", name(node_type))) { +return false;} else { +if (squint_core.identical_QMARK_("TaggedLiteral", name(node_type))) { +return false;} else { +if (squint_core.identical_QMARK_("ConstructorCall", name(node_type))) { +return false;} else { +if ("else") { +return true;} else { +return null;}}}}}}} +}) +; +j.defn(balanced_QMARK_, [({ "as": node, "keys": [firstChild, lastChild] })], (function () { + let temp__24970__auto__15 = closed_by(firstChild); +if (temp__24970__auto__15) { +let closing16 = temp__24970__auto__15; +return ((closing16 === name(lastChild)) && (end(firstChild) !== end(lastChild)));} else { +return true;} +})()); +var ancestors = (function (node) { +let temp__25231__auto__17 = up(node); +if (squint_core.nil_QMARK_(temp__25231__auto__17)) { +return null;} else { +let parent18 = temp__25231__auto__17; +return squint_core.cons(parent18, new squint_core.LazySeq((function () { +return ancestors(parent18); +})));} +}) +; +var closest = (function (node, pred) { +if (pred(node)) { +return node;} else { +return squint_core.reduce((function (_, x) { +if (pred(x)) { +return squint_core.reduced(x);} +}), null, ancestors(node));} +}) +; +var highest = (function (node, pred) { +return squint_core.reduce((function (found, x) { +if (pred(x)) { +return x;} else { +return squint_core.reduced(found);} +}), null, squint_core.cons(node, ancestors(node))); +}) +; +var children = (function () { + let f19 = (function (var_args) { +let G__2223 = arguments["length"]; +switch (G__2223) {case 3: +return f19.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +break; +case 1: +return f19.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f19["cljs$core$IFn$_invoke$arity$3"] = (function (parent, from, dir) { +let temp__25231__auto__25 = (function () { + let G__2627 = dir; +switch (G__2627) {case 1: +return parent.childAfter(from); +break; +case -1: +return parent.childBefore(from); +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__2627))} +})(); +if (squint_core.nil_QMARK_(temp__25231__auto__25)) { +return null;} else { +let child29 = temp__25231__auto__25; +return squint_core.cons(child29, new squint_core.LazySeq((function () { +return children(parent, (function () { + let G__3031 = dir; +switch (G__3031) {case 1: +return end(child29); +break; +case -1: +return start(child29); +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__3031))} +})(), dir); +})));} +}); +f19["cljs$core$IFn$_invoke$arity$1"] = (function (subtree) { +return children(subtree, start(subtree), 1); +}); +f19["cljs$lang$maxFixedArity"] = 3; +return f19; +})() +; +var eq_QMARK_ = (function (x, y) { +return ((start(x) == start(y)) && (end(x) == end(y)) && (depth(x) == depth(y))); +}) +; +var empty_QMARK_ = (function (node) { +let type_name33 = name(node); +if (coll_QMARK_(node)) { +return eq_QMARK_(right(down(node)), down_last(node));} else { +if (("String" === type_name33)) { +return (end(down(node)) == start(down_last(node)));} else { +if ("else") { +return false;} else { +return null;}}} +}) +; +var from_to = (function () { + let f34 = (function (var_args) { +let G__3738 = arguments["length"]; +switch (G__3738) {case 2: +return f34.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +case 1: +return f34.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f34["cljs$core$IFn$_invoke$arity$2"] = (function (from, to) { +return ({ "from": from, "to": to }); +}); +f34["cljs$core$IFn$_invoke$arity$1"] = (function (node) { +return from_to(start(node), end(node)); +}); +f34["cljs$lang$maxFixedArity"] = 2; +return f34; +})() +; +var range = (function (node) { +return sel.range(start(node), end(node)); +}) +; +var string = (function () { + let f40 = (function (var_args) { +let G__4344 = arguments["length"]; +switch (G__4344) {case 2: +return f40.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +case 3: +return f40.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f40["cljs$core$IFn$_invoke$arity$2"] = (function (state, node) { +return string(state, start(node), end(node)); +}); +f40["cljs$core$IFn$_invoke$arity$3"] = (function (state, from, to) { +return state["doc"].sliceString(from, to, "\n"); +}); +f40["cljs$lang$maxFixedArity"] = 3; +return f40; +})() +; +var ancestor_QMARK_ = (function (parent, child) { +return squint_core.boolean$(((start(parent) <= start(child)) && (end(parent) >= end(child)) && (depth(parent) < depth(child)))); +}) +; +var move_toward = (function (node, to_node) { +if (eq_QMARK_(node, to_node)) { +return null;} else { +let G__4647 = compare(start(to_node), start(node)); +switch (G__4647) {case 0: +if (ancestor_QMARK_(to_node, node)) { +return up(node);} else { +if (ancestor_QMARK_(node, to_node)) { +return down(node);} else { +return null;}} +break; +case -1: +if (ancestor_QMARK_(node, to_node)) { +return down_last(node);} else { +return (left(node) || up(node));} +break; +case 1: +if (ancestor_QMARK_(node, to_node)) { +return down(node);} else { +return (right(node) || up(node));} +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__4647))}} +}) +; +var nodes_between = (function (node, to_node) { +return squint_core.take_while(squint_core.identity, iterate((function (_PERCENT_1) { +return move_toward(_PERCENT_1, to_node); +}), node)); +}) +; +var require_balance_QMARK_ = (function (node) { +return (coll_QMARK_(node) || string_QMARK_(node) || regexp_QMARK_(node)); +}) +; +var tree = (function () { + let f49 = (function (var_args) { +let G__5253 = arguments["length"]; +switch (G__5253) {case 1: +return f49.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +case 2: +return f49.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +case 3: +return f49.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f49["cljs$core$IFn$_invoke$arity$1"] = (function (state) { +return language.syntaxTree(state); +}); +f49["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { +return language.syntaxTree(state).resolveInner(pos); +}); +f49["cljs$core$IFn$_invoke$arity$3"] = (function (state, pos, dir) { +return language.syntaxTree(state).resolveInner(pos, dir); +}); +f49["cljs$lang$maxFixedArity"] = 3; +return f49; +})() +; +var cursor = (function () { + let f55 = (function (var_args) { +let G__5859 = arguments["length"]; +switch (G__5859) {case 1: +return f55.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +case 2: +return f55.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +case 3: +return f55.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f55["cljs$core$IFn$_invoke$arity$1"] = (function (tree) { +return tree.cursor(); +}); +f55["cljs$core$IFn$_invoke$arity$2"] = (function (tree, pos) { +return tree.cursorAt(pos); +}); +f55["cljs$core$IFn$_invoke$arity$3"] = (function (tree, pos, dir) { +return tree.cursorAt(pos, dir); +}); +f55["cljs$lang$maxFixedArity"] = 3; +return f55; +})() +; +var terminal_cursor = (function (tree, pos, dir) { +let i61 = pos; +while(true){ +let c62 = cursor(tree, i61, dir); +let type63 = c62["type"]; +if (top_type_QMARK_(type63)) { +return null;} else { +if (terminal_type_QMARK_(c62["type"])) { +return c62;} else { +if ("else") { +let G__64 = (dir + i61); +i61 = G__64; +continue; +} else { +return null;}}};break; +} + +}) +; +var up_here = (function (node) { +let from65 = start(node); +return (highest(node, (function (_PERCENT_1) { +return (from65 === start(_PERCENT_1)); +})) || node); +}) +; +var topmost_cursor = (function (state, from) { +return up_here(tree(state, from, 1)["node"]).cursor(); +}) +; +var terminal_nodes = (function (state, from, to) { +let cursor66 = topmost_cursor(state, from); +let found67 = []; +while(true){ +let node_type68 = type(cursor66); +if ((start(cursor66) > to)) { +return found67;} else { +if ((terminal_type_QMARK_(node_type68) || error_QMARK_(node_type68))) { +let found69 = squint_core.conj(found67, ({ "type": node_type68, "from": start(cursor66), "to": end(cursor66) })); +cursor66.lastChild(); +if (cursor66.next()) { +let G__70 = found69; +found67 = G__70; +continue; +} else { +return found69;}} else { +if ("else") { +if (cursor66.next()) { +let G__71 = found67; +found67 = G__71; +continue; +} else { +return found67;}} else { +return null;}}};break; +} + +}) +; +j.defn(balanced_range, [state, node](balanced_range(state, start(node), end(node))), [state, from, to]((function () { + let vec__7278 = squint_core.sort([from, to]); +let from79 = squint_core.nth(vec__7278, 0, null); +let to80 = squint_core.nth(vec__7278, 1, null); +let from_node81 = tree(state, from79, 1); +let to_node82 = tree(state, to80, -1); +let from83 = (require_balance_QMARK_(from_node81)) ? (start(from_node81)) : (from79); +let to84 = (require_balance_QMARK_(to_node82)) ? (end(to_node82)) : (to80); +let vec__7585 = squint_core.reduce((function (p__86, node_between) { +let vec__8790 = p__86; +let left91 = squint_core.nth(vec__8790, 0, null); +let right92 = squint_core.nth(vec__8790, 1, null); +return [(ancestor_QMARK_(node_between, from_node81)) ? (start(node_between)) : (left91), (ancestor_QMARK_(node_between, to_node82)) ? (end(node_between)) : (right92)]; +}), [from83, to84], squint_core.map((function (_PERCENT_1) { +let G__9394 = _PERCENT_1; +if (edge_QMARK_(_PERCENT_1)) { +return up(G__9394);} else { +return G__9394;} +}), nodes_between(from_node81, to_node82))); +let left95 = squint_core.nth(vec__7585, 0, null); +let right96 = squint_core.nth(vec__7585, 1, null); +return sel.range(left95, right96); +})())); +j.defn(inner_span, "Span of collection not including edges", [({ "as": node, "keys": [firstChild, lastChild] })], ({ "from": (left_edge_QMARK_(firstChild)) ? (end(firstChild)) : (start(node)), "to": (right_edge_QMARK_(lastChild)) ? (start(lastChild)) : (end(node)) })); +var within_QMARK__LT_ = (function (parent, child) { +let c197 = compare(start(parent), start(child)); +let c298 = compare(end(parent), end(child)); +return ((squint_core.pos_QMARK_(c197) || squint_core.neg_QMARK_(c298)) && !squint_core.neg_QMARK_(c197) && !squint_core.pos_QMARK_(c298)); +}) +; +var within_QMARK_ = (function (parent, child) { +return (!squint_core.neg_QMARK_(compare(start(parent), start(child))) && !squint_core.pos_QMARK_(compare(end(parent), end(child)))); +}) +; +var follow_edges = (function (node) { +if (edge_QMARK_(node)) { +return up(node);} else { +return node;} +}) +; +var prefix = (function (node) { +let temp__25231__auto__99 = up(node); +if (squint_core.nil_QMARK_(temp__25231__auto__99)) { +return null;} else { +let parent100 = temp__25231__auto__99; +return (u.guard(parent100, prefix_container_QMARK_) || u.guard(down(parent100), prefix_edge_QMARK_));} +}) +; +var left_edge_with_prefix = (function (state, node) { +return squint_core.str((function () { + let G__101102 = prefix(node); +if (squint_core.nil_QMARK_(G__101102)) { +return null;} else { +return string(state, G__101102);} +})(), name(down(node))); +}) +; +var with_prefix = (function (node) { +let G__103104 = node; +if (prefix(node)) { +return up(G__103104);} else { +return G__103104;} +}) +; +var node_BAR_ = (function (state, pos) { +let G__105106 = tree(state, pos, -1); +if (squint_core.nil_QMARK_(G__105106)) { +return null;} else { +return u.guard(G__105106, (function (_PERCENT_1) { +return (pos === end(_PERCENT_1)); +}));} +}) +; +var _BAR_node = (function (state, pos) { +let G__107108 = tree(state, pos, 1); +if (squint_core.nil_QMARK_(G__107108)) { +return null;} else { +return u.guard(G__107108, (function (_PERCENT_1) { +return (pos === start(_PERCENT_1)); +}));} +}) +; +var nearest_touching = (function (state, pos, dir) { +let L109 = (function () { + let G__110111 = tree(state, pos, -1); +if (squint_core.nil_QMARK_(G__110111)) { +return null;} else { +return u.guard(G__110111, j.fn([({ "keys": [to] })], (pos === to)));} +})(); +let R112 = (function () { + let G__113114 = tree(state, pos, 1); +if (squint_core.nil_QMARK_(G__113114)) { +return null;} else { +return u.guard(G__113114, j.fn([({ "keys": [from] })], (pos === from)));} +})(); +let mid115 = tree(state, pos); +let G__116117 = dir; +switch (G__116117) {case 1: +return (u.guard(R112, every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { +return (same_edge_QMARK_(_PERCENT_1) || !right_edge_QMARK_(_PERCENT_1)); +}))) || L109 || R112 || mid115); +break; +case -1: +return (u.guard(L109, every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { +return (same_edge_QMARK_(_PERCENT_1) || !left_edge_QMARK_(_PERCENT_1)); +}))) || R112 || L109 || mid115); +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__116117))} +}) +; +var embedded_QMARK_ = (function () { + let f119 = (function (var_args) { +let G__122123 = arguments["length"]; +switch (G__122123) {case 1: +return f119.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +case 2: +return f119.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f119["cljs$core$IFn$_invoke$arity$1"] = (function (state) { +return embedded_QMARK_(state, state["selection"]["main"]["head"]); +}); +f119["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { +return squint_core.identical_QMARK_(lezer_markdown.parser.nodeTypes["FencedCode"], state["tree"].resolve(pos)["type"]["id"]); +}); +f119["cljs$lang$maxFixedArity"] = 2; +return f119; +})() +; +var within_program_QMARK_ = (function () { + let f125 = (function (var_args) { +let G__128129 = arguments["length"]; +switch (G__128129) {case 1: +return f125.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +case 2: +return f125.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f125["cljs$core$IFn$_invoke$arity$1"] = (function (state) { +return within_program_QMARK_(state, state["selection"]["main"]["head"]); +}); +f125["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { +let n131 = tree(state, pos); +return (program_QMARK_(n131) || squint_core.some(program_QMARK_, ancestors(n131))); +}); +f125["cljs$lang$maxFixedArity"] = 2; +return f125; +})() +; +null; + +export { end_edge_prop, ancestors, range, string_QMARK_, within_QMARK__LT_, edge_QMARK_, right, terminal_nodes, string, same_edge_type_QMARK_, up, line_comment_QMARK_, prefix_coll_prop, prefix, left_edge_with_prefix, top_QMARK_, empty_QMARK_, terminal_type_QMARK_, left_edge_type_QMARK_, children, nodes_between, prefix_edge_QMARK_, discard_QMARK_, right_edge_type_QMARK_, prefix_container_QMARK_, topmost_cursor, coll_prop, closed_by, error_QMARK_, _BAR_node, start_edge_type_QMARK_, prefix_container_prop, down_last, prefix_QMARK_, name, same_edge_QMARK_, prefix_container_type_QMARK_, rights, with_prefix, start, tree, closest, cursor, node_prop, from_to, follow_edges, start_edge_QMARK_, highest, embedded_QMARK_, opened_by, coll_QMARK_, down, type, terminal_cursor, within_QMARK_, depth, prefix_type_QMARK_, same_edge_prop, nearest_touching, regexp_QMARK_, top_type_QMARK_, error_type_QMARK_, up_here, ancestor_QMARK_, end_edge_type_QMARK_, right_edge_QMARK_, start_edge_prop, prefix_edge_prop, node_BAR_, left_edge_QMARK_, coll_type_QMARK_, lefts, require_balance_QMARK_, end, prefix_edge_type_QMARK_, within_program_QMARK_, left, end_edge_QMARK_, program_QMARK_, move_toward, eq_QMARK_ } diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/selections.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/selections.mjs new file mode 100644 index 00000000..f99ee7a5 --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/selections.mjs @@ -0,0 +1,42 @@ +import * as squint_core from 'squint-cljs/core.js'; +import { EditorSelection } from '@codemirror/state'; +var range = (function () { + let f1 = (function (var_args) { +let G__45 = arguments["length"]; +switch (G__45) {case 2: +return f1.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +case 1: +return f1.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f1["cljs$core$IFn$_invoke$arity$2"] = (function (from, to) { +return EditorSelection.range(from, to); +}); +f1["cljs$core$IFn$_invoke$arity$1"] = (function (range) { +return EditorSelection.range(range["from"], range["to"]); +}); +f1["cljs$lang$maxFixedArity"] = 2; +return f1; +})() +; +var cursor = (function (from) { +return EditorSelection.cursor(from); +}) +; +var create = (function (ranges, index) { +return EditorSelection.create(ranges, index); +}) +; +var constrain = (function (state, from) { +return min(max(from, 0), state["doc"]["length"]); +}) +; +var eq_QMARK_ = (function (sel1, sel2) { +return sel1.eq(sel2); +}) +; + +export { range, cursor, create, constrain, eq_QMARK_ } diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs new file mode 100644 index 00000000..37041fe2 --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs @@ -0,0 +1,266 @@ +import * as squint_core from 'squint-cljs/core.js'; +import { EditorSelection, ChangeSet, ChangeDesc, TransactionSpec, StrictTransactionSpec, StateEffect, Transaction } from '@codemirror/state'; +import * as sel from './selections'; +goog_define(node_js_QMARK_, false); +var user_event_annotation = (function (event_name) { +return Transaction["userEvent"].of(event_name); +}) +; +var get_user_event_annotation = (function (tr) { +return tr.annotation(Transaction["userEvent"]); +}) +; +var guard = (function (x, f) { +if (f(x)) { +return x;} +}) +; +var from_to = (function (p1, p2) { +if ((p1 > p2)) { +return ({ "from": p2, "to": p1 });} else { +return ({ "from": p1, "to": p2 });} +}) +; +var dispatch_some = (function (view, tr) { +if (tr) { +view.dispatch(tr); +return true;} else { +return false;} +}) +; +var insertion = (function () { + let f1 = (function (var_args) { +let G__45 = arguments["length"]; +switch (G__45) {case 2: +return f1.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +case 3: +return f1.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f1["cljs$core$IFn$_invoke$arity$2"] = (function (from, s) { +return insertion(from, from, s); +}); +f1["cljs$core$IFn$_invoke$arity$3"] = (function (from, to, s) { +return ({ "changes": ({ "insert": s, "from": from, "to": to }), "cursor": (from + squint_core.count(s)) }); +}); +f1["cljs$lang$maxFixedArity"] = 3; +return f1; +})() +; +var deletion = (function () { + let f7 = (function (var_args) { +let G__1011 = arguments["length"]; +switch (G__1011) {case 1: +return f7.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +case 2: +return f7.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f7["cljs$core$IFn$_invoke$arity$1"] = (function (from) { +return deletion(max(0, (from - 1)), from); +}); +f7["cljs$core$IFn$_invoke$arity$2"] = (function (from, to) { +let from13 = ((from === to)) ? (max(0, (from - 1))) : (from); +return ({ "cursor": from13, "changes": ({ "from": from13, "to": to }) }); +}); +f7["cljs$lang$maxFixedArity"] = 2; +return f7; +})() +; +var line_content_at = (function (state, from) { +return j.call(j.call_in(state, ["doc", "lineAt"], from), "slice"); +}) +; +var map_cursor = (function (original_range, state, update_map) { +assert(map_QMARK_(update_map)); +let map__1415 = guard(update_map, map_QMARK_); +let mapped16 = squint_core.get(map__1415, "cursor/mapped"); +let cursor17 = squint_core.get(map__1415, "cursor"); +let from_to18 = squint_core.get(map__1415, "from-to"); +let range19 = squint_core.get(map__1415, "range"); +let changes20 = squint_core.get(map__1415, "changes"); +let change_desc21 = (changes20) ? (state.changes(clj__GT_js(changes20))) : (null); +let G__2223 = ({ "range": (range19 || (mapped16) ? (sel.cursor(change_desc21.mapPos(mapped16))) : ((cursor17) ? (sel.cursor(cursor17)) : ((from_to18) ? (sel.range(from_to18(0), from_to18(1))) : (null))) || original_range) }); +if (change_desc21) { +return j._BANG_set(G__2223, "changes", change_desc21);} else { +return G__2223;} +}) +; +var update_ranges = (function () { + let f24 = (function (var_args) { +let G__2728 = arguments["length"]; +switch (G__2728) {case 2: +return f24.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +case 3: +return f24.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f24["cljs$core$IFn$_invoke$arity$2"] = (function (state, f) { +return update_ranges(state, null, f); +}); +f24["cljs$core$IFn$_invoke$arity$3"] = (function (state, tr_specs, f) { +return state.update((function (_PERCENT_1) { +return j.extend_BANG_(_PERCENT_1, tr_specs); +})(state.changeByRange((function (range) { +return ((function () { + let temp__25231__auto__30 = f(range); +if (squint_core.nil_QMARK_(temp__25231__auto__30)) { +return null;} else { +let result31 = temp__25231__auto__30; +return map_cursor(range, state, result31);} +})() || ({ "range": range })); +})))); +}); +f24["cljs$lang$maxFixedArity"] = 3; +return f24; +})() +; +var dispatch_changes = (function (state, dispatch, changes) { +if (changes["empty"]) { +return null;} else { +return dispatch(state.update(({ "changes": changes })));} +}) +; +var update_lines = (function () { + let f32 = (function (var_args) { +let args3338 = []; +let len__24329__auto__39 = arguments["length"]; +let i3440 = 0; +while(true){ +if ((i3440 < len__24329__auto__39)) { +args3338.push((arguments[i3440])); +let G__41 = (i3440 + 1); +i3440 = G__41; +continue; +};break; +} +; +let argseq__24575__auto__42 = ((2 < args3338["length"])) ? (args3338.slice(2)) : (null); +return f32.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__24575__auto__42); +}); +f32["cljs$core$IFn$_invoke$arity$variadic"] = (function (state, f, p__43) { +let vec__4448 = p__43; +let map__4749 = squint_core.nth(vec__4448, 0, null); +let from50 = squint_core.get(map__4749, "from", 0); +let to51 = squint_core.get(map__4749, "to"); +let spec52 = squint_core.get(map__4749, "spec"); +let iterator53 = state["doc"].iter(); +let result54 = iterator53.next(); +let changes55 = []; +let from_pos56 = from50; +let line_num57 = 1; +while(true){ +return j.let$([({ "keys": [done, lineBreak, value] }), result54], ((done || (from50 > to51))) ? (state.update(j.extend_BANG_(({ "changes": state.changes(changes55) }), spec52))) : (let G__58 = iterator53.next(); +let G__59 = (function () { + let temp__24970__auto__60 = (!lineBreak && f(from_pos56, value, line_num57)); +if (temp__24970__auto__60) { +let change61 = temp__24970__auto__60; +return j.push_BANG_(changes55, change61);} else { +return changes55;} +})(); +let G__62 = (from_pos56 + squint_core.count(value)); +let G__63 = (function () { + let G__6465 = line_num57; +if (lineBreak) { +return (G__6465 + 1);} else { +return G__6465;} +})(); +result54 = G__58; +changes55 = G__59; +from_pos56 = G__62; +line_num57 = G__63; +continue; +));;break; +} + +}); +f32["cljs$lang$maxFixedArity"] = 2; +f32["cljs$lang$applyTo"] = (function (seq35) { +let G__3666 = squint_core.first(seq35); +let seq3567 = next(seq35); +let G__3768 = squint_core.first(seq3567); +let seq3569 = next(seq3567); +let self__24359__auto__70 = this; +return self__24359__auto__70.cljs$core$IFn$_invoke$arity$variadic(G__3666, G__3768, seq3569); +}); +return f32; +})() +; +var update_selected_lines = (function (state, f) { +let at_line71 = squint_core.atom(-1); +let doc72 = state["doc"]; +return state.changeByRange(j.fn([({ "as": squint_core.range, "keys": [from, to, anchor, head] })], j.let$([changes, []], (function () { + let line73 = doc72.lineAt(from); +while(true){ +return j.let$([({ "line-number": "number", "line-to": "to" }), line73], ((line73["number"] > squint_core.deref(at_line71))) ? ((function () { + squint_core.reset_BANG_(at_line71, line_number); +return f(line73, changes, squint_core.range); +})()) : (null), (function () { + let temp__24970__auto__74 = ((to > line_to) && guard(doc72.lineAt((line_to + 1)), (function (_PERCENT_1) { +return (_PERCENT_1["number"] > line_number); +}))); +if (temp__24970__auto__74) { +let next_line75 = temp__24970__auto__74; +let G__76 = next_line75; +line73 = G__76; +continue; +} else { +let change_set77 = state.changes(changes); +return ({ "changes": changes, "range": EditorSelection.range(change_set77.mapPos(anchor, 1), change_set77.mapPos(head, 1)) });} +})());;break; +} + +})()))); +}) +; +var iter_changed_lines = (function (p__78, f) { +let map__7981 = p__78; +let tr82 = map__7981; +let map__8083 = squint_core.get(map__7981, "state"); +let state84 = map__8083; +let doc85 = squint_core.get(map__8083, "doc"); +let changes86 = squint_core.get(map__7981, "changes"); +let effects87 = squint_core.get(map__7981, "effects"); +let selection88 = squint_core.get(map__7981, "selection"); +let at_line89 = squint_core.atom(-1); +let next_changes90 = []; +let _91 = changes86.iterChanges((function (from_a, to_a, from_b, to_b, inserted) { +return j.let$([({ "as": line, "line-number": "number", "line-to": "to" }), doc85.lineAt(from_b)], (function () { + let line92 = line; +while(true){ +if ((line_number > squint_core.deref(at_line89))) { +squint_core.reset_BANG_(at_line89, line_number); +f(line92, next_changes90)}; +if ((to_b <= line_to)) { +return null;} else { +let next_line93 = doc85.lineAt((line_to + 1)); +if ((next_line93 && (next_line93["number"] > line92["number"]))) { +let G__94 = next_line93; +line92 = G__94; +continue; +}};break; +} + +})()); +})); +let next_changeset95 = state84.changes(next_changes90); +if (squint_core.seq(next_changes90)) { +let G__9697 = j.assoc_BANG_(j.select_keys(tr82, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes86.compose(next_changeset95)); +let G__9698 = (selection88) ? (j.assoc_BANG_(G__9697, "selection", state84["selection"].map(next_changeset95))) : (G__9697); +if (effects87) { +return j.assoc_BANG_(G__9698, "effects", StateEffect.mapEffects(effects87, next_changeset95));} else { +return G__9698;}} else { +return tr82;} +}) +; + +export { dispatch_some, guard, dispatch_changes, insertion, deletion, line_content_at, update_selected_lines, map_cursor, get_user_event_annotation, user_event_annotation, update_ranges, from_to, iter_changed_lines, update_lines } diff --git a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs new file mode 100644 index 00000000..9b531669 --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs @@ -0,0 +1,166 @@ +(ns nextjournal.clojure-mode.extensions.close-brackets + (:require ["w3c-keyname" :refer [keyName]] + ["@codemirror/view" :as view] + ["@codemirror/state" :refer [EditorState + EditorSelection + Transaction + CharCategory + Extension + Prec]] + [nextjournal.clojure-mode.node :as n] + [nextjournal.clojure-mode.util :as u :refer [from-to]] + [clojure.string :as str])) + +(defn in-string? [state pos] + (#{"StringContent" "String"} (n/name (n/tree state pos)))) + +(defn escaped? [state pos] + (= \\ (.. state -doc (slice (max 0 (dec pos)) pos) toString))) + +(defn backspace-backoff [state from to] + (if + ;; handle line-comments (backspace should not drag forms up into line comments) + (and + ;; we are directly in front of a line-comment + (some-> (n/node| state (dec from)) (u/guard n/line-comment?)) + ;; current line is blank + (not (str/blank? (u/line-content-at state from)))) + {:cursor (dec from)} + (u/deletion from to))) + +(j/defn handle-backspace + "- skips over closing brackets + - when deleting an opening bracket of an empty list, removes both brackets" + [^:js {:as ^EditorState state :keys [doc]}] + (when-not (and (= 1 (.. state -selection -ranges -length)) + (let [^js range (j/get-in state [:selection :ranges 0])] + (and (.-empty range) (= 0 (.-from range))))) + (u/update-ranges state + #js{:annotations (u/user-event-annotation "delete")} + (j/fn [^:js {:as range :keys [head empty anchor]}] + (j/let [^:js {:as range from :from to :to} (from-to head anchor) + ^js node| (.resolveInner (n/tree state) from -1) ;; node immediately to the left of cursor + ^js parent (.-parent node|)] + (cond + + (or (not empty) ;; selection + (= "StringContent" (n/name (n/tree state from -1))) ;; inside a string + (and parent (not (n/balanced? parent)) (n/left-edge? node|))) ;; unbalanced left-paren + (u/deletion from to) + + ;; entering right edge of collection - skip + (and (n/right-edge? node|) (== from (n/end parent))) + {:cursor (dec from)} + + ;; inside left edge of collection - remove or stop + (and (or (n/start-edge? node|) + (n/same-edge? node|)) (== (n/start node|) (n/start parent))) + (if (n/empty? (n/up node|)) + ;; remove empty collection + {:cursor (n/start parent) + :changes [(from-to (n/start parent) (n/end parent))]} + ;; stop cursor at inner-left of collection + {:cursor from}) + + :else (backspace-backoff state from to))))))) + +(def coll-pairs {"(" ")" + "[" "]" + "{" "}" + \" \"}) + +(defn handle-open [^EditorState state ^string open] + (let [^string close (coll-pairs open)] + (u/update-ranges state + #js{:annotations (u/user-event-annotation "input")} + (j/fn [^:js {:keys [from to head anchor empty]}] + (cond + (in-string? state from) + (if (= open \") + (u/insertion head "\\\"") + (u/insertion from to open)) + ;; allow typing escaped bracket + (escaped? state from) + (u/insertion from to open) + :else + (if empty + {:changes {:insert (str open close) + :from head} + :cursor (+ head (count open))} + ;; wrap selections with brackets + {:changes [{:insert open :from from} + {:insert close :from to}] + :from-to [(+ anchor (count open)) (+ head (count open))]})))))) + +(defn handle-close [state key-name] + (u/update-ranges state + #js{:annotations (u/user-event-annotation "input")} + (j/fn [^:js {:as range :keys [empty head from to]}] + (if (or (in-string? state from) + (escaped? state from)) + (u/insertion from to key-name) + (when empty + (or + ;; close unbalanced (open) collection + (let [unbalanced (some-> + (n/tree state head -1) + (n/ancestors) + (->> (filter (every-pred n/coll? (complement n/balanced?)))) + first) + closing (some-> unbalanced n/down n/closed-by) + pos (some-> unbalanced n/end)] + (when (and closing (= closing key-name)) + {:changes {:from pos + :insert closing} + :cursor (inc pos)})) + + ;; jump to next closing bracket + (when-let [close-node-end + (when-let [^js cursor (-> state n/tree + (n/terminal-cursor head 1))] + (loop [] + (if (n/right-edge-type? (.-type cursor)) + (n/end cursor) + (when (.next cursor) + (recur)))))] + {:cursor close-node-end}) + ;; no-op + {:cursor head} + #_(u/insertion head key-name))))))) + +(j/defn handle-backspace-cmd [^:js {:as view :keys [state]}] + (u/dispatch-some view (handle-backspace state))) + +(defn handle-open-cmd [key-name] + (j/fn [^:js {:as view :keys [state]}] + (u/dispatch-some view (handle-open state key-name)))) + +(defn handle-close-cmd [key-name] + (j/fn [^:js {:as view :keys [state]}] + (u/dispatch-some view (handle-close state key-name)))) + +(defn guard-scope + "Command -> Command + + Guards command for it to be triggered from within the right scope, does nothing and propagates key otherwise" + [cmd] + (j/fn [^:js {:as view :keys [state]}] + (if (or (n/embedded? state) (n/within-program? state)) + (cmd view) + false))) + +(defn extension [] + (.high Prec + (.of view/keymap + (j/lit + [{:key "Backspace" + :run (guard-scope + (j/fn [^:js {:as view :keys [state]}] + (u/dispatch-some view (handle-backspace state))))} + {:key "(" :run (guard-scope (handle-open-cmd "("))} + {:key "[" :run (guard-scope (handle-open-cmd "["))} + {:key "{" :run (guard-scope (handle-open-cmd "{"))} + {:key \" :run (guard-scope (handle-open-cmd \"))} + {:key \) :run (guard-scope (handle-close-cmd \)))} + {:key \] :run (guard-scope (handle-close-cmd \]))} + {:key \} :run (guard-scope (handle-close-cmd \}))}])))) diff --git a/src-squint/nextjournal/clojure_mode/node.cljs b/src-squint/nextjournal/clojure_mode/node.cljs new file mode 100644 index 00000000..75a3706f --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/node.cljs @@ -0,0 +1,421 @@ +(ns nextjournal.clojure-mode.node + (:refer-clojure :exclude [coll? ancestors string? empty? regexp? name range resolve type]) + (:require ["@lezer/common" :as lz-tree] + ["@lezer/markdown" :as lezer-markdown] + ["@codemirror/language" :as language] + ["@nextjournal/lezer-clojure" :as lezer-clj] + ["./util.mjs" :as u] + #_[nextjournal.clojure-mode.util :as u] + ["./selections.mjs" :as sel] + #_[nextjournal.clojure-mode.selections :as sel] + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Node props are marked in the grammar and distinguish categories of nodes + +;; primitive collection +(def coll-prop (.-coll lezer-clj/props)) +;; prefix collection - a prefix token that wraps the next element +(def prefix-coll-prop (.-prefixColl lezer-clj/props)) +;; the prefix edge itself +(def prefix-edge-prop (.-prefixEdge lezer-clj/props)) +;; prefix form - pair of [metadata, target] +(def prefix-container-prop (.-prefixContainer lezer-clj/props)) +;; edges at the beginning/end of collections, + "same" edges (string quotes) +(def start-edge-prop (.-closedBy lz-tree/NodeProp)) +(def end-edge-prop (.-openedBy lz-tree/NodeProp)) +(def same-edge-prop (.-sameEdge lezer-clj/props )) + +;; used when instantiating the parser +(defn node-prop [prop-name] + (case prop-name "prefixColl" prefix-coll-prop + "coll" coll-prop + "prefixEdge" prefix-edge-prop + "prefixContainer" prefix-container-prop + "sameEdge" same-edge-prop)) + +;; these wrapping functions exist mainly to avoid type hints +;; & are mostly compiled away + +(defn ^lz-tree/NodeType type [^js node] (.-type node)) + +(defn ^number start [^js node] + {:pre [(.-from node)]} + (.-from node)) + +(defn ^number end [^js node] + {:pre [(.-to node)]} + (.-to node)) + +;; a more zipper-like interface +(defn ^js up [node] (.-parent ^js node)) + +(defn ^js down [node] + {:pre [(not (fn? (.-lastChild ^js node)))]} + (.-firstChild ^js node)) + +(defn ^js down-last [node] + {:pre [(not (fn? (.-lastChild ^js node)))]} + (.-lastChild ^js node)) + +(defn ^number depth [^js node] + (loop [node node + i 0] + (if-some [parent (up node)] + (recur parent (inc i)) + i))) + +(defn ^js left [^js node] + (.childBefore (up node) (start node)) + #_(.-prevSibling node)) + +(defn lefts [node] + (take-while identity (iterate left (left node)))) + +(defn ^js right [node] + (.childAfter (up node) (end node)) + #_(.-nextSibling node)) + +(defn rights [node] + (take-while identity (iterate right (right node)))) + +;; category predicates + +(defn coll-type? [^js node-type] + (or (.prop node-type coll-prop) + #_(.prop node-type prefix-coll-prop))) + +(defn ^boolean prefix-type? [node-type] (.prop ^js node-type prefix-coll-prop)) +(defn ^boolean prefix-edge-type? [node-type] (.prop ^js node-type prefix-edge-prop)) +(defn ^boolean prefix-container-type? [node-type] (.prop ^js node-type prefix-container-prop)) +(defn ^boolean same-edge-type? [node-type] (.prop ^js node-type same-edge-prop)) +(defn ^boolean start-edge-type? [node-type] (.prop ^js node-type start-edge-prop)) +(defn ^boolean end-edge-type? [node-type] (.prop ^js node-type end-edge-prop)) +(defn ^boolean top-type? [node-type] (.-isTop ^js node-type)) +(defn ^boolean error-type? [node-type] (.-isError ^js node-type)) + +(defn ^boolean prefix? [n] (prefix-type? (type n))) +(defn ^boolean prefix-edge? [n] (prefix-edge-type? (type n))) +(defn ^boolean prefix-container? [n] (prefix-container-type? (type n))) +(defn ^boolean same-edge? [n] (same-edge-type? (type n))) +(defn ^boolean start-edge? [n] + (start-edge-type? (type n))) +(defn ^boolean end-edge? [n] (end-edge-type? (type n))) + +(defn ^boolean left-edge-type? [t] + (or (start-edge-type? t) + (same-edge-type? t) + (prefix-edge-type? t))) + +(defn ^boolean left-edge? [n] + (left-edge-type? (type n))) + +(defn ^boolean right-edge-type? [t] + (or (end-edge-type? t) + (same-edge-type? t))) + +(defn ^boolean right-edge? [n] + (right-edge-type? (type n))) + +(defn ^boolean edge? [n] + (let [t (type n)] + (or (start-edge-type? t) + (end-edge-type? t) + (same-edge-type? t) + (prefix-type? t)))) + +(defn closed-by [n] + (some-> (.prop (type n) (.-closedBy lz-tree/NodeProp)) + (aget 0))) +(defn opened-by [n] + (some-> (.prop (type n) (.-openedBy lz-tree/NodeProp)) + (aget 0))) + +(defn ^string name [^js node] (.-name node)) + +;; specific node types + +(defn error? [^js node] (error-type? node)) +(defn top? [node] (top-type? (type node))) + +(defn program? [node] (identical? "Program" (name node))) +(defn string? [node] (identical? "String" (name node))) +(defn regexp? [node] (identical? "RegExp" (name node))) +(defn line-comment? [node] (identical? "LineComment" (name node))) +(defn discard? [node] (identical? "Discard" (name node))) + +(comment + ;; find a node type id at load time, maybe faster checks? + (some #(and (.is % "Program") (.-id %)) + (.. lezer-clj -parser -nodeSet -types))) + +(defn coll? [node] + (coll-type? (type node))) + +(defn terminal-type? [^js node-type] + (cond (top-type? node-type) false + (.prop node-type prefix-coll-prop) false + (.prop node-type coll-prop) false + (identical? "Meta" (name node-type)) false + (identical? "TaggedLiteral" (name node-type)) false + (identical? "ConstructorCall" (name node-type)) false + :else true)) + +(j/defn balanced? [^:js {:as node :keys [^js firstChild ^js lastChild]}] + (if-let [closing (closed-by firstChild)] + (and (= closing (name lastChild)) + (not= (end firstChild) (end lastChild))) + true)) + +(defn ancestors [^js node] + (when-some [parent (up node)] + (cons parent + (lazy-seq (ancestors parent))))) + +(defn ^js closest [node pred] + (if (pred node) + node + (reduce (fn [_ x] + (if (pred x) (reduced x) nil)) nil (ancestors node)))) + +(defn ^js highest [node pred] + (reduce (fn [found x] + (if (pred x) x (reduced found))) nil (cons node (ancestors node)))) + +(defn children + ([^js parent from dir] + (when-some [^js child (case dir 1 (.childAfter parent from) + -1 (.childBefore parent from))] + (cons child (lazy-seq + (children parent (case dir 1 (end child) + -1 (start child)) dir))))) + ([^js subtree] + (children subtree (start subtree) 1))) + +(defn eq? [^js x ^js y] + (and (== (start x) (start y)) + (== (end x) (end y)) + (== (depth x) (depth y)))) + +(defn empty? + "Node only contains whitespace" + [^js node] + (let [type-name (name node)] + (cond (coll? node) + (eq? (-> node down right) (-> node down-last)) + + (= "String" type-name) + (== (-> node down end) (-> node down-last start)) + :else false))) + +(defn from-to + ([from to] #js{:from from :to to}) + ([node] + (from-to (start node) (end node)))) + +(defn range [node] + (sel/range (start node) (end node))) + +(defn string + ([^js state node] + (string state (start node) (end node))) + ([^js state from to] + (.sliceString (.-doc state) from to \newline))) + +(defn ancestor? [parent child] + (boolean + (and (<= (start parent) (start child)) + (>= (end parent) (end child)) + (< (depth parent) (depth child))))) + +(defn move-toward + "Returns next loc moving toward `to-path`, skipping children" + [node to-node] + (when-not (eq? node to-node) + (case (compare (start to-node) (start node)) + 0 (cond (ancestor? to-node node) (up node) + (ancestor? node to-node) (down node)) + -1 (if (ancestor? node to-node) + (down-last node) + (or (left node) + (up node))) + 1 (if (ancestor? node to-node) + (down node) + (or (right node) + (up node)))))) + +(defn nodes-between [node to-node] + (take-while identity (iterate #(move-toward % to-node) node))) + +(defn- require-balance? [node] + (or (coll? node) + (string? node) + (regexp? node))) + +(defn ^js tree + "Returns a (Tree https://lezer.codemirror.net/docs/ref/#common.Tree) for editor state + or the SyntaxNode at pos. + + If pos is given and we're using Clojure language support embedded in other languages (e.g. markdown) + enters overlaid Clojure nodes (https://lezer.codemirror.net/docs/ref/#common.MountedTree)." + ([^js state] (language/syntaxTree state)) + ([^js state pos] (-> state language/syntaxTree (.resolveInner pos))) + ([^js state pos dir] (-> state language/syntaxTree (.resolveInner pos dir)))) + +(defn ^js cursor + ([^js tree] (.cursor tree)) + ([^js tree pos] (.cursorAt tree pos)) + ([^js tree pos dir] (.cursorAt tree pos dir))) + +(defn ^js terminal-cursor + [^js tree pos dir] + (loop [i pos] + (let [^js c (cursor tree i dir) + type (.-type c)] + (cond (top-type? type) nil + (terminal-type? (.-type c)) c + :else (recur (+ dir i)))))) + +(defn ^js up-here + "Returns topmost node at same starting position" + [node] + (let [from (start node)] + (or (highest node #(= from (start %))) + node))) + +(defn topmost-cursor [state from] + (-> (tree state from 1) .-node up-here .cursor)) + +(defn terminal-nodes [state from to] + (let [^js cursor (topmost-cursor state from)] + (loop [found []] + (let [node-type (type cursor)] + (cond (> (start cursor) to) found + (or (terminal-type? node-type) + (error? node-type)) + (let [found (conj found #js{:type node-type + :from (start cursor) + :to (end cursor)})] + (.lastChild cursor) + (if (.next cursor) + (recur found) + found)) + :else (if (.next cursor) + (recur found) + found)))))) + +(j/defn balanced-range + ([state ^js node] (balanced-range state (start node) (end node))) + ([state from to] + (let [[from to] (sort [from to]) + from-node (tree state from 1) + to-node (tree state to -1) + from (if (require-balance? from-node) + (start from-node) + from) + to (if (require-balance? to-node) + (end to-node) + to) + [left right] (->> (nodes-between from-node to-node) + (map #(cond-> % (edge? %) up)) + (reduce (fn [[left right] ^js node-between] + [(if (ancestor? node-between from-node) (start node-between) left) + (if (ancestor? node-between to-node) (end node-between) right)]) + [from to]))] + (sel/range left right)))) + +(j/defn inner-span + "Span of collection not including edges" + [^:js {:as node :keys [firstChild lastChild]}] + #js{:from (if (left-edge? firstChild) + (end firstChild) + (start node)) + :to (if (right-edge? lastChild) + (start lastChild) + (end node))}) + +(defn within?< "within (exclusive of edges)" + [parent child] + (let [c1 (compare (start parent) (start child)) + c2 (compare (end parent) (end child))] + (and (or (pos? c1) (neg? c2)) + (not (neg? c1)) + (not (pos? c2))))) + +(defn within? "within (inclusive of edges)" + [parent child] + (and (not (neg? (compare (start parent) (start child)))) + (not (pos? (compare (end parent) (end child)))))) + +(defn follow-edges [node] + (if (edge? node) + (up node) + node)) + +(defn prefix [node] + (when-some [parent (up node)] + (or (u/guard parent prefix-container?) + (u/guard (down parent) prefix-edge?)))) + +(defn left-edge-with-prefix [state node] + (str (some->> (prefix node) (string state)) + (name (down node)))) + +(defn with-prefix [node] + (cond-> node + (prefix node) up)) + +(defn node| + "Node ending immediately to the left of pos" + [state pos] + (some-> (tree state pos -1) + (u/guard #(= pos (end %))))) + +(defn |node + "Node starting immediately to the right of pos" + [state pos] + (some-> (tree state pos 1) + (u/guard #(= pos (start %))))) + +(defn nearest-touching [^js state pos dir] + (let [L (some-> (tree state pos -1) + (u/guard (j/fn [^:js {:keys [to]}] (= pos to)))) + R (some-> (tree state pos 1) + (u/guard (j/fn [^:js {:keys [from]}] + (= pos from)))) + mid (tree state pos)] + (case dir 1 (or (u/guard R (every-pred some? #(or (same-edge? %) (not (right-edge? %))))) + L + R + mid) + -1 (or (u/guard L (every-pred some? #(or (same-edge? %) (not (left-edge? %))))) + R + L + mid)))) + +(defn embedded? + "State position is inside fenced code blocks regardless of clojure syntax." + ([state] (embedded? state (.. state -selection -main -head))) + ([state pos] + (identical? (.-FencedCode lezer-markdown/parser.nodeTypes) + (.. state -tree (resolve pos) -type -id)))) + +(defn within-program? + "Returns true when position (or current cursor) is inside some Clojure node. + + This is useful for limiting certain actions when clojure is nested into another language (e.g. Markdown)" + ([state] (within-program? state (.. state -selection -main -head))) + ([state pos] + (let [n (tree state pos)] + (or (program? n) + (some program? (ancestors n)))))) + +(comment + ;; test state overlaid nodes + (let [state + (nextjournal.clojure-mode.test-utils/make-state + #js [nextjournal.livedoc/markdown-language-support] + "```\n(| a)\n```")] + + (js/console.log (-> (tree state 4 1) .-node up-here .cursor)) + (js/console.log (terminal-nodes state 4 9)))) diff --git a/src-squint/nextjournal/clojure_mode/selections.cljs b/src-squint/nextjournal/clojure_mode/selections.cljs new file mode 100644 index 00000000..c331d1ff --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/selections.cljs @@ -0,0 +1,12 @@ +(ns nextjournal.clojure-mode.selections + (:refer-clojure :exclude [range]) + (:require ["@codemirror/state" :refer [EditorSelection]])) + +(defn range + ([from to] (.range EditorSelection from to)) + ([^js range] (.range EditorSelection (.-from range) (.-to range)))) +(defn cursor [from] (.cursor EditorSelection from)) +(defn create [ranges index] (.create EditorSelection ranges index)) +(defn constrain [^js state from] (-> from (max 0) (min (.. state -doc -length)))) +(defn eq? [^js sel1 sel2] + (.eq sel1 sel2)) diff --git a/src-squint/nextjournal/clojure_mode/util.cljs b/src-squint/nextjournal/clojure_mode/util.cljs new file mode 100644 index 00000000..3aeab066 --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/util.cljs @@ -0,0 +1,169 @@ +(ns nextjournal.clojure-mode.util + (:require ["@codemirror/state" :refer [EditorSelection + ChangeSet + ChangeDesc + TransactionSpec + StrictTransactionSpec + StateEffect + Transaction]] + ["./selections" :as sel] + #_[nextjournal.clojure-mode.selections :as sel])) + +(goog-define node-js? false) + +(defn user-event-annotation [event-name] + (.. Transaction -userEvent (of event-name))) + +(defn get-user-event-annotation [tr] + (.annotation ^Transaction tr (.-userEvent Transaction))) + +(defn guard [x f] (when (f x) x)) + +(defn ^js from-to [p1 p2] + (if (> p1 p2) #js{:from p2 :to p1} #js{:from p1 :to p2})) + +(defn dispatch-some + "If passed a transaction, dispatch to view and return true to stop processing commands." + [^js view tr] + (if tr + (do (.dispatch view tr) + true) + false)) + +(defn insertion + "Returns a `change` that inserts string `s` at position `from` and moves cursor to end of insertion." + ([from s] (insertion from from s)) + ([from to ^string s] + {:changes {:insert s + :from from + :to to} + :cursor (+ from (count s))})) + +(defn deletion + ([from] (deletion (max 0 (dec from)) from)) + ([from to] + (let [from (if (= from to) + (max 0 (dec from)) + from)] + {:cursor from + :changes {:from from :to to}}))) + +(defn line-content-at [state from] + (-> state + (j/call-in [:doc :lineAt] from) + (j/call :slice))) + +(defn map-cursor [^js original-range ^js state update-map] + {:pre [(map? update-map)]} + (let [{:keys [cursor/mapped + cursor + from-to + range + changes]} (guard update-map map?) + change-desc (when changes (.changes state (clj->js changes)))] + (cond-> #js{:range (or range + (cond mapped (sel/cursor (.mapPos change-desc mapped)) + cursor (sel/cursor cursor) + from-to (sel/range (from-to 0) (from-to 1))) + original-range)} + change-desc (j/!set :changes change-desc)))) + +(defn update-ranges + "Applies `f` to each range in `state` (see `changeByRange`)" + ([state f] + (update-ranges state nil f)) + ([^js state tr-specs f ] + (->> (fn [range] + (or (when-some [result (f range)] + (map-cursor range state result)) + #js{:range range})) + (.changeByRange state) + (#(j/extend! % tr-specs)) + (.update state)))) + +(defn dispatch-changes [^js state dispatch ^js changes] + (when-not (.-empty changes) + (dispatch (.update state #js{:changes changes})))) + +(defn update-lines + [^js state f & [{:keys [from to spec] + :or {from 0}}]] + (let [iterator (.. state -doc iter)] + (loop [result (.next iterator) + changes #js[] + from-pos from + line-num 1] + (j/let [^:js {:keys [done lineBreak ^string value]} result] + (if (or done + (> from to)) + (.update state (j/extend! #js{:changes (.changes state changes)} spec)) + (recur (.next iterator) + (if-let [change (and (not lineBreak) (f from-pos value line-num))] + (j/push! changes change) + changes) + (+ from-pos (count value)) + (cond-> line-num lineBreak inc))))))) + +(defn update-selected-lines + "`f` will be called for each selected line with args [line, changes-array, range] + and should *mutate* changes-array" + [^js state f] + (let [at-line (atom -1) + doc (.-doc state)] + (->> (j/fn [^:js {:as range :keys [from to anchor head]}] + (j/let [changes #js[]] + (loop [^js line (.lineAt doc from)] + (j/let [^:js {line-number :number line-to :to} line] + (when (> (.-number line) @at-line) + (reset! at-line line-number) + (f line changes range)) + (if-let [next-line (and (> to line-to) + (guard (.lineAt doc (inc line-to)) + #(> (.-number ^js %) line-number)))] + (recur next-line) + (let [^js change-set (.changes state changes)] + #js{:changes changes + :range (.range EditorSelection + (.mapPos change-set anchor 1) + (.mapPos change-set head 1))})))))) + (.changeByRange state)))) + + +(defn iter-changed-lines + "`f` will be called for each changed line with args [line, changes-array] + and should *mutate* changes-array. Selections will be mapped through the resulting changeset." + [^:js {:as tr + :keys [^js changes ^js effects selection] + {:as ^js state :keys [^js doc]} :state} f] + (let [at-line (atom -1) + next-changes #js[] + _ (.iterChanges + changes + (fn [from-a to-a from-b to-b inserted] + (j/let [^:js {:as line line-number :number line-to :to} (.lineAt doc from-b)] + (loop [line line] + (when (> line-number @at-line) + (reset! at-line line-number) + (f line next-changes)) + (when-not (<= to-b line-to) + (let [next-line (.lineAt doc (inc line-to))] + (when (and next-line (> (.-number next-line) (.-number line))) + (recur next-line)))))))) + next-changeset (.changes state next-changes)] + (if (seq next-changes) + (-> (j/select-keys tr [:annotations + :scrollIntoView + :reconfigure]) + (j/assoc! :changes (.compose changes next-changeset)) + (cond-> + selection + (j/assoc! :selection (.. state -selection (map next-changeset))) + effects + (j/assoc! :effects (.mapEffects StateEffect effects next-changeset)))) + tr))) + +;; (j/defn something-selected? [^:js {{:keys [ranges]} :selection}] +;; (not (every? #(.-empty ^js %) ranges))) + +;; (j/defn range-str [state ^:js {:as selection :keys [from to]}] +;; (str (j/call-in state [:doc :slice] from to))) diff --git a/vite.config.js b/vite.config.js index 6d916df1..d5485036 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,3 +1,7 @@ export default { - + optimizeDeps: { + // avoids loading deps multiple time + exclude: ['prosemirror-model', 'y-prosemirror', 'y-websocket'], + // root: "demo" + } }; From 3d85bf5f98b20c8613a32bfa935ab4ef511787c8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 16:01:15 +0200 Subject: [PATCH 04/80] wip --- bb.edn | 10 +- package.json | 2 +- .../nextjournal/clojure_mode/util.mjs | 176 ++++++++++-------- src-squint/nextjournal/clojure_mode/util.cljs | 38 ++-- 4 files changed, 121 insertions(+), 105 deletions(-) diff --git a/bb.edn b/bb.edn index d3b4d6f2..7d507516 100644 --- a/bb.edn +++ b/bb.edn @@ -25,13 +25,13 @@ (println (apply str (interpose "\n" (cons "removing:" paths)))) (doseq [path paths] (fs/delete path))) - compile {:doc "Use squintjs to compile all cljs files recursively" + #_#_compile {:doc "Use squintjs to compile all cljs files recursively" :depends [yarn-install] :task (shell {:std :inherit :err :inherit} (apply str (cons "yarn squint compile " (interpose " " (get-paths :cljs)))))} - build {:doc "Compiles cljs files with squint and builds from mjs sources with vite" + #_#_build {:doc "Compiles cljs files with squint and builds from mjs sources with vite" :depends [compile] :task (shell {:std :inherit :err :inherit} "yarn build")} @@ -42,6 +42,8 @@ :depends [yarn-install] :task (shell "yarn dev")} + -dev {:depends [vite-dev watch-cljs]} + dev {:doc "Compiles all cljs to mjs, runs vite in dev and starts a cherry watcher to recompile changed cljs. When run as `bb dev collab` also starts a Y.js collaboration server." - :depends [compile] - :task (run '-dev)}}} + ;; :depends [compile] + :task (run '-dev {:parallel true})}}} diff --git a/package.json b/package.json index e38b2408..3cf8f4ba 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "build": "shadow-cljs -A:demo release demo livedoc", "test": "shadow-cljs -A:dev release ci-test && node out/node-tests.js", "watch2": "git ls-files | entr yarn test", - "dev": "vite --open -l info --config vite.config.js demo" + "dev": "vite --open -l info --config vite.config.js public/squint" }, "devDependencies": { "shadow-cljs": "2.19.5", diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs index 37041fe2..02a4daf8 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs @@ -1,7 +1,8 @@ import * as squint_core from 'squint-cljs/core.js'; -import { EditorSelection, ChangeSet, ChangeDesc, TransactionSpec, StrictTransactionSpec, StateEffect, Transaction } from '@codemirror/state'; +import { EditorSelection, StateEffect, Transaction } from '@codemirror/state'; import * as sel from './selections'; -goog_define(node_js_QMARK_, false); +var node_js_QMARK_ = squint_core.some_QMARK_(globalThis.process) +; var user_event_annotation = (function (event_name) { return Transaction["userEvent"].of(event_name); }) @@ -74,7 +75,7 @@ return f7; })() ; var line_content_at = (function (state, from) { -return j.call(j.call_in(state, ["doc", "lineAt"], from), "slice"); +return state["doc"].lineAt(from).slice(); }) ; var map_cursor = (function (original_range, state, update_map) { @@ -88,7 +89,8 @@ let changes20 = squint_core.get(map__1415, "changes"); let change_desc21 = (changes20) ? (state.changes(clj__GT_js(changes20))) : (null); let G__2223 = ({ "range": (range19 || (mapped16) ? (sel.cursor(change_desc21.mapPos(mapped16))) : ((cursor17) ? (sel.cursor(cursor17)) : ((from_to18) ? (sel.range(from_to18(0), from_to18(1))) : (null))) || original_range) }); if (change_desc21) { -return j._BANG_set(G__2223, "changes", change_desc21);} else { +return G__2223 = "changes"; +;} else { return G__2223;} }) ; @@ -109,7 +111,7 @@ return update_ranges(state, null, f); }); f24["cljs$core$IFn$_invoke$arity$3"] = (function (state, tr_specs, f) { return state.update((function (_PERCENT_1) { -return j.extend_BANG_(_PERCENT_1, tr_specs); +return Object.assign(_PERCENT_1, tr_specs); })(state.changeByRange((function (range) { return ((function () { let temp__25231__auto__30 = f(range); @@ -159,108 +161,126 @@ let changes55 = []; let from_pos56 = from50; let line_num57 = 1; while(true){ -return j.let$([({ "keys": [done, lineBreak, value] }), result54], ((done || (from50 > to51))) ? (state.update(j.extend_BANG_(({ "changes": state.changes(changes55) }), spec52))) : (let G__58 = iterator53.next(); -let G__59 = (function () { - let temp__24970__auto__60 = (!lineBreak && f(from_pos56, value, line_num57)); -if (temp__24970__auto__60) { -let change61 = temp__24970__auto__60; -return j.push_BANG_(changes55, change61);} else { +let map__5859 = result54; +let done60 = squint_core.get(map__5859, "done"); +let lineBreak61 = squint_core.get(map__5859, "lineBreak"); +let value62 = squint_core.get(map__5859, "value"); +if ((done60 || (from50 > to51))) { +return state.update(Object.assign(({ "changes": state.changes(changes55) }), spec52));} else { +let G__63 = iterator53.next(); +let G__64 = (function () { + let temp__24970__auto__65 = (!lineBreak61 && f(from_pos56, value62, line_num57)); +if (temp__24970__auto__65) { +let change66 = temp__24970__auto__65; +let G__6768 = changes55; +G__6768.push(change66); +return G__6768;} else { return changes55;} })(); -let G__62 = (from_pos56 + squint_core.count(value)); -let G__63 = (function () { - let G__6465 = line_num57; -if (lineBreak) { -return (G__6465 + 1);} else { -return G__6465;} +let G__69 = (from_pos56 + squint_core.count(value62)); +let G__70 = (function () { + let G__7172 = line_num57; +if (lineBreak61) { +return (G__7172 + 1);} else { +return G__7172;} })(); -result54 = G__58; -changes55 = G__59; -from_pos56 = G__62; -line_num57 = G__63; +result54 = G__63; +changes55 = G__64; +from_pos56 = G__69; +line_num57 = G__70; continue; -));;break; +};break; } }); f32["cljs$lang$maxFixedArity"] = 2; f32["cljs$lang$applyTo"] = (function (seq35) { -let G__3666 = squint_core.first(seq35); -let seq3567 = next(seq35); -let G__3768 = squint_core.first(seq3567); -let seq3569 = next(seq3567); -let self__24359__auto__70 = this; -return self__24359__auto__70.cljs$core$IFn$_invoke$arity$variadic(G__3666, G__3768, seq3569); +let G__3673 = squint_core.first(seq35); +let seq3574 = next(seq35); +let G__3775 = squint_core.first(seq3574); +let seq3576 = next(seq3574); +let self__24359__auto__77 = this; +return self__24359__auto__77.cljs$core$IFn$_invoke$arity$variadic(G__3673, G__3775, seq3576); }); return f32; })() ; var update_selected_lines = (function (state, f) { -let at_line71 = squint_core.atom(-1); -let doc72 = state["doc"]; -return state.changeByRange(j.fn([({ "as": squint_core.range, "keys": [from, to, anchor, head] })], j.let$([changes, []], (function () { - let line73 = doc72.lineAt(from); +let at_line78 = squint_core.atom(-1); +let doc79 = state["doc"]; +return state.changeByRange((function (p__80) { +let map__8182 = p__80; +let range83 = map__8182; +let from84 = squint_core.get(map__8182, "from"); +let to85 = squint_core.get(map__8182, "to"); +let anchor86 = squint_core.get(map__8182, "anchor"); +let head87 = squint_core.get(map__8182, "head"); +let changes88 = []; +let line89 = doc79.lineAt(from84); while(true){ -return j.let$([({ "line-number": "number", "line-to": "to" }), line73], ((line73["number"] > squint_core.deref(at_line71))) ? ((function () { - squint_core.reset_BANG_(at_line71, line_number); -return f(line73, changes, squint_core.range); -})()) : (null), (function () { - let temp__24970__auto__74 = ((to > line_to) && guard(doc72.lineAt((line_to + 1)), (function (_PERCENT_1) { -return (_PERCENT_1["number"] > line_number); +let map__9091 = line89; +let line_number92 = squint_core.get(map__9091, "number"); +let line_to93 = squint_core.get(map__9091, "to"); +if ((line89["number"] > squint_core.deref(at_line78))) { +squint_core.reset_BANG_(at_line78, line_number92); +f(line89, changes88, range83)}; +let temp__24970__auto__94 = ((to85 > line_to93) && guard(doc79.lineAt((line_to93 + 1)), (function (_PERCENT_1) { +return (_PERCENT_1["number"] > line_number92); }))); -if (temp__24970__auto__74) { -let next_line75 = temp__24970__auto__74; -let G__76 = next_line75; -line73 = G__76; +if (temp__24970__auto__94) { +let next_line95 = temp__24970__auto__94; +let G__96 = next_line95; +line89 = G__96; continue; } else { -let change_set77 = state.changes(changes); -return ({ "changes": changes, "range": EditorSelection.range(change_set77.mapPos(anchor, 1), change_set77.mapPos(head, 1)) });} -})());;break; +let change_set97 = state.changes(changes88); +return ({ "changes": changes88, "range": EditorSelection.range(change_set97.mapPos(anchor86, 1), change_set97.mapPos(head87, 1)) });};break; } -})()))); +})); }) ; -var iter_changed_lines = (function (p__78, f) { -let map__7981 = p__78; -let tr82 = map__7981; -let map__8083 = squint_core.get(map__7981, "state"); -let state84 = map__8083; -let doc85 = squint_core.get(map__8083, "doc"); -let changes86 = squint_core.get(map__7981, "changes"); -let effects87 = squint_core.get(map__7981, "effects"); -let selection88 = squint_core.get(map__7981, "selection"); -let at_line89 = squint_core.atom(-1); -let next_changes90 = []; -let _91 = changes86.iterChanges((function (from_a, to_a, from_b, to_b, inserted) { -return j.let$([({ "as": line, "line-number": "number", "line-to": "to" }), doc85.lineAt(from_b)], (function () { - let line92 = line; +var iter_changed_lines = (function (p__98, f) { +let map__99101 = p__98; +let tr102 = map__99101; +let map__100103 = squint_core.get(map__99101, "state"); +let state104 = map__100103; +let doc105 = squint_core.get(map__100103, "doc"); +let changes106 = squint_core.get(map__99101, "changes"); +let effects107 = squint_core.get(map__99101, "effects"); +let selection108 = squint_core.get(map__99101, "selection"); +let at_line109 = squint_core.atom(-1); +let next_changes110 = []; +let _111 = changes106.iterChanges((function (_from_a, _to_a, from_b, to_b, _inserted) { +let map__112113 = doc105.lineAt(from_b); +let line114 = map__112113; +let line_number115 = squint_core.get(map__112113, "number"); +let line_to116 = squint_core.get(map__112113, "to"); +let line117 = line114; while(true){ -if ((line_number > squint_core.deref(at_line89))) { -squint_core.reset_BANG_(at_line89, line_number); -f(line92, next_changes90)}; -if ((to_b <= line_to)) { +if ((line_number115 > squint_core.deref(at_line109))) { +squint_core.reset_BANG_(at_line109, line_number115); +f(line117, next_changes110)}; +if ((to_b <= line_to116)) { return null;} else { -let next_line93 = doc85.lineAt((line_to + 1)); -if ((next_line93 && (next_line93["number"] > line92["number"]))) { -let G__94 = next_line93; -line92 = G__94; +let next_line118 = doc105.lineAt((line_to116 + 1)); +if ((next_line118 && (next_line118["number"] > line117["number"]))) { +let G__119 = next_line118; +line117 = G__119; continue; }};break; } -})()); })); -let next_changeset95 = state84.changes(next_changes90); -if (squint_core.seq(next_changes90)) { -let G__9697 = j.assoc_BANG_(j.select_keys(tr82, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes86.compose(next_changeset95)); -let G__9698 = (selection88) ? (j.assoc_BANG_(G__9697, "selection", state84["selection"].map(next_changeset95))) : (G__9697); -if (effects87) { -return j.assoc_BANG_(G__9698, "effects", StateEffect.mapEffects(effects87, next_changeset95));} else { -return G__9698;}} else { -return tr82;} +let next_changeset120 = state104.changes(next_changes110); +if (squint_core.seq(next_changes110)) { +let G__121122 = squint_core.assoc_BANG_(squint_core.select_keys(tr102, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes106.compose(next_changeset120)); +let G__121123 = (selection108) ? (squint_core.assoc_BANG_(G__121122, "selection", state104["selection"].map(next_changeset120))) : (G__121122); +if (effects107) { +return squint_core.assoc_BANG_(G__121123, "effects", StateEffect.mapEffects(effects107, next_changeset120));} else { +return G__121123;}} else { +return tr102;} }) ; -export { dispatch_some, guard, dispatch_changes, insertion, deletion, line_content_at, update_selected_lines, map_cursor, get_user_event_annotation, user_event_annotation, update_ranges, from_to, iter_changed_lines, update_lines } +export { dispatch_some, guard, node_js_QMARK_, dispatch_changes, insertion, deletion, line_content_at, update_selected_lines, map_cursor, get_user_event_annotation, user_event_annotation, update_ranges, from_to, iter_changed_lines, update_lines } diff --git a/src-squint/nextjournal/clojure_mode/util.cljs b/src-squint/nextjournal/clojure_mode/util.cljs index 3aeab066..05ca0823 100644 --- a/src-squint/nextjournal/clojure_mode/util.cljs +++ b/src-squint/nextjournal/clojure_mode/util.cljs @@ -1,15 +1,11 @@ (ns nextjournal.clojure-mode.util (:require ["@codemirror/state" :refer [EditorSelection - ChangeSet - ChangeDesc - TransactionSpec - StrictTransactionSpec StateEffect Transaction]] ["./selections" :as sel] #_[nextjournal.clojure-mode.selections :as sel])) -(goog-define node-js? false) +(def node-js? (some? js/globalThis.process)) (defn user-event-annotation [event-name] (.. Transaction -userEvent (of event-name))) @@ -49,9 +45,7 @@ :changes {:from from :to to}}))) (defn line-content-at [state from] - (-> state - (j/call-in [:doc :lineAt] from) - (j/call :slice))) + (.. state -doc (lineAt from) slice)) (defn map-cursor [^js original-range ^js state update-map] {:pre [(map? update-map)]} @@ -66,7 +60,7 @@ cursor (sel/cursor cursor) from-to (sel/range (from-to 0) (from-to 1))) original-range)} - change-desc (j/!set :changes change-desc)))) + change-desc (set! :changes change-desc)))) (defn update-ranges "Applies `f` to each range in `state` (see `changeByRange`)" @@ -78,7 +72,7 @@ (map-cursor range state result)) #js{:range range})) (.changeByRange state) - (#(j/extend! % tr-specs)) + (#(js/Object.assign % tr-specs)) (.update state)))) (defn dispatch-changes [^js state dispatch ^js changes] @@ -93,13 +87,13 @@ changes #js[] from-pos from line-num 1] - (j/let [^:js {:keys [done lineBreak ^string value]} result] + (let [^:js {:keys [done lineBreak ^string value]} result] (if (or done (> from to)) - (.update state (j/extend! #js{:changes (.changes state changes)} spec)) + (.update state (js/Object.assign #js{:changes (.changes state changes)} spec)) (recur (.next iterator) (if-let [change (and (not lineBreak) (f from-pos value line-num))] - (j/push! changes change) + (doto changes (.push change)) changes) (+ from-pos (count value)) (cond-> line-num lineBreak inc))))))) @@ -110,10 +104,10 @@ [^js state f] (let [at-line (atom -1) doc (.-doc state)] - (->> (j/fn [^:js {:as range :keys [from to anchor head]}] - (j/let [changes #js[]] + (->> (fn [^:js {:as range :keys [from to anchor head]}] + (let [changes #js[]] (loop [^js line (.lineAt doc from)] - (j/let [^:js {line-number :number line-to :to} line] + (let [^:js {line-number :number line-to :to} line] (when (> (.-number line) @at-line) (reset! at-line line-number) (f line changes range)) @@ -139,8 +133,8 @@ next-changes #js[] _ (.iterChanges changes - (fn [from-a to-a from-b to-b inserted] - (j/let [^:js {:as line line-number :number line-to :to} (.lineAt doc from-b)] + (fn [_from-a _to-a from-b to-b _inserted] + (let [^:js {:as line line-number :number line-to :to} (.lineAt doc from-b)] (loop [line line] (when (> line-number @at-line) (reset! at-line line-number) @@ -151,15 +145,15 @@ (recur next-line)))))))) next-changeset (.changes state next-changes)] (if (seq next-changes) - (-> (j/select-keys tr [:annotations + (-> (select-keys tr [:annotations :scrollIntoView :reconfigure]) - (j/assoc! :changes (.compose changes next-changeset)) + (assoc! :changes (.compose changes next-changeset)) (cond-> selection - (j/assoc! :selection (.. state -selection (map next-changeset))) + (assoc! :selection (.. state -selection (map next-changeset))) effects - (j/assoc! :effects (.mapEffects StateEffect effects next-changeset)))) + (assoc! :effects (.mapEffects StateEffect effects next-changeset)))) tr))) ;; (j/defn something-selected? [^:js {{:keys [ranges]} :selection}] From 21a58482b28a94e81cd610be4f6c70a123f63173 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 16:02:21 +0200 Subject: [PATCH 05/80] util --- public/squint/js/main.mjs | 3 ++- public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs | 1 + src-squint/nextjournal/clojure_mode/util.cljs | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 59450f57..7df4297f 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -1,4 +1,5 @@ -import './src-squint/nextjournal/clojure_mode/node.mjs'; +import './src-squint/nextjournal/clojure_mode/util.mjs'; +// import './src-squint/nextjournal/clojure_mode/node.mjs'; // import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs index 02a4daf8..be7cf7ed 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs @@ -282,5 +282,6 @@ return G__121123;}} else { return tr102;} }) ; +squint_core.prn("util-loaded"); export { dispatch_some, guard, node_js_QMARK_, dispatch_changes, insertion, deletion, line_content_at, update_selected_lines, map_cursor, get_user_event_annotation, user_event_annotation, update_ranges, from_to, iter_changed_lines, update_lines } diff --git a/src-squint/nextjournal/clojure_mode/util.cljs b/src-squint/nextjournal/clojure_mode/util.cljs index 05ca0823..471429a2 100644 --- a/src-squint/nextjournal/clojure_mode/util.cljs +++ b/src-squint/nextjournal/clojure_mode/util.cljs @@ -161,3 +161,5 @@ ;; (j/defn range-str [state ^:js {:as selection :keys [from to]}] ;; (str (j/call-in state [:doc :slice] from to))) + +(prn :util-loaded) From 6d4436755fb2bbd783aac57854cb1948bf41909b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 16:10:50 +0200 Subject: [PATCH 06/80] close brackets --- public/squint/js/main.mjs | 5 +- .../extensions/close_brackets.mjs | 190 +++++--- .../nextjournal/clojure_mode/node.mjs | 404 ++++++++++-------- .../extensions/close_brackets.cljs | 58 ++- src-squint/nextjournal/clojure_mode/node.cljs | 12 +- 5 files changed, 398 insertions(+), 271 deletions(-) diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 7df4297f..caa83e54 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -1,5 +1,4 @@ import './src-squint/nextjournal/clojure_mode/util.mjs'; - -// import './src-squint/nextjournal/clojure_mode/node.mjs'; -// import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; +import './src-squint/nextjournal/clojure_mode/node.mjs'; +import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs index 280d6821..8525e56c 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs @@ -1,13 +1,12 @@ import * as squint_core from 'squint-cljs/core.js'; -import { keyName } from 'w3c-keyname'; import * as view from '@codemirror/view'; -import { EditorState, EditorSelection, Transaction, CharCategory, Extension, Prec } from '@codemirror/state'; -import * as n from 'nextjournal.clojure-mode.node'; -import * as u from 'nextjournal.clojure-mode.util'; -import { from_to } from 'nextjournal.clojure-mode.util'; +import { EditorState, Prec } from '@codemirror/state'; +import * as n from '../node.mjs'; +import * as u from '../util.mjs'; +import { from_to } from '../util.mjs'; import * as str from 'squint-cljs/string.js'; var in_string_QMARK_ = (function (state, pos) { -return new Set(["StringContent", "String"])(nextjournal.clojure_mode.node.name(nextjournal.clojure_mode.node.tree(state, pos))); +return new Set(["StringContent", "String"])(n.name(n.tree(state, pos))); }) ; var escaped_QMARK_ = (function (state, pos) { @@ -16,87 +15,176 @@ return ("\\" === state["doc"].slice(max(0, (pos - 1)), pos).toString()); ; var backspace_backoff = (function (state, from, to) { if (((function () { - let G__12 = nextjournal.clojure_mode.node.node_BAR_(state, (from - 1)); + let G__12 = n.node_BAR_(state, (from - 1)); if (squint_core.nil_QMARK_(G__12)) { return null;} else { -return nextjournal.clojure_mode.util.guard(G__12, nextjournal.clojure_mode.node.line_comment_QMARK_);} -})() && !str.blank_QMARK_(nextjournal.clojure_mode.util.line_content_at(state, from)))) { +return u.guard(G__12, n.line_comment_QMARK_);} +})() && !str.blank_QMARK_(u.line_content_at(state, from)))) { return ({ "cursor": (from - 1) });} else { -return nextjournal.clojure_mode.util.deletion(from, to);} +return u.deletion(from, to);} +}) +; +var handle_backspace = (function (p__3) { +let map__45 = p__3; +let state6 = map__45; +let doc7 = squint_core.get(map__45, "doc"); +if (((1 === state6["selection"]["ranges"]["length"]) && (function () { + let range8 = squint_core.get_in(state6, ["selection", "ranges", 0]); +return (range8["empty"] && (0 === range8["from"])); +})())) { +return null;} else { +return u.update_ranges(state6, ({ "annotations": u.user_event_annotation("delete") }), (function (p__9) { +let map__1011 = p__9; +let range12 = map__1011; +let head13 = squint_core.get(map__1011, "head"); +let empty14 = squint_core.get(map__1011, "empty"); +let anchor15 = squint_core.get(map__1011, "anchor"); +let map__1617 = from_to(head13, anchor15); +let range18 = map__1617; +let from19 = squint_core.get(map__1617, "from"); +let to20 = squint_core.get(map__1617, "to"); +let node_BAR_21 = n.tree(state6).resolveInner(from19, -1); +let parent22 = node_BAR_21["parent"]; +if ((!empty14 || ("StringContent" === n.name(n.tree(state6, from19, -1))) || (parent22 && !n.balanced_QMARK_(parent22) && n.left_edge_QMARK_(node_BAR_21)))) { +return u.deletion(from19, to20);} else { +if ((n.right_edge_QMARK_(node_BAR_21) && (from19 == n.end(parent22)))) { +return ({ "cursor": (from19 - 1) });} else { +if (((n.start_edge_QMARK_(node_BAR_21) || n.same_edge_QMARK_(node_BAR_21)) && (n.start(node_BAR_21) == n.start(parent22)))) { +if (n.empty_QMARK_(n.up(node_BAR_21))) { +return ({ "cursor": n.start(parent22), "changes": [from_to(n.start(parent22), n.end(parent22))] });} else { +return ({ "cursor": from19 });}} else { +if ("else") { +return backspace_backoff(state6, from19, to20);} else { +return null;}}}} +}));} }) ; -j.defn(handle_backspace, "- skips over closing brackets\n - when deleting an opening bracket of an empty list, removes both brackets", [({ "as": state, "keys": [doc] })], (((1 === state["selection"]["ranges"]["length"]) && (function () { - let range3 = j.get_in(state, ["selection", "ranges", 0]); -return (range3["empty"] && (0 === range3["from"])); -})())) ? (null) : (nextjournal.clojure_mode.util.update_ranges(state, ({ "annotations": nextjournal.clojure_mode.util.user_event_annotation("delete") }), j.fn([({ "as": squint_core.range, "keys": [head, squint_core.empty, anchor] })], j.let$([({ "as": squint_core.range, "from": "from", "to": "to" }), from_to(head, anchor), node_BAR_, nextjournal.clojure_mode.node.tree(state).resolveInner(from, -1), parent, node_BAR_["parent"]], ((!squint_core.empty || ("StringContent" === nextjournal.clojure_mode.node.name(nextjournal.clojure_mode.node.tree(state, from, -1))) || (parent && !nextjournal.clojure_mode.node.balanced_QMARK_(parent) && nextjournal.clojure_mode.node.left_edge_QMARK_(node_BAR_)))) ? (nextjournal.clojure_mode.util.deletion(from, to)) : (((nextjournal.clojure_mode.node.right_edge_QMARK_(node_BAR_) && (from == nextjournal.clojure_mode.node.end(parent)))) ? (({ "cursor": (from - 1) })) : ((((nextjournal.clojure_mode.node.start_edge_QMARK_(node_BAR_) || nextjournal.clojure_mode.node.same_edge_QMARK_(node_BAR_)) && (nextjournal.clojure_mode.node.start(node_BAR_) == nextjournal.clojure_mode.node.start(parent)))) ? ((nextjournal.clojure_mode.node.empty_QMARK_(nextjournal.clojure_mode.node.up(node_BAR_))) ? (({ "cursor": nextjournal.clojure_mode.node.start(parent), "changes": [from_to(nextjournal.clojure_mode.node.start(parent), nextjournal.clojure_mode.node.end(parent))] })) : (({ "cursor": from }))) : (("else") ? (backspace_backoff(state, from, to)) : (null))))))))); var coll_pairs = ({ "(": ")", "[": "]", "{": "}", "\"": "\"" }) ; var handle_open = (function (state, open) { -let close4 = coll_pairs(open); -return nextjournal.clojure_mode.util.update_ranges(state, ({ "annotations": nextjournal.clojure_mode.util.user_event_annotation("input") }), j.fn([({ "keys": [from, to, head, anchor, squint_core.empty] })], (in_string_QMARK_(state, from)) ? (((open === "\"")) ? (nextjournal.clojure_mode.util.insertion(head, "\\\"")) : (nextjournal.clojure_mode.util.insertion(from, to, open))) : ((escaped_QMARK_(state, from)) ? (nextjournal.clojure_mode.util.insertion(from, to, open)) : (("else") ? ((squint_core.empty) ? (({ "changes": ({ "insert": squint_core.str(open, close4), "from": head }), "cursor": (head + squint_core.count(open)) })) : (({ "changes": [({ "insert": open, "from": from }), ({ "insert": close4, "from": to })], "from-to": [(anchor + squint_core.count(open)), (head + squint_core.count(open))] }))) : (null))))); +let close23 = coll_pairs(open); +return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__24) { +let map__2526 = p__24; +let from27 = squint_core.get(map__2526, "from"); +let to28 = squint_core.get(map__2526, "to"); +let head29 = squint_core.get(map__2526, "head"); +let anchor30 = squint_core.get(map__2526, "anchor"); +let empty31 = squint_core.get(map__2526, "empty"); +if (in_string_QMARK_(state, from27)) { +if ((open === "\"")) { +return u.insertion(head29, "\\\"");} else { +return u.insertion(from27, to28, open);}} else { +if (escaped_QMARK_(state, from27)) { +return u.insertion(from27, to28, open);} else { +if ("else") { +if (empty31) { +return ({ "changes": ({ "insert": squint_core.str(open, close23), "from": head29 }), "cursor": (head29 + squint_core.count(open)) });} else { +return ({ "changes": [({ "insert": open, "from": from27 }), ({ "insert": close23, "from": to28 })], "from-to": [(anchor30 + squint_core.count(open)), (head29 + squint_core.count(open))] });}} else { +return null;}}} +})); }) ; var handle_close = (function (state, key_name) { -return nextjournal.clojure_mode.util.update_ranges(state, ({ "annotations": nextjournal.clojure_mode.util.user_event_annotation("input") }), j.fn([({ "as": squint_core.range, "keys": [squint_core.empty, head, from, to] })], ((in_string_QMARK_(state, from) || escaped_QMARK_(state, from))) ? (nextjournal.clojure_mode.util.insertion(from, to, key_name)) : ((squint_core.empty) ? (((function () { - let unbalanced5 = (function () { - let G__67 = nextjournal.clojure_mode.node.tree(state, head, -1); -let G__68 = (squint_core.nil_QMARK_(G__67)) ? (null) : (nextjournal.clojure_mode.node.ancestors(G__67)); -let G__69 = (squint_core.nil_QMARK_(G__68)) ? (null) : (squint_core.filter(every_pred(nextjournal.clojure_mode.node.coll_QMARK_, squint_core.complement(nextjournal.clojure_mode.node.balanced_QMARK_)), G__68)); -if (squint_core.nil_QMARK_(G__69)) { +return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__32) { +let map__3334 = p__32; +let range35 = map__3334; +let empty36 = squint_core.get(map__3334, "empty"); +let head37 = squint_core.get(map__3334, "head"); +let from38 = squint_core.get(map__3334, "from"); +let to39 = squint_core.get(map__3334, "to"); +if ((in_string_QMARK_(state, from38) || escaped_QMARK_(state, from38))) { +return u.insertion(from38, to39, key_name);} else { +if (empty36) { +return ((function () { + let unbalanced40 = (function () { + let G__4142 = n.tree(state, head37, -1); +let G__4143 = (squint_core.nil_QMARK_(G__4142)) ? (null) : (n.ancestors(G__4142)); +let G__4144 = (squint_core.nil_QMARK_(G__4143)) ? (null) : (squint_core.filter(every_pred(n.coll_QMARK_, squint_core.complement(n.balanced_QMARK_)), G__4143)); +if (squint_core.nil_QMARK_(G__4144)) { return null;} else { -return squint_core.first(G__69);} +return squint_core.first(G__4144);} })(); -let closing10 = (function () { - let G__1112 = unbalanced5; -let G__1113 = (squint_core.nil_QMARK_(G__1112)) ? (null) : (nextjournal.clojure_mode.node.down(G__1112)); -if (squint_core.nil_QMARK_(G__1113)) { +let closing45 = (function () { + let G__4647 = unbalanced40; +let G__4648 = (squint_core.nil_QMARK_(G__4647)) ? (null) : (n.down(G__4647)); +if (squint_core.nil_QMARK_(G__4648)) { return null;} else { -return nextjournal.clojure_mode.node.closed_by(G__1113);} +return n.closed_by(G__4648);} })(); -let pos14 = (function () { - let G__1516 = unbalanced5; -if (squint_core.nil_QMARK_(G__1516)) { +let pos49 = (function () { + let G__5051 = unbalanced40; +if (squint_core.nil_QMARK_(G__5051)) { return null;} else { -return nextjournal.clojure_mode.node.end(G__1516);} +return n.end(G__5051);} })(); -if ((closing10 && (closing10 === key_name))) { -return ({ "changes": ({ "from": pos14, "insert": closing10 }), "cursor": (pos14 + 1) });} +if ((closing45 && (closing45 === key_name))) { +return ({ "changes": ({ "from": pos49, "insert": closing45 }), "cursor": (pos49 + 1) });} })() || (function () { - let temp__25187__auto__17 = (function () { - let temp__25187__auto__18 = nextjournal.clojure_mode.node.terminal_cursor(nextjournal.clojure_mode.node.tree(state), head, 1); -if (temp__25187__auto__18) { -let cursor19 = temp__25187__auto__18; + let temp__25187__auto__52 = (function () { + let temp__25187__auto__53 = n.terminal_cursor(n.tree(state), head37, 1); +if (temp__25187__auto__53) { +let cursor54 = temp__25187__auto__53; while(true){ -if (nextjournal.clojure_mode.node.right_edge_type_QMARK_(cursor19["type"])) { -return nextjournal.clojure_mode.node.end(cursor19);} else { -if (cursor19.next()) { +if (n.right_edge_type_QMARK_(cursor54["type"])) { +return n.end(cursor54);} else { +if (cursor54.next()) { continue; }};break; } } })(); -if (temp__25187__auto__17) { -let close_node_end20 = temp__25187__auto__17; -return ({ "cursor": close_node_end20 });} -})() || ({ "cursor": head }))) : (null)))); +if (temp__25187__auto__52) { +let close_node_end55 = temp__25187__auto__52; +return ({ "cursor": close_node_end55 });} +})() || ({ "cursor": head37 }));}} +})); +}) +; +var handle_backspace_cmd = (function (p__56) { +let map__5758 = p__56; +let view59 = map__5758; +let state60 = squint_core.get(map__5758, "state"); +return u.dispatch_some(view59, handle_backspace(state60)); }) ; -j.defn(handle_backspace_cmd, [({ "as": view, "keys": [state] })], nextjournal.clojure_mode.util.dispatch_some(view, handle_backspace(state))); var handle_open_cmd = (function (key_name) { -return j.fn([({ "as": view, "keys": [state] })], nextjournal.clojure_mode.util.dispatch_some(view, handle_open(state, key_name))); +return function (p__61) { +let map__6263 = p__61; +let view64 = map__6263; +let state65 = squint_core.get(map__6263, "state"); +return u.dispatch_some(view64, handle_open(state65, key_name)); +}; }) ; var handle_close_cmd = (function (key_name) { -return j.fn([({ "as": view, "keys": [state] })], nextjournal.clojure_mode.util.dispatch_some(view, handle_close(state, key_name))); +return function (p__66) { +let map__6768 = p__66; +let view69 = map__6768; +let state70 = squint_core.get(map__6768, "state"); +return u.dispatch_some(view69, handle_close(state70, key_name)); +}; }) ; var guard_scope = (function (cmd) { -return j.fn([({ "as": view, "keys": [state] })], ((nextjournal.clojure_mode.node.embedded_QMARK_(state) || nextjournal.clojure_mode.node.within_program_QMARK_(state))) ? (cmd(view)) : (false)); +return function (p__71) { +let map__7273 = p__71; +let view74 = map__7273; +let state75 = squint_core.get(map__7273, "state"); +if ((n.embedded_QMARK_(state75) || n.within_program_QMARK_(state75))) { +return cmd(view74);} else { +return false;} +}; }) ; var extension = (function () { -return Prec.high(view.keymap.of(j.lit([({ "key": "Backspace", "run": guard_scope(j.fn([({ "as": view, "keys": [state] })], nextjournal.clojure_mode.util.dispatch_some(view, handle_backspace(state)))) }), ({ "key": "(", "run": guard_scope(handle_open_cmd("(")) }), ({ "key": "[", "run": guard_scope(handle_open_cmd("[")) }), ({ "key": "{", "run": guard_scope(handle_open_cmd("{")) }), ({ "key": "\"", "run": guard_scope(handle_open_cmd("\"")) }), ({ "key": ")", "run": guard_scope(handle_close_cmd(")")) }), ({ "key": "]", "run": guard_scope(handle_close_cmd("]")) }), ({ "key": "}", "run": guard_scope(handle_close_cmd("}")) })]))); +return Prec.high(view.keymap.of([({ "key": "Backspace", "run": guard_scope((function (p__76) { +let map__7778 = p__76; +let view79 = map__7778; +let state80 = squint_core.get(map__7778, "state"); +return u.dispatch_some(view79, handle_backspace(state80)); +})) }), ({ "key": "(", "run": guard_scope(handle_open_cmd("(")) }), ({ "key": "[", "run": guard_scope(handle_open_cmd("[")) }), ({ "key": "{", "run": guard_scope(handle_open_cmd("{")) }), ({ "key": "\"", "run": guard_scope(handle_open_cmd("\"")) }), ({ "key": ")", "run": guard_scope(handle_close_cmd(")")) }), ({ "key": "]", "run": guard_scope(handle_close_cmd("]")) }), ({ "key": "}", "run": guard_scope(handle_close_cmd("}")) })])); }) ; +squint_core.prn("close-brackets-loaded"); -export { handle_close_cmd, backspace_backoff, escaped_QMARK_, guard_scope, handle_close, handle_open_cmd, extension, in_string_QMARK_, handle_open, coll_pairs } +export { handle_backspace_cmd, handle_backspace, handle_close_cmd, backspace_backoff, escaped_QMARK_, guard_scope, handle_close, handle_open_cmd, extension, in_string_QMARK_, handle_open, coll_pairs } diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs index f900267e..907fba68 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs @@ -252,20 +252,25 @@ return true;} else { return null;}}}}}}} }) ; -j.defn(balanced_QMARK_, [({ "as": node, "keys": [firstChild, lastChild] })], (function () { - let temp__24970__auto__15 = closed_by(firstChild); -if (temp__24970__auto__15) { -let closing16 = temp__24970__auto__15; -return ((closing16 === name(lastChild)) && (end(firstChild) !== end(lastChild)));} else { +var balanced_QMARK_ = (function (p__15) { +let map__1617 = p__15; +let node18 = map__1617; +let firstChild19 = squint_core.get(map__1617, "firstChild"); +let lastChild20 = squint_core.get(map__1617, "lastChild"); +let temp__24970__auto__21 = closed_by(firstChild19); +if (temp__24970__auto__21) { +let closing22 = temp__24970__auto__21; +return ((closing22 === name(lastChild20)) && (end(firstChild19) !== end(lastChild20)));} else { return true;} -})()); +}) +; var ancestors = (function (node) { -let temp__25231__auto__17 = up(node); -if (squint_core.nil_QMARK_(temp__25231__auto__17)) { +let temp__25231__auto__23 = up(node); +if (squint_core.nil_QMARK_(temp__25231__auto__23)) { return null;} else { -let parent18 = temp__25231__auto__17; -return squint_core.cons(parent18, new squint_core.LazySeq((function () { -return ancestors(parent18); +let parent24 = temp__25231__auto__23; +return squint_core.cons(parent24, new squint_core.LazySeq((function () { +return ancestors(parent24); })));} }) ; @@ -287,51 +292,51 @@ return squint_core.reduced(found);} }) ; var children = (function () { - let f19 = (function (var_args) { -let G__2223 = arguments["length"]; -switch (G__2223) {case 3: -return f19.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); + let f25 = (function (var_args) { +let G__2829 = arguments["length"]; +switch (G__2829) {case 3: +return f25.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); break; case 1: -return f19.cljs$core$IFn$_invoke$arity$1((arguments[0])); +return f25.cljs$core$IFn$_invoke$arity$1((arguments[0])); break; default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); -f19["cljs$core$IFn$_invoke$arity$3"] = (function (parent, from, dir) { -let temp__25231__auto__25 = (function () { - let G__2627 = dir; -switch (G__2627) {case 1: +f25["cljs$core$IFn$_invoke$arity$3"] = (function (parent, from, dir) { +let temp__25231__auto__31 = (function () { + let G__3233 = dir; +switch (G__3233) {case 1: return parent.childAfter(from); break; case -1: return parent.childBefore(from); break; default: -throw new Error(squint_core.str("No matching clause: ", G__2627))} +throw new Error(squint_core.str("No matching clause: ", G__3233))} })(); -if (squint_core.nil_QMARK_(temp__25231__auto__25)) { +if (squint_core.nil_QMARK_(temp__25231__auto__31)) { return null;} else { -let child29 = temp__25231__auto__25; -return squint_core.cons(child29, new squint_core.LazySeq((function () { +let child35 = temp__25231__auto__31; +return squint_core.cons(child35, new squint_core.LazySeq((function () { return children(parent, (function () { - let G__3031 = dir; -switch (G__3031) {case 1: -return end(child29); + let G__3637 = dir; +switch (G__3637) {case 1: +return end(child35); break; case -1: -return start(child29); +return start(child35); break; default: -throw new Error(squint_core.str("No matching clause: ", G__3031))} +throw new Error(squint_core.str("No matching clause: ", G__3637))} })(), dir); })));} }); -f19["cljs$core$IFn$_invoke$arity$1"] = (function (subtree) { +f25["cljs$core$IFn$_invoke$arity$1"] = (function (subtree) { return children(subtree, start(subtree), 1); }); -f19["cljs$lang$maxFixedArity"] = 3; -return f19; +f25["cljs$lang$maxFixedArity"] = 3; +return f25; })() ; var eq_QMARK_ = (function (x, y) { @@ -339,10 +344,10 @@ return ((start(x) == start(y)) && (end(x) == end(y)) && (depth(x) == depth(y))); }) ; var empty_QMARK_ = (function (node) { -let type_name33 = name(node); +let type_name39 = name(node); if (coll_QMARK_(node)) { return eq_QMARK_(right(down(node)), down_last(node));} else { -if (("String" === type_name33)) { +if (("String" === type_name39)) { return (end(down(node)) == start(down_last(node)));} else { if ("else") { return false;} else { @@ -350,25 +355,25 @@ return null;}}} }) ; var from_to = (function () { - let f34 = (function (var_args) { -let G__3738 = arguments["length"]; -switch (G__3738) {case 2: -return f34.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); + let f40 = (function (var_args) { +let G__4344 = arguments["length"]; +switch (G__4344) {case 2: +return f40.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); break; case 1: -return f34.cljs$core$IFn$_invoke$arity$1((arguments[0])); +return f40.cljs$core$IFn$_invoke$arity$1((arguments[0])); break; default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); -f34["cljs$core$IFn$_invoke$arity$2"] = (function (from, to) { +f40["cljs$core$IFn$_invoke$arity$2"] = (function (from, to) { return ({ "from": from, "to": to }); }); -f34["cljs$core$IFn$_invoke$arity$1"] = (function (node) { +f40["cljs$core$IFn$_invoke$arity$1"] = (function (node) { return from_to(start(node), end(node)); }); -f34["cljs$lang$maxFixedArity"] = 2; -return f34; +f40["cljs$lang$maxFixedArity"] = 2; +return f40; })() ; var range = (function (node) { @@ -376,25 +381,25 @@ return sel.range(start(node), end(node)); }) ; var string = (function () { - let f40 = (function (var_args) { -let G__4344 = arguments["length"]; -switch (G__4344) {case 2: -return f40.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); + let f46 = (function (var_args) { +let G__4950 = arguments["length"]; +switch (G__4950) {case 2: +return f46.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); break; case 3: -return f40.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +return f46.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); break; default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); -f40["cljs$core$IFn$_invoke$arity$2"] = (function (state, node) { +f46["cljs$core$IFn$_invoke$arity$2"] = (function (state, node) { return string(state, start(node), end(node)); }); -f40["cljs$core$IFn$_invoke$arity$3"] = (function (state, from, to) { +f46["cljs$core$IFn$_invoke$arity$3"] = (function (state, from, to) { return state["doc"].sliceString(from, to, "\n"); }); -f40["cljs$lang$maxFixedArity"] = 3; -return f40; +f46["cljs$lang$maxFixedArity"] = 3; +return f46; })() ; var ancestor_QMARK_ = (function (parent, child) { @@ -404,8 +409,8 @@ return squint_core.boolean$(((start(parent) <= start(child)) && (end(parent) >= var move_toward = (function (node, to_node) { if (eq_QMARK_(node, to_node)) { return null;} else { -let G__4647 = compare(start(to_node), start(node)); -switch (G__4647) {case 0: +let G__5253 = compare(start(to_node), start(node)); +switch (G__5253) {case 0: if (ancestor_QMARK_(to_node, node)) { return up(node);} else { if (ancestor_QMARK_(node, to_node)) { @@ -423,7 +428,7 @@ return down(node);} else { return (right(node) || up(node));} break; default: -throw new Error(squint_core.str("No matching clause: ", G__4647))}} +throw new Error(squint_core.str("No matching clause: ", G__5253))}} }) ; var nodes_between = (function (node, to_node) { @@ -437,73 +442,73 @@ return (coll_QMARK_(node) || string_QMARK_(node) || regexp_QMARK_(node)); }) ; var tree = (function () { - let f49 = (function (var_args) { -let G__5253 = arguments["length"]; -switch (G__5253) {case 1: -return f49.cljs$core$IFn$_invoke$arity$1((arguments[0])); + let f55 = (function (var_args) { +let G__5859 = arguments["length"]; +switch (G__5859) {case 1: +return f55.cljs$core$IFn$_invoke$arity$1((arguments[0])); break; case 2: -return f49.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +return f55.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); break; case 3: -return f49.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +return f55.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); break; default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); -f49["cljs$core$IFn$_invoke$arity$1"] = (function (state) { +f55["cljs$core$IFn$_invoke$arity$1"] = (function (state) { return language.syntaxTree(state); }); -f49["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { +f55["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { return language.syntaxTree(state).resolveInner(pos); }); -f49["cljs$core$IFn$_invoke$arity$3"] = (function (state, pos, dir) { +f55["cljs$core$IFn$_invoke$arity$3"] = (function (state, pos, dir) { return language.syntaxTree(state).resolveInner(pos, dir); }); -f49["cljs$lang$maxFixedArity"] = 3; -return f49; +f55["cljs$lang$maxFixedArity"] = 3; +return f55; })() ; var cursor = (function () { - let f55 = (function (var_args) { -let G__5859 = arguments["length"]; -switch (G__5859) {case 1: -return f55.cljs$core$IFn$_invoke$arity$1((arguments[0])); + let f61 = (function (var_args) { +let G__6465 = arguments["length"]; +switch (G__6465) {case 1: +return f61.cljs$core$IFn$_invoke$arity$1((arguments[0])); break; case 2: -return f55.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +return f61.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); break; case 3: -return f55.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +return f61.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); break; default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); -f55["cljs$core$IFn$_invoke$arity$1"] = (function (tree) { +f61["cljs$core$IFn$_invoke$arity$1"] = (function (tree) { return tree.cursor(); }); -f55["cljs$core$IFn$_invoke$arity$2"] = (function (tree, pos) { +f61["cljs$core$IFn$_invoke$arity$2"] = (function (tree, pos) { return tree.cursorAt(pos); }); -f55["cljs$core$IFn$_invoke$arity$3"] = (function (tree, pos, dir) { +f61["cljs$core$IFn$_invoke$arity$3"] = (function (tree, pos, dir) { return tree.cursorAt(pos, dir); }); -f55["cljs$lang$maxFixedArity"] = 3; -return f55; +f61["cljs$lang$maxFixedArity"] = 3; +return f61; })() ; var terminal_cursor = (function (tree, pos, dir) { -let i61 = pos; +let i67 = pos; while(true){ -let c62 = cursor(tree, i61, dir); -let type63 = c62["type"]; -if (top_type_QMARK_(type63)) { +let c68 = cursor(tree, i67, dir); +let type69 = c68["type"]; +if (top_type_QMARK_(type69)) { return null;} else { -if (terminal_type_QMARK_(c62["type"])) { -return c62;} else { +if (terminal_type_QMARK_(c68["type"])) { +return c68;} else { if ("else") { -let G__64 = (dir + i61); -i61 = G__64; +let G__70 = (dir + i67); +i67 = G__70; continue; } else { return null;}}};break; @@ -512,9 +517,9 @@ return null;}}};break; }) ; var up_here = (function (node) { -let from65 = start(node); +let from71 = start(node); return (highest(node, (function (_PERCENT_1) { -return (from65 === start(_PERCENT_1)); +return (from71 === start(_PERCENT_1)); })) || node); }) ; @@ -523,61 +528,87 @@ return up_here(tree(state, from, 1)["node"]).cursor(); }) ; var terminal_nodes = (function (state, from, to) { -let cursor66 = topmost_cursor(state, from); -let found67 = []; +let cursor72 = topmost_cursor(state, from); +let found73 = []; while(true){ -let node_type68 = type(cursor66); -if ((start(cursor66) > to)) { -return found67;} else { -if ((terminal_type_QMARK_(node_type68) || error_QMARK_(node_type68))) { -let found69 = squint_core.conj(found67, ({ "type": node_type68, "from": start(cursor66), "to": end(cursor66) })); -cursor66.lastChild(); -if (cursor66.next()) { -let G__70 = found69; -found67 = G__70; +let node_type74 = type(cursor72); +if ((start(cursor72) > to)) { +return found73;} else { +if ((terminal_type_QMARK_(node_type74) || error_QMARK_(node_type74))) { +let found75 = squint_core.conj(found73, ({ "type": node_type74, "from": start(cursor72), "to": end(cursor72) })); +cursor72.lastChild(); +if (cursor72.next()) { +let G__76 = found75; +found73 = G__76; continue; } else { -return found69;}} else { +return found75;}} else { if ("else") { -if (cursor66.next()) { -let G__71 = found67; -found67 = G__71; +if (cursor72.next()) { +let G__77 = found73; +found73 = G__77; continue; } else { -return found67;}} else { +return found73;}} else { return null;}}};break; } }) ; -j.defn(balanced_range, [state, node](balanced_range(state, start(node), end(node))), [state, from, to]((function () { - let vec__7278 = squint_core.sort([from, to]); -let from79 = squint_core.nth(vec__7278, 0, null); -let to80 = squint_core.nth(vec__7278, 1, null); -let from_node81 = tree(state, from79, 1); -let to_node82 = tree(state, to80, -1); -let from83 = (require_balance_QMARK_(from_node81)) ? (start(from_node81)) : (from79); -let to84 = (require_balance_QMARK_(to_node82)) ? (end(to_node82)) : (to80); -let vec__7585 = squint_core.reduce((function (p__86, node_between) { -let vec__8790 = p__86; -let left91 = squint_core.nth(vec__8790, 0, null); -let right92 = squint_core.nth(vec__8790, 1, null); -return [(ancestor_QMARK_(node_between, from_node81)) ? (start(node_between)) : (left91), (ancestor_QMARK_(node_between, to_node82)) ? (end(node_between)) : (right92)]; -}), [from83, to84], squint_core.map((function (_PERCENT_1) { -let G__9394 = _PERCENT_1; +var balanced_range = (function () { + let f78 = (function (var_args) { +let G__8182 = arguments["length"]; +switch (G__8182) {case 2: +return f78.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +break; +case 3: +return f78.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f78["cljs$core$IFn$_invoke$arity$2"] = (function (state, node) { +return balanced_range(state, start(node), end(node)); +}); +f78["cljs$core$IFn$_invoke$arity$3"] = (function (state, from, to) { +let vec__8490 = squint_core.sort([from, to]); +let from91 = squint_core.nth(vec__8490, 0, null); +let to92 = squint_core.nth(vec__8490, 1, null); +let from_node93 = tree(state, from91, 1); +let to_node94 = tree(state, to92, -1); +let from95 = (require_balance_QMARK_(from_node93)) ? (start(from_node93)) : (from91); +let to96 = (require_balance_QMARK_(to_node94)) ? (end(to_node94)) : (to92); +let vec__8797 = squint_core.reduce((function (p__98, node_between) { +let vec__99102 = p__98; +let left103 = squint_core.nth(vec__99102, 0, null); +let right104 = squint_core.nth(vec__99102, 1, null); +return [(ancestor_QMARK_(node_between, from_node93)) ? (start(node_between)) : (left103), (ancestor_QMARK_(node_between, to_node94)) ? (end(node_between)) : (right104)]; +}), [from95, to96], squint_core.map((function (_PERCENT_1) { +let G__105106 = _PERCENT_1; if (edge_QMARK_(_PERCENT_1)) { -return up(G__9394);} else { -return G__9394;} -}), nodes_between(from_node81, to_node82))); -let left95 = squint_core.nth(vec__7585, 0, null); -let right96 = squint_core.nth(vec__7585, 1, null); -return sel.range(left95, right96); -})())); -j.defn(inner_span, "Span of collection not including edges", [({ "as": node, "keys": [firstChild, lastChild] })], ({ "from": (left_edge_QMARK_(firstChild)) ? (end(firstChild)) : (start(node)), "to": (right_edge_QMARK_(lastChild)) ? (start(lastChild)) : (end(node)) })); +return up(G__105106);} else { +return G__105106;} +}), nodes_between(from_node93, to_node94))); +let left107 = squint_core.nth(vec__8797, 0, null); +let right108 = squint_core.nth(vec__8797, 1, null); +return sel.range(left107, right108); +}); +f78["cljs$lang$maxFixedArity"] = 3; +return f78; +})() +; +var inner_span = (function (p__109) { +let map__110111 = p__109; +let node112 = map__110111; +let firstChild113 = squint_core.get(map__110111, "firstChild"); +let lastChild114 = squint_core.get(map__110111, "lastChild"); +return ({ "from": (left_edge_QMARK_(firstChild113)) ? (end(firstChild113)) : (start(node112)), "to": (right_edge_QMARK_(lastChild114)) ? (start(lastChild114)) : (end(node112)) }); +}) +; var within_QMARK__LT_ = (function (parent, child) { -let c197 = compare(start(parent), start(child)); -let c298 = compare(end(parent), end(child)); -return ((squint_core.pos_QMARK_(c197) || squint_core.neg_QMARK_(c298)) && !squint_core.neg_QMARK_(c197) && !squint_core.pos_QMARK_(c298)); +let c1115 = compare(start(parent), start(child)); +let c2116 = compare(end(parent), end(child)); +return ((squint_core.pos_QMARK_(c1115) || squint_core.neg_QMARK_(c2116)) && !squint_core.neg_QMARK_(c1115) && !squint_core.pos_QMARK_(c2116)); }) ; var within_QMARK_ = (function (parent, child) { @@ -591,121 +622,130 @@ return node;} }) ; var prefix = (function (node) { -let temp__25231__auto__99 = up(node); -if (squint_core.nil_QMARK_(temp__25231__auto__99)) { +let temp__25231__auto__117 = up(node); +if (squint_core.nil_QMARK_(temp__25231__auto__117)) { return null;} else { -let parent100 = temp__25231__auto__99; -return (u.guard(parent100, prefix_container_QMARK_) || u.guard(down(parent100), prefix_edge_QMARK_));} +let parent118 = temp__25231__auto__117; +return (u.guard(parent118, prefix_container_QMARK_) || u.guard(down(parent118), prefix_edge_QMARK_));} }) ; var left_edge_with_prefix = (function (state, node) { return squint_core.str((function () { - let G__101102 = prefix(node); -if (squint_core.nil_QMARK_(G__101102)) { + let G__119120 = prefix(node); +if (squint_core.nil_QMARK_(G__119120)) { return null;} else { -return string(state, G__101102);} +return string(state, G__119120);} })(), name(down(node))); }) ; var with_prefix = (function (node) { -let G__103104 = node; +let G__121122 = node; if (prefix(node)) { -return up(G__103104);} else { -return G__103104;} +return up(G__121122);} else { +return G__121122;} }) ; var node_BAR_ = (function (state, pos) { -let G__105106 = tree(state, pos, -1); -if (squint_core.nil_QMARK_(G__105106)) { +let G__123124 = tree(state, pos, -1); +if (squint_core.nil_QMARK_(G__123124)) { return null;} else { -return u.guard(G__105106, (function (_PERCENT_1) { +return u.guard(G__123124, (function (_PERCENT_1) { return (pos === end(_PERCENT_1)); }));} }) ; var _BAR_node = (function (state, pos) { -let G__107108 = tree(state, pos, 1); -if (squint_core.nil_QMARK_(G__107108)) { +let G__125126 = tree(state, pos, 1); +if (squint_core.nil_QMARK_(G__125126)) { return null;} else { -return u.guard(G__107108, (function (_PERCENT_1) { +return u.guard(G__125126, (function (_PERCENT_1) { return (pos === start(_PERCENT_1)); }));} }) ; var nearest_touching = (function (state, pos, dir) { -let L109 = (function () { - let G__110111 = tree(state, pos, -1); -if (squint_core.nil_QMARK_(G__110111)) { +let L127 = (function () { + let G__128129 = tree(state, pos, -1); +if (squint_core.nil_QMARK_(G__128129)) { return null;} else { -return u.guard(G__110111, j.fn([({ "keys": [to] })], (pos === to)));} +return u.guard(G__128129, (function (p__130) { +let map__131132 = p__130; +let to133 = squint_core.get(map__131132, "to"); +return (pos === to133); +}));} })(); -let R112 = (function () { - let G__113114 = tree(state, pos, 1); -if (squint_core.nil_QMARK_(G__113114)) { +let R134 = (function () { + let G__135136 = tree(state, pos, 1); +if (squint_core.nil_QMARK_(G__135136)) { return null;} else { -return u.guard(G__113114, j.fn([({ "keys": [from] })], (pos === from)));} +return u.guard(G__135136, (function (p__137) { +let map__138139 = p__137; +let from140 = squint_core.get(map__138139, "from"); +return (pos === from140); +}));} })(); -let mid115 = tree(state, pos); -let G__116117 = dir; -switch (G__116117) {case 1: -return (u.guard(R112, every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { +let mid141 = tree(state, pos); +let G__142143 = dir; +switch (G__142143) {case 1: +return (u.guard(R134, every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { return (same_edge_QMARK_(_PERCENT_1) || !right_edge_QMARK_(_PERCENT_1)); -}))) || L109 || R112 || mid115); +}))) || L127 || R134 || mid141); break; case -1: -return (u.guard(L109, every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { +return (u.guard(L127, every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { return (same_edge_QMARK_(_PERCENT_1) || !left_edge_QMARK_(_PERCENT_1)); -}))) || R112 || L109 || mid115); +}))) || R134 || L127 || mid141); break; default: -throw new Error(squint_core.str("No matching clause: ", G__116117))} +throw new Error(squint_core.str("No matching clause: ", G__142143))} }) ; var embedded_QMARK_ = (function () { - let f119 = (function (var_args) { -let G__122123 = arguments["length"]; -switch (G__122123) {case 1: -return f119.cljs$core$IFn$_invoke$arity$1((arguments[0])); + let f145 = (function (var_args) { +let G__148149 = arguments["length"]; +switch (G__148149) {case 1: +return f145.cljs$core$IFn$_invoke$arity$1((arguments[0])); break; case 2: -return f119.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +return f145.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); break; default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); -f119["cljs$core$IFn$_invoke$arity$1"] = (function (state) { +f145["cljs$core$IFn$_invoke$arity$1"] = (function (state) { return embedded_QMARK_(state, state["selection"]["main"]["head"]); }); -f119["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { +f145["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { return squint_core.identical_QMARK_(lezer_markdown.parser.nodeTypes["FencedCode"], state["tree"].resolve(pos)["type"]["id"]); }); -f119["cljs$lang$maxFixedArity"] = 2; -return f119; +f145["cljs$lang$maxFixedArity"] = 2; +return f145; })() ; var within_program_QMARK_ = (function () { - let f125 = (function (var_args) { -let G__128129 = arguments["length"]; -switch (G__128129) {case 1: -return f125.cljs$core$IFn$_invoke$arity$1((arguments[0])); + let f151 = (function (var_args) { +let G__154155 = arguments["length"]; +switch (G__154155) {case 1: +return f151.cljs$core$IFn$_invoke$arity$1((arguments[0])); break; case 2: -return f125.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); +return f151.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); break; default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); -f125["cljs$core$IFn$_invoke$arity$1"] = (function (state) { +f151["cljs$core$IFn$_invoke$arity$1"] = (function (state) { return within_program_QMARK_(state, state["selection"]["main"]["head"]); }); -f125["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { -let n131 = tree(state, pos); -return (program_QMARK_(n131) || squint_core.some(program_QMARK_, ancestors(n131))); +f151["cljs$core$IFn$_invoke$arity$2"] = (function (state, pos) { +let n157 = tree(state, pos); +return (program_QMARK_(n157) || squint_core.some(program_QMARK_, ancestors(n157))); }); -f125["cljs$lang$maxFixedArity"] = 2; -return f125; +f151["cljs$lang$maxFixedArity"] = 2; +return f151; })() ; +squint_core.prn("node-loaded"); null; -export { end_edge_prop, ancestors, range, string_QMARK_, within_QMARK__LT_, edge_QMARK_, right, terminal_nodes, string, same_edge_type_QMARK_, up, line_comment_QMARK_, prefix_coll_prop, prefix, left_edge_with_prefix, top_QMARK_, empty_QMARK_, terminal_type_QMARK_, left_edge_type_QMARK_, children, nodes_between, prefix_edge_QMARK_, discard_QMARK_, right_edge_type_QMARK_, prefix_container_QMARK_, topmost_cursor, coll_prop, closed_by, error_QMARK_, _BAR_node, start_edge_type_QMARK_, prefix_container_prop, down_last, prefix_QMARK_, name, same_edge_QMARK_, prefix_container_type_QMARK_, rights, with_prefix, start, tree, closest, cursor, node_prop, from_to, follow_edges, start_edge_QMARK_, highest, embedded_QMARK_, opened_by, coll_QMARK_, down, type, terminal_cursor, within_QMARK_, depth, prefix_type_QMARK_, same_edge_prop, nearest_touching, regexp_QMARK_, top_type_QMARK_, error_type_QMARK_, up_here, ancestor_QMARK_, end_edge_type_QMARK_, right_edge_QMARK_, start_edge_prop, prefix_edge_prop, node_BAR_, left_edge_QMARK_, coll_type_QMARK_, lefts, require_balance_QMARK_, end, prefix_edge_type_QMARK_, within_program_QMARK_, left, end_edge_QMARK_, program_QMARK_, move_toward, eq_QMARK_ } +export { end_edge_prop, ancestors, range, string_QMARK_, within_QMARK__LT_, edge_QMARK_, right, terminal_nodes, string, same_edge_type_QMARK_, up, line_comment_QMARK_, prefix_coll_prop, prefix, left_edge_with_prefix, top_QMARK_, empty_QMARK_, terminal_type_QMARK_, left_edge_type_QMARK_, children, nodes_between, prefix_edge_QMARK_, discard_QMARK_, right_edge_type_QMARK_, balanced_range, prefix_container_QMARK_, topmost_cursor, coll_prop, closed_by, error_QMARK_, _BAR_node, balanced_QMARK_, start_edge_type_QMARK_, prefix_container_prop, down_last, prefix_QMARK_, name, same_edge_QMARK_, prefix_container_type_QMARK_, rights, with_prefix, start, tree, closest, cursor, node_prop, from_to, follow_edges, start_edge_QMARK_, highest, embedded_QMARK_, opened_by, coll_QMARK_, down, type, terminal_cursor, within_QMARK_, inner_span, depth, prefix_type_QMARK_, same_edge_prop, nearest_touching, regexp_QMARK_, top_type_QMARK_, error_type_QMARK_, up_here, ancestor_QMARK_, end_edge_type_QMARK_, right_edge_QMARK_, start_edge_prop, prefix_edge_prop, node_BAR_, left_edge_QMARK_, coll_type_QMARK_, lefts, require_balance_QMARK_, end, prefix_edge_type_QMARK_, within_program_QMARK_, left, end_edge_QMARK_, program_QMARK_, move_toward, eq_QMARK_ } diff --git a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs index 9b531669..03993fc6 100644 --- a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs +++ b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs @@ -1,14 +1,11 @@ (ns nextjournal.clojure-mode.extensions.close-brackets - (:require ["w3c-keyname" :refer [keyName]] - ["@codemirror/view" :as view] + (:require ["@codemirror/view" :as view] ["@codemirror/state" :refer [EditorState - EditorSelection - Transaction - CharCategory - Extension Prec]] - [nextjournal.clojure-mode.node :as n] - [nextjournal.clojure-mode.util :as u :refer [from-to]] + ["../node.mjs" :as n] + #_[nextjournal.clojure-mode.node :as n] + ["../util.mjs" :as u :refer [from-to]] + #_[nextjournal.clojure-mode.util :as u :refer [from-to]] [clojure.string :as str])) (defn in-string? [state pos] @@ -28,17 +25,17 @@ {:cursor (dec from)} (u/deletion from to))) -(j/defn handle-backspace +(defn handle-backspace "- skips over closing brackets - when deleting an opening bracket of an empty list, removes both brackets" [^:js {:as ^EditorState state :keys [doc]}] (when-not (and (= 1 (.. state -selection -ranges -length)) - (let [^js range (j/get-in state [:selection :ranges 0])] + (let [^js range (get-in state [:selection :ranges 0])] (and (.-empty range) (= 0 (.-from range))))) (u/update-ranges state #js{:annotations (u/user-event-annotation "delete")} - (j/fn [^:js {:as range :keys [head empty anchor]}] - (j/let [^:js {:as range from :from to :to} (from-to head anchor) + (fn [^:js {:as range :keys [head empty anchor]}] + (let [^:js {:as range from :from to :to} (from-to head anchor) ^js node| (.resolveInner (n/tree state) from -1) ;; node immediately to the left of cursor ^js parent (.-parent node|)] (cond @@ -73,7 +70,7 @@ (let [^string close (coll-pairs open)] (u/update-ranges state #js{:annotations (u/user-event-annotation "input")} - (j/fn [^:js {:keys [from to head anchor empty]}] + (fn [^:js {:keys [from to head anchor empty]}] (cond (in-string? state from) (if (= open \") @@ -95,7 +92,7 @@ (defn handle-close [state key-name] (u/update-ranges state #js{:annotations (u/user-event-annotation "input")} - (j/fn [^:js {:as range :keys [empty head from to]}] + (fn [^:js {:as range :keys [empty head from to]}] (if (or (in-string? state from) (escaped? state from)) (u/insertion from to key-name) @@ -128,15 +125,15 @@ {:cursor head} #_(u/insertion head key-name))))))) -(j/defn handle-backspace-cmd [^:js {:as view :keys [state]}] +(defn handle-backspace-cmd [^:js {:as view :keys [state]}] (u/dispatch-some view (handle-backspace state))) (defn handle-open-cmd [key-name] - (j/fn [^:js {:as view :keys [state]}] + (fn [^:js {:as view :keys [state]}] (u/dispatch-some view (handle-open state key-name)))) (defn handle-close-cmd [key-name] - (j/fn [^:js {:as view :keys [state]}] + (fn [^:js {:as view :keys [state]}] (u/dispatch-some view (handle-close state key-name)))) (defn guard-scope @@ -144,7 +141,7 @@ Guards command for it to be triggered from within the right scope, does nothing and propagates key otherwise" [cmd] - (j/fn [^:js {:as view :keys [state]}] + (fn [^:js {:as view :keys [state]}] (if (or (n/embedded? state) (n/within-program? state)) (cmd view) false))) @@ -152,15 +149,16 @@ (defn extension [] (.high Prec (.of view/keymap - (j/lit - [{:key "Backspace" - :run (guard-scope - (j/fn [^:js {:as view :keys [state]}] - (u/dispatch-some view (handle-backspace state))))} - {:key "(" :run (guard-scope (handle-open-cmd "("))} - {:key "[" :run (guard-scope (handle-open-cmd "["))} - {:key "{" :run (guard-scope (handle-open-cmd "{"))} - {:key \" :run (guard-scope (handle-open-cmd \"))} - {:key \) :run (guard-scope (handle-close-cmd \)))} - {:key \] :run (guard-scope (handle-close-cmd \]))} - {:key \} :run (guard-scope (handle-close-cmd \}))}])))) + [{:key "Backspace" + :run (guard-scope + (fn [^:js {:as view :keys [state]}] + (u/dispatch-some view (handle-backspace state))))} + {:key "(" :run (guard-scope (handle-open-cmd "("))} + {:key "[" :run (guard-scope (handle-open-cmd "["))} + {:key "{" :run (guard-scope (handle-open-cmd "{"))} + {:key \" :run (guard-scope (handle-open-cmd \"))} + {:key \) :run (guard-scope (handle-close-cmd \)))} + {:key \] :run (guard-scope (handle-close-cmd \]))} + {:key \} :run (guard-scope (handle-close-cmd \}))}]))) + +(prn :close-brackets-loaded) diff --git a/src-squint/nextjournal/clojure_mode/node.cljs b/src-squint/nextjournal/clojure_mode/node.cljs index 75a3706f..c7a0caf3 100644 --- a/src-squint/nextjournal/clojure_mode/node.cljs +++ b/src-squint/nextjournal/clojure_mode/node.cljs @@ -161,7 +161,7 @@ (identical? "ConstructorCall" (name node-type)) false :else true)) -(j/defn balanced? [^:js {:as node :keys [^js firstChild ^js lastChild]}] +(defn balanced? [^:js {:as node :keys [^js firstChild ^js lastChild]}] (if-let [closing (closed-by firstChild)] (and (= closing (name lastChild)) (not= (end firstChild) (end lastChild))) @@ -304,7 +304,7 @@ (recur found) found)))))) -(j/defn balanced-range +(defn balanced-range ([state ^js node] (balanced-range state (start node) (end node))) ([state from to] (let [[from to] (sort [from to]) @@ -324,7 +324,7 @@ [from to]))] (sel/range left right)))) -(j/defn inner-span +(defn inner-span "Span of collection not including edges" [^:js {:as node :keys [firstChild lastChild]}] #js{:from (if (left-edge? firstChild) @@ -379,9 +379,9 @@ (defn nearest-touching [^js state pos dir] (let [L (some-> (tree state pos -1) - (u/guard (j/fn [^:js {:keys [to]}] (= pos to)))) + (u/guard (fn [^:js {:keys [to]}] (= pos to)))) R (some-> (tree state pos 1) - (u/guard (j/fn [^:js {:keys [from]}] + (u/guard (fn [^:js {:keys [from]}] (= pos from)))) mid (tree state pos)] (case dir 1 (or (u/guard R (every-pred some? #(or (same-edge? %) (not (right-edge? %))))) @@ -410,6 +410,8 @@ (or (program? n) (some program? (ancestors n)))))) +(prn :node-loaded) + (comment ;; test state overlaid nodes (let [state From 08d9886266891db612603da3625dff1cd8332264 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 16:14:35 +0200 Subject: [PATCH 07/80] match brackets --- public/squint/js/main.mjs | 2 + .../extensions/match_brackets.mjs | 57 +++++++++++++ .../extensions/match_brackets.cljs | 81 +++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs create mode 100644 src-squint/nextjournal/clojure_mode/extensions/match_brackets.cljs diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index caa83e54..c3bf87be 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -1,4 +1,6 @@ import './src-squint/nextjournal/clojure_mode/util.mjs'; import './src-squint/nextjournal/clojure_mode/node.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; +import './src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs'; + console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs new file mode 100644 index 00000000..4f959d4b --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs @@ -0,0 +1,57 @@ +import * as squint_core from 'squint-cljs/core.js'; +import { StateField } from '@codemirror/state'; +import { EditorView, Decoration } from '@codemirror/view'; +import * as n from '../node.mjs'; +import * as u from '../util.mjs'; +var base_theme = EditorView.baseTheme(({ "$matchingBracket": ({ "color": "#0b0" }), "$nonmatchingBracket": ({ "color": "#a22" }) })) +; +var matching_mark = Decoration.mark(({ "class": "cm-matchingBracket" })) +; +var nonmatching_mark = Decoration.mark(({ "class": "cm-nonmatchingBracket" })) +; +var mark_node = (function (node, mark) { +return mark.range(n.start(node), n.end(node)); +}) +; +var state = StateField.define(({ "create": squint_core.constantly(Decoration["none"]), "update": (function (deco, p__1) { +let map__23 = p__1; +let tr4 = map__23; +let state5 = squint_core.get(map__23, "state"); +let docChanged6 = squint_core.get(map__23, "docChanged"); +let selection7 = squint_core.get(map__23, "selection"); +if ((docChanged6 || selection7)) { +let decos8 = squint_core.reduce((function (out, p__9) { +let map__1011 = p__9; +let head12 = squint_core.get(map__1011, "head"); +let empty13 = squint_core.get(map__1011, "empty"); +return ((function () { + let temp__25187__auto__14 = (empty13 && squint_core.first(squint_core.filter(some_fn(n.start_edge_QMARK_, n.end_edge_QMARK_), [n.tree(state5, head12, -1), n.tree(state5, head12, 1)]))); +if (temp__25187__auto__14) { +let bracket15 = temp__25187__auto__14; +let temp__24970__auto__16 = ((n.start_edge_QMARK_(bracket15) && (n.start(bracket15) === n.start(n.up(bracket15))))) ? (u.guard(n.down_last(n.up(bracket15)), (function (_PERCENT_1) { +return (n.name(_PERCENT_1) === n.closed_by(bracket15)); +}))) : (((n.end_edge_QMARK_(bracket15) && (n.end(bracket15) === n.end(n.up(bracket15))))) ? (u.guard(n.down(n.up(bracket15)), (function (_PERCENT_1) { +return (n.name(_PERCENT_1) === n.opened_by(bracket15)); +}))) : (null)); +if (temp__24970__auto__16) { +let other_bracket17 = temp__24970__auto__16; +return squint_core.conj(out, mark_node(bracket15, matching_mark), mark_node(other_bracket17, matching_mark));} else { +return squint_core.conj(out, mark_node(bracket15, nonmatching_mark));}} +})() || (function () { + let temp__25187__auto__18 = (!n.closest(n.tree(state5, head12), n.string_QMARK_) && new Set(["]", ")", "}"])(tr4["state"]["doc"].slice(head12, (head12 + 1)).toString())); +if (temp__25187__auto__18) { +let _unparsed_bracket19 = temp__25187__auto__18; +return squint_core.conj(out, mark_node(n.from_to(head12, (head12 + 1)), nonmatching_mark));} +})() || out); +}), [], tr4["state"]["selection"]["ranges"]); +return Decoration.set(into_array(decos8), true);} else { +return deco;} +}) })) +; +var extension = (function () { +return [base_theme, state, EditorView["decorations"].from(state)]; +}) +; +squint_core.prn("match-brackets-loaded"); + +export { base_theme, matching_mark, nonmatching_mark, mark_node, state, extension } diff --git a/src-squint/nextjournal/clojure_mode/extensions/match_brackets.cljs b/src-squint/nextjournal/clojure_mode/extensions/match_brackets.cljs new file mode 100644 index 00000000..6ab5f34e --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/extensions/match_brackets.cljs @@ -0,0 +1,81 @@ +(ns nextjournal.clojure-mode.extensions.match-brackets + (:require + ["@codemirror/state" :refer [StateField]] + ["@codemirror/view" :refer [EditorView + Decoration]] + ["../node.mjs" :as n] + #_[nextjournal.clojure-mode.node :as n] + ["../util.mjs" :as u] + #_[nextjournal.clojure-mode.util :as u :refer [from-to]])) + +(def base-theme + (->> + {:$matchingBracket {:color "#0b0"} + :$nonmatchingBracket {:color "#a22"}} + (.baseTheme EditorView))) + +(def ^js matching-mark (.mark Decoration {:class "cm-matchingBracket"})) +(def ^js nonmatching-mark (.mark Decoration {:class "cm-nonmatchingBracket"})) + +(defn mark-node [node ^js mark] + (.range mark (n/start node) (n/end node))) + +(def state + (->> + {:create (constantly (.-none Decoration)) + :update (fn [deco ^:js {:as tr :keys [state docChanged selection]}] + (if (or docChanged selection) + (let [decos (->> (.. tr -state -selection -ranges) + (reduce + (fn [out ^:js {:keys [head empty]}] + (or + ;; a parsed bracket is found before/after cursor + (when-let [bracket (and empty + (->> [(n/tree state head -1) (n/tree state head 1)] + (filter (some-fn n/start-edge? n/end-edge?)) + first))] + ;; try finding a matching bracket + (if-let [other-bracket (cond + + ;; are we at starting position? + (and (n/start-edge? bracket) + (= (n/start bracket) + (n/start (n/up bracket)))) + ;; get end-bracket + (-> bracket n/up n/down-last + (u/guard #(= (n/name %) + (n/closed-by bracket)))) + + ;; are we at ending position? + (and (n/end-edge? bracket) + (= (n/end bracket) + (n/end (n/up bracket)))) + ;; get start-bracket + (-> bracket n/up n/down + (u/guard #(= (n/name %) + (n/opened-by bracket)))))] + (conj out + (mark-node bracket matching-mark) + (mark-node other-bracket matching-mark)) + (conj out (mark-node bracket nonmatching-mark)))) + ;; lezer does not produce tokens for non-matching close-brackets + ;; (we haven't entered a collection, so brackets are not valid tokens + ;; and aren't parsed). So we need to check the string to see if an + ;; unmatched bracket is sitting in front of the cursor. + (when-let [_unparsed-bracket (and + ;; skip this check if we're inside a string + (not (-> (n/tree state head) (n/closest n/string?))) + (-> (.. tr -state -doc (slice head (inc head)) toString) + (#{\] \) \}})))] + (conj out (mark-node (n/from-to head (inc head)) nonmatching-mark))) + out)) []))] + (.set Decoration (into-array decos) true)) + deco))} + (.define StateField))) + +(defn extension [] + #js[base-theme + state + (.. EditorView -decorations (from state))]) + +(prn :match-brackets-loaded) From 66385e0060a8e479b7381fb69fdaead09b1abfe8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 16:59:29 +0200 Subject: [PATCH 08/80] formatting --- public/squint/js/main.mjs | 1 + .../clojure_mode/extensions/formatting.mjs | 237 ++++++++++++++++++ .../nextjournal/clojure_mode/util.mjs | 8 +- .../clojure_mode/extensions/formatting.cljs | 185 ++++++++++++++ src-squint/nextjournal/clojure_mode/util.cljs | 3 + src/nextjournal/clojure_mode.cljs | 1 + 6 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/extensions/formatting.mjs create mode 100644 src-squint/nextjournal/clojure_mode/extensions/formatting.cljs diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index c3bf87be..47e47bb4 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -2,5 +2,6 @@ import './src-squint/nextjournal/clojure_mode/util.mjs'; import './src-squint/nextjournal/clojure_mode/node.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs'; +import './src-squint/nextjournal/clojure_mode/extensions/formatting.mjs'; console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/formatting.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/formatting.mjs new file mode 100644 index 00000000..d5b9818d --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/formatting.mjs @@ -0,0 +1,237 @@ +import * as squint_core from 'squint-cljs/core.js'; +import * as language from '@codemirror/language'; +import { IndentContext } from '@codemirror/language'; +import { EditorState } from '@codemirror/state'; +import * as n from '../node.mjs'; +import * as u from '../util.mjs'; +var spaces = (function (state, n) { +return language.indentString(state, n); +}) +; +var indent_node_props = (function (p__1) { +let map__23 = p__1; +let type4 = map__23; +let type_name5 = squint_core.get(map__23, "name"); +return function (p__6) { +let map__78 = p__6; +let context9 = map__78; +let pos10 = squint_core.get(map__78, "pos"); +let unit11 = squint_core.get(map__78, "unit"); +let node12 = squint_core.get(map__78, "node"); +let state13 = squint_core.get(map__78, "state"); +if (("Program" === type_name5)) { +return 0;} else { +if (n.coll_type_QMARK_(type4)) { +let G__1415 = context9.column(n.end(n.down(node12))); +if ((("List" === type_name5) && new Set(["Operator", "DefLike", "NS"])((function () { + let G__1617 = node12; +let G__1618 = (squint_core.nil_QMARK_(G__1617)) ? (null) : (n.down(G__1617)); +let G__1619 = (squint_core.nil_QMARK_(G__1618)) ? (null) : (n.right(G__1618)); +if (squint_core.nil_QMARK_(G__1619)) { +return null;} else { +return n.name(G__1619);} +})()))) { +return (G__1415 + 1);} else { +return G__1415;}} else { +if ("else") { +return -1;} else { +return null;}}} +}; +}) +; +var props = language.indentNodeProp.add(indent_node_props) +; +var get_indentation = (function (context, pos) { +return language.getIndentation(context["state"], pos); +}) +; +var make_indent_context = (function (state) { +return new IndentContext(state); +}) +; +var indent_all = (function (state) { +let context20 = make_indent_context(state); +return u.update_lines(state, (function (from, content, line_num) { +let current_indent21 = /^\s*/.exec(content)[0]["length"]; +let indent22 = u.guard(get_indentation(context20, from), squint_core.complement(squint_core.neg_QMARK_)); +if (indent22) { +let G__2324 = compare(indent22, current_indent21); +switch (G__2324) {case 0: +return null; +break; +case 1: +return ({ "from": (from + current_indent21), "insert": spaces(state, (indent22 - current_indent21)) }); +break; +case -1: +return ({ "from": (from + indent22), "to": (from + current_indent21) }); +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__2324))}} +})); +}) +; +var expected_space = (function (n1, n2) { +if ((n.start_edge_type_QMARK_(n1) || n.prefix_edge_type_QMARK_(n1) || n.end_edge_type_QMARK_(n2) || n.same_edge_type_QMARK_(n2))) { +return 0;} else { +return 1;} +}) +; +var space_changes = (function (state, from, to) { +let nodes26 = squint_core.reverse(squint_core.filter((function (_PERCENT_1) { +return (((from <= n.start(_PERCENT_1)) && (n.start(_PERCENT_1) <= to)) || ((from <= n.end(_PERCENT_1)) && (n.end(_PERCENT_1) <= to))); +}), n.terminal_nodes(state, from, to))); +let trim_QMARK_27 = (function () { + let G__2829 = squint_core.first(nodes26); +let G__2830 = (squint_core.nil_QMARK_(G__2829)) ? (null) : (n.end(G__2829)); +if (squint_core.nil_QMARK_(G__2830)) { +return null;} else { +return (G__2830 < to);} +})(); +return squint_core.reduce((function (out, p__31) { +let vec__3237 = p__31; +let map__3538 = squint_core.nth(vec__3237, 0, null); +let n239 = squint_core.get(map__3538, "type"); +let start240 = squint_core.get(map__3538, "from"); +let end241 = squint_core.get(map__3538, "to"); +let map__3642 = squint_core.nth(vec__3237, 1, null); +let n143 = squint_core.get(map__3642, "type"); +let start144 = squint_core.get(map__3642, "from"); +let end145 = squint_core.get(map__3642, "to"); +let expected46 = expected_space(n143, n239); +let actual47 = (start240 - end145); +let G__4849 = compare(actual47, expected46); +switch (G__4849) {case 0: +return out; +break; +case 1: +return u.push_BANG_(out, ({ "from": ((expected46 == 0)) ? (end145) : ((end145 + 1)), "to": start240 })); +break; +case -1: +return u.push_BANG_(out, ({ "from": end145, "insert": " " })); +break; +default: +return out;} +}), (trim_QMARK_27) ? ([({ "from": n.end(squint_core.first(nodes26)), "to": to })]) : ([]), squint_core.partition(2, 1, nodes26)); +}) +; +var into_arr = (function (arr, items) { +for (let i of items) { +[true, arr.push(i)] +}; +null; +return arr; +}) +; +var format_line = (function (state, indent_context, from, text, line_num, changes, format_spaces_QMARK_) { +assert(squint_core.some_QMARK_(text)); +let current_indent51 = /^\s*/.exec(text)[0]["length"]; +let indent52 = u.guard(get_indentation(indent_context, from), squint_core.complement(squint_core.neg_QMARK_)); +let indentation_change53 = (indent52) ? ((function () { + let G__5455 = compare(indent52, current_indent51); +switch (G__5455) {case 0: +return null; +break; +case 1: +return ({ "from": (from + current_indent51), "insert": spaces(state, (indent52 - current_indent51)) }); +break; +case -1: +return ({ "from": (from + indent52), "to": (from + current_indent51) }); +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__5455))} +})()) : (null); +let space_changes57 = ((format_spaces_QMARK_ && (n.embedded_QMARK_(state, from) || n.within_program_QMARK_(state, from)))) ? (space_changes(state, (from + current_indent51), (from + squint_core.count(text)))) : (null); +let G__5859 = changes; +let G__5860 = (space_changes57) ? (into_arr(G__5859, space_changes57)) : (G__5859); +if (indentation_change53) { +return u.push_BANG_(G__5860, indentation_change53);} else { +return G__5860;} +}) +; +var format_selection = (function (state) { +let context61 = make_indent_context(state); +return u.update_selected_lines(state, (function (p__62, changes, range) { +let map__6364 = p__62; +let line65 = map__6364; +let from66 = squint_core.get(map__6364, "from"); +let text67 = squint_core.get(map__6364, "text"); +let number68 = squint_core.get(map__6364, "number"); +return format_line(state, context61, from66, text67, number68, changes, true); +})); +}) +; +var format_all = (function (state) { +let context69 = make_indent_context(state); +return u.update_lines(state, (function (from, text, line_num) { +return format_line(state, context69, from, text, line_num, [], true); +})); +}) +; +var format_transaction = (function (tr) { +let origin70 = u.get_user_event_annotation(tr); +let temp__25059__auto__71 = (n.within_program_QMARK_(tr["startState"])) ? ((function () { + let G__7273 = origin70; +switch (G__7273) {case "input": +return null; +break; +case "input.type": +return null; +break; +case "delete": +return null; +break; +case "keyboardselection": +return null; +break; +case "pointerselection": +return null; +break; +case "select.pointer": +return null; +break; +case "cut": +return null; +break; +case "noformat": +return null; +break; +case "evalregion": +return null; +break; +case "format-selections": +return format_selection(tr["state"]); +break; +default: +if (tr["changes"]["empty"]) { +return null;} else { +let state75 = tr["state"]; +let context76 = make_indent_context(state75); +return u.iter_changed_lines(tr, (function (line, changes) { +return format_line(state75, context76, line["from"], line["text"], line["number"], changes, true); +}));}} +})()) : (null); +if (squint_core.nil_QMARK_(temp__25059__auto__71)) { +return tr;} else { +let changes77 = temp__25059__auto__71; +return tr["startState"].update(squint_core.assoc_BANG_(changes77, "filter", false));} +}) +; +var format = (function (state) { +if (u.something_selected_QMARK_(state)) { +return state.update(format_selection(state));} else { +return format_all(state);} +}) +; +var prefix_all = (function (prefix, state) { +return u.update_lines(state, (function (from, _, _78) { +return ({ "from": from, "insert": prefix }); +})); +}) +; +var ext_format_changed_lines = (function () { +return EditorState["transactionFilter"].of(format_transaction); +}) +; +squint_core.prn("formatting-loaded"); + +export { format_selection, expected_space, get_indentation, ext_format_changed_lines, format_all, format_transaction, space_changes, spaces, make_indent_context, indent_all, props, indent_node_props, prefix_all, into_arr, format_line, format } diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs index be7cf7ed..fa55096d 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs @@ -282,6 +282,12 @@ return G__121123;}} else { return tr102;} }) ; +var push_BANG_ = (function (arr, x) { +let G__124125 = arr; +G__124125.push(x); +return G__124125; +}) +; squint_core.prn("util-loaded"); -export { dispatch_some, guard, node_js_QMARK_, dispatch_changes, insertion, deletion, line_content_at, update_selected_lines, map_cursor, get_user_event_annotation, user_event_annotation, update_ranges, from_to, iter_changed_lines, update_lines } +export { dispatch_some, guard, node_js_QMARK_, dispatch_changes, insertion, deletion, line_content_at, update_selected_lines, map_cursor, get_user_event_annotation, user_event_annotation, update_ranges, from_to, iter_changed_lines, update_lines, push_BANG_ } diff --git a/src-squint/nextjournal/clojure_mode/extensions/formatting.cljs b/src-squint/nextjournal/clojure_mode/extensions/formatting.cljs new file mode 100644 index 00000000..e711b44d --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/extensions/formatting.cljs @@ -0,0 +1,185 @@ +(ns nextjournal.clojure-mode.extensions.formatting + (:require ["@codemirror/language" :as language :refer [IndentContext]] + ["@codemirror/state" :refer [EditorState]] + ["../node.mjs" :as n] + #_[nextjournal.clojure-mode.node :as n] + ["../util.mjs" :as u] + #_[nextjournal.clojure-mode.util :as u :refer [from-to]] + )) + +;; CodeMirror references +;; IndentContext https://codemirror.net/6/docs/ref/#state.IndentContext +;; indentation facet: https://codemirror.net/6/docs/ref/#state.EditorState%5Eindentation +;; indentation commands: https://codemirror.net/6/docs/ref/#commands.indentSelection + +;; Clojure formatting reference +;; https://tonsky.me/blog/clojurefmt/ + +(defn spaces [^js state n] + (.indentString language state n)) + +(defn indent-node-props [^:js {type-name :name :as type}] + (fn [^:js {:as ^js context :keys [pos unit node ^js state]}] + (cond (= "Program" type-name) + 0 + + (n/coll-type? type) + (cond-> (.column context + (-> node n/down n/end)) + ;; start at the inner-left edge of the coll. + ;; if it's a list beginning with a symbol, add 1 space. + (and (= "List" type-name) + (#{"Operator" + "DefLike" + "NS"} (some-> node n/down n/right n/name))) + (+ 1)) + :else -1))) + +(def props (.add language/indentNodeProp + indent-node-props)) + +(defn get-indentation [^js context pos] + (language/getIndentation (.-state context) pos)) + +(defn make-indent-context [state] + (new IndentContext state)) + +;; TODO: check if this is used at all +(defn indent-all [^js state] + (let [context (make-indent-context state)] + (u/update-lines state + (fn [from content line-num] + (let [current-indent (-> (.exec #"^\s*" content) + ^js (aget 0) + .-length) + ^number indent (-> (get-indentation context from) + (u/guard (complement neg?)))] + (when indent + (case (compare indent current-indent) + 0 nil + 1 #js{:from (+ from current-indent) + :insert (spaces state (- indent ^number current-indent))} + -1 #js{:from (+ from indent) + :to (+ from current-indent)}))))))) + +(defn expected-space [n1 n2] + ;; (prn :expected (map n/name [n1 n2])) + (if + (or + (n/start-edge-type? n1) + (n/prefix-edge-type? n1) + (n/end-edge-type? n2) + (n/same-edge-type? n2)) + 0 + 1)) + +(defn space-changes [state from to] + (let [nodes (->> (n/terminal-nodes state from to) + (filter #(or (<= from (n/start %) to) + (<= from (n/end %) to))) + (reverse)) + trim? (some-> (first nodes) n/end (< to))] + (->> nodes + (partition 2 1) + (reduce (fn [out [^:js {n2 :type start2 :from end2 :to} + ^:js {n1 :type start1 :from end1 :to}]] + (let [expected (expected-space n1 n2) + actual (- start2 end1)] + (case (compare actual expected) + 0 out + 1 (u/push! out #js{:from (if (zero? expected) + end1 + (inc end1)) + :to start2}) + -1 (u/push! out #js{:from end1 + :insert " "}) + out))) + + (if trim? + [{:from (-> nodes first n/end) + :to to}] + #js[]))))) + +(defn into-arr [^js arr items] + (doseq [i items] (.push arr i)) + arr) + +(defn format-line + "Returns mutated `changes` array" + [^js state + indent-context + from + text + line-num + changes + format-spaces?] + {:pre [(some? text)]} + (let [current-indent (-> ^js (aget (.exec #"^\s*" text) 0) + .-length) + ^number indent (-> (get-indentation indent-context from) + (u/guard (complement neg?))) + indentation-change + (when indent + (case (compare indent current-indent) + 0 nil + 1 #js{:from (+ from current-indent) + :insert (spaces state (- indent current-indent))} + -1 #js{:from (+ from indent) + :to (+ from current-indent)})) + space-changes (when (and format-spaces? + (or (n/embedded? state from) + (n/within-program? state from))) + (space-changes state + (+ from current-indent) + (+ from (count text))))] + (cond-> changes + space-changes (into-arr space-changes) + indentation-change (u/push! indentation-change)))) + +(defn format-selection + [^js state] + (let [context (make-indent-context state)] + (u/update-selected-lines state + (fn [^:js {:as line :keys [from text number]} ^js changes ^js range] + (format-line state context from text number changes true))))) + +(defn format-all [state] + (let [context (make-indent-context state)] + (u/update-lines state + (fn [^number from ^string text line-num] + (format-line state context from text line-num #js[] true))))) + +(defn format-transaction [^js tr] + (let [origin (u/get-user-event-annotation tr)] + (if-some [changes + (when (n/within-program? (.-startState tr)) + (case origin + ("input" "input.type" + "delete" + "keyboardselection" + "pointerselection" "select.pointer" + "cut" + "noformat" + "evalregion") nil + "format-selections" (format-selection (.-state tr)) + (when-not (.. tr -changes -empty) + (let [state (.-state tr) + context (make-indent-context state)] + (u/iter-changed-lines tr + (fn [^js line ^js changes] + (format-line state context (.-from line) (.-text line) (.-number line) changes true)))))))] + (.. tr -startState (update (assoc! changes :filter false))) + tr))) + +(defn format [state] + (if (u/something-selected? state) + (.update state (format-selection state)) + (format-all state))) + +(defn prefix-all [prefix state] + (u/update-lines state + (fn [from _ _] #js{:from from :insert prefix}))) + +(defn ext-format-changed-lines [] (.. EditorState -transactionFilter (of format-transaction))) + +(prn :formatting-loaded) diff --git a/src-squint/nextjournal/clojure_mode/util.cljs b/src-squint/nextjournal/clojure_mode/util.cljs index 471429a2..d80d02a6 100644 --- a/src-squint/nextjournal/clojure_mode/util.cljs +++ b/src-squint/nextjournal/clojure_mode/util.cljs @@ -162,4 +162,7 @@ ;; (j/defn range-str [state ^:js {:as selection :keys [from to]}] ;; (str (j/call-in state [:doc :slice] from to))) +(defn push! [arr x] + (doto arr (.push x))) + (prn :util-loaded) diff --git a/src/nextjournal/clojure_mode.cljs b/src/nextjournal/clojure_mode.cljs index f3ebf128..621758a3 100644 --- a/src/nextjournal/clojure_mode.cljs +++ b/src/nextjournal/clojure_mode.cljs @@ -5,6 +5,7 @@ [applied-science.js-interop :as j] [nextjournal.clojure-mode.extensions.close-brackets :as close-brackets] [nextjournal.clojure-mode.extensions.match-brackets :as match-brackets] + ;; TODO: [nextjournal.clojure-mode.extensions.formatting :as format] [nextjournal.clojure-mode.extensions.selection-history :as sel-history] [nextjournal.clojure-mode.keymap :as keymap] From b509991a94ece8a2a8c5e95a7f7492f2d9166eb1 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 17:02:27 +0200 Subject: [PATCH 09/80] selection history --- public/squint/js/main.mjs | 1 + .../extensions/selection_history.mjs | 78 +++++++++++++++ .../extensions/selection_history.cljs | 95 +++++++++++++++++++ src/nextjournal/clojure_mode.cljs | 2 +- 4 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs create mode 100644 src-squint/nextjournal/clojure_mode/extensions/selection_history.cljs diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 47e47bb4..f81b95f8 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -3,5 +3,6 @@ import './src-squint/nextjournal/clojure_mode/node.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/formatting.mjs'; +import './src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs'; console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs new file mode 100644 index 00000000..607a8ef2 --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs @@ -0,0 +1,78 @@ +import * as squint_core from 'squint-cljs/core.js'; +import { StateField } from '@codemirror/state'; +import * as n from '../node.mjs'; +import * as u from '../util.mjs'; +import * as sel from '../selections.mjs'; +var event_annotation = u.user_event_annotation("selectionhistory") +; +var second_last = (function (arr) { +if ((arr["length"] > 1)) { +return arr[(arr["length"] - 1)];} +}) +; +var ser = (function (selection) { +return squint_core.map(juxt("anchor", "head"), squint_core.get(js__GT_clj(selection.toJSON(), "keywordize-keys", true), "ranges")); +}) +; +var something_selected_QMARK_ = (function (selection) { +return squint_core.some((function (_PERCENT_1) { +return !_PERCENT_1["empty"]; +}), selection["ranges"]); +}) +; +var selection_history_field = "Stores selection history" +; +var extension = (function () { +return selection_history_field; +}) +; +var stack = (function (state) { +return state.field(selection_history_field); +}) +; +var grow_1 = (function (state, start, end) { +let node1 = n.nearest_touching(state, end, -1); +return squint_core.first(squint_core.filter((function (p__2) { +let map__34 = p__2; +let a_start5 = squint_core.get(map__34, "from"); +let a_end6 = squint_core.get(map__34, "to"); +return ((a_start5 <= start) && (a_end6 >= end) && !((a_start5 == start) && (a_end6 == end))); +}), squint_core.cons(node1, squint_core.mapcat(juxt(n.inner_span, squint_core.identity), n.ancestors(node1))))); +}) +; +var selection_grow_STAR_ = (function (state) { +return u.update_ranges(state, ({ "annotations": event_annotation }), (function (p__7) { +let map__89 = p__7; +let range10 = map__89; +let from11 = squint_core.get(map__89, "from"); +let to12 = squint_core.get(map__89, "to"); +let empty13 = squint_core.get(map__89, "empty"); +if (empty13) { +return ({ "range": ((function () { + let G__1415 = n.nearest_touching(state, from11, -1); +if (squint_core.nil_QMARK_(G__1415)) { +return null;} else { +return n.balanced_range(state, G__1415);} +})() || range10) });} else { +return ({ "range": ((function () { + let G__1617 = grow_1(state, from11, to12); +if (squint_core.nil_QMARK_(G__1617)) { +return null;} else { +return n.range(G__1617);} +})() || range10) });} +})); +}) +; +var selection_return_STAR_ = (function (state) { +let temp__24970__auto__18 = squint_core.get(squint_core.second(stack(state)), "selection"); +if (temp__24970__auto__18) { +let selection19 = temp__24970__auto__18; +return state.update(({ "selection": selection19, "annotations": event_annotation }));} else { +return u.update_ranges(state, ({ "annotations": event_annotation }), (function (range) { +return ({ "cursor": range["from"] }); +}));} +}) +; +squint_core.prn("selection-history-loaded"); + +export { selection_grow_STAR_, extension, second_last, event_annotation, selection_history_field, selection_return_STAR_, grow_1, ser, something_selected_QMARK_, stack } diff --git a/src-squint/nextjournal/clojure_mode/extensions/selection_history.cljs b/src-squint/nextjournal/clojure_mode/extensions/selection_history.cljs new file mode 100644 index 00000000..9c86f877 --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/extensions/selection_history.cljs @@ -0,0 +1,95 @@ +(ns nextjournal.clojure-mode.extensions.selection-history + (:require ["@codemirror/state" :refer [StateField]] + ["../node.mjs" :as n] + #_[nextjournal.clojure-mode.node :as n] + ["../util.mjs" :as u] + #_[nextjournal.clojure-mode.util :as u :refer [from-to]] + ["../selections.mjs" :as sel] + #_[nextjournal.clojure-mode.selections :as sel] + )) + +(def event-annotation (u/user-event-annotation "selectionhistory")) + +(defn second-last [^js arr] + (when (> (.-length arr) 1) + (aget arr (dec (.-length arr))))) + +(defn ser [selection] + (-> (.toJSON ^js selection) + (js->clj :keywordize-keys true) + :ranges + (->> (map (juxt :anchor :head))))) + +(defn something-selected? [^js selection] + (-> selection .-ranges (->> (some #(not (.-empty ^js %)))))) + +(def selection-history-field + "Stores selection history" + (.define StateField + #js{:create (fn [^js state] (list {:selection (.-selection state)})) + :update + (fn [stack ^:js {:as tr {:keys [selection]} :state :keys [docChanged]}] + (let [previous-position + (first (keep-indexed (fn [i x] + (when (sel/eq? (:selection x) selection) + i)) stack))] + (cond + + ;; doc changed => clear log + docChanged (list {:selection selection + :event (u/get-user-event-annotation tr)}) + + ;; no selection => clear stack to current position + (not (something-selected? selection)) + (list {:selection selection + :event (u/get-user-event-annotation tr)}) + + ;; selection found in stack => move there + previous-position + (let [[f & more] (drop previous-position stack)] + (cons (assoc f :prev-event (:event (first stack))) more)) + + ;; transaction has selection => add to log + :else + (cons {:selection selection + :event (u/get-user-event-annotation tr)} + stack))))})) + +(defn extension [] selection-history-field) + +(defn stack [^js state] + (.field state selection-history-field)) + +(defn grow-1 [state start end] + (let [node (n/nearest-touching state end -1)] + (->> (n/ancestors node) + (mapcat (juxt n/inner-span identity)) ;; include inner-spans + (cons node) + (filter (fn [^:js {a-start :from a-end :to}] + (and (<= a-start start) + (>= a-end end) + (not (and (== a-start start) + (== a-end end)))))) + first))) + +(defn selection-grow* [^js state] + (u/update-ranges state + #js{:annotations event-annotation} + (fn [^:js {:as range :keys [from to empty]}] + (if empty + {:range (or (some->> (n/nearest-touching state from -1) + (n/balanced-range state)) + range)} + {:range (or (some->> (grow-1 state from to) + n/range) + range)})))) + +(defn selection-return* [^js state] + (if-let [selection (:selection (second (stack state)))] + (.update state #js{:selection selection + :annotations event-annotation}) + (u/update-ranges state + #js{:annotations event-annotation} + (fn [^js range] {:cursor (.-from range)})))) + +(prn :selection-history-loaded) diff --git a/src/nextjournal/clojure_mode.cljs b/src/nextjournal/clojure_mode.cljs index 621758a3..24eaf02c 100644 --- a/src/nextjournal/clojure_mode.cljs +++ b/src/nextjournal/clojure_mode.cljs @@ -5,8 +5,8 @@ [applied-science.js-interop :as j] [nextjournal.clojure-mode.extensions.close-brackets :as close-brackets] [nextjournal.clojure-mode.extensions.match-brackets :as match-brackets] - ;; TODO: [nextjournal.clojure-mode.extensions.formatting :as format] + ;; TODO: [nextjournal.clojure-mode.extensions.selection-history :as sel-history] [nextjournal.clojure-mode.keymap :as keymap] [nextjournal.clojure-mode.node :as n] From ca8cd0e1af95562dda61fa3d98a93d0db98268dc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 17:12:19 +0200 Subject: [PATCH 10/80] commands --- public/squint/js/main.mjs | 1 + .../nextjournal/clojure_mode/commands.mjs | 380 ++++++++++++++++++ .../nextjournal/clojure_mode/commands.cljs | 286 +++++++++++++ src/nextjournal/clojure_mode.cljs | 2 +- 4 files changed, 668 insertions(+), 1 deletion(-) create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/commands.mjs create mode 100644 src-squint/nextjournal/clojure_mode/commands.cljs diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index f81b95f8..568b675d 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -4,5 +4,6 @@ import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/formatting.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs'; +import './src-squint/nextjournal/clojure_mode/commands.mjs'; console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/commands.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/commands.mjs new file mode 100644 index 00000000..c2c4c410 --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/commands.mjs @@ -0,0 +1,380 @@ +import * as squint_core from 'squint-cljs/core.js'; +import * as commands from '@codemirror/commands'; +import * as u from './util.mjs'; +import * as sel from './selections.mjs'; +import * as n from './node.mjs'; +import * as format from './extensions/formatting.mjs'; +import * as sel_history from './extensions/selection_history.mjs'; +var view_command = (function (f) { +return function (p__1) { +let map__23 = p__1; +let state4 = squint_core.get(map__23, "state"); +let dispatch5 = squint_core.get(map__23, "dispatch"); +let G__67 = f(state4); +if (squint_core.nil_QMARK_(G__67)) { +null} else { +dispatch5(G__67)}; +return true; +}; +}) +; +var scoped_view_command = (function (f) { +return function (p__8) { +let map__910 = p__8; +let state11 = squint_core.get(map__910, "state"); +let dispatch12 = squint_core.get(map__910, "dispatch"); +if (n.within_program_QMARK_(state11)) { +let G__1314 = f(state11); +if (squint_core.nil_QMARK_(G__1314)) { +null} else { +dispatch12(G__1314)}; +return true;} else { +return false;} +}; +}) +; +var unwrap_STAR_ = (function (state) { +return u.update_ranges(state, (function (p__15) { +let map__1617 = p__15; +let range18 = map__1617; +let from19 = squint_core.get(map__1617, "from"); +let to20 = squint_core.get(map__1617, "to"); +let empty21 = squint_core.get(map__1617, "empty"); +if (empty21) { +let temp__25187__auto__22 = (function () { + let G__2324 = n.tree(state, from19, -1); +let G__2325 = (squint_core.nil_QMARK_(G__2324)) ? (null) : (n.closest(G__2324, n.coll_QMARK_)); +if (squint_core.nil_QMARK_(G__2325)) { +return null;} else { +return u.guard(G__2325, n.balanced_QMARK_);} +})(); +if (temp__25187__auto__22) { +let nearest_balanced_coll26 = temp__25187__auto__22; +return ({ "cursor": (from19 - 1), "changes": [n.from_to(n.down(nearest_balanced_coll26)), n.from_to(n.down_last(nearest_balanced_coll26))] });}} +})); +}) +; +var copy_to_clipboard_BANG_ = (function (text) { +let focus_el27 = squint_core.get(document, "activeElement"); +let input_el28 = document.createElement("textarea"); +input_el28.setAttribute("class", "clipboard-input"); +squint_core.assoc_BANG_(input_el28, "innerHTML", text); +document["body"].appendChild(input_el28); +input_el28.focus(({ "preventScroll": true })); +input_el28.select(); +document.execCommand("copy"); +focus_el27.focus(({ "preventScroll": true })); +return document["body"].removeChild(input_el28); +}) +; +var kill_STAR_ = (function (state) { +return u.update_ranges(state, (function (p__29) { +let map__3031 = p__29; +let range32 = map__3031; +let from33 = squint_core.get(map__3031, "from"); +let to34 = squint_core.get(map__3031, "to"); +let empty35 = squint_core.get(map__3031, "empty"); +if (empty35) { +let node36 = n.tree(state, from33); +let parent37 = n.closest(node36, (function (_PERCENT_1) { +return (n.coll_QMARK_(_PERCENT_1) || n.string_QMARK_(_PERCENT_1) || n.top_QMARK_(_PERCENT_1)); +})); +let line_end38 = state["doc"].lineAt(from33)["to"]; +let next_children39 = (parent37) ? (n.children(parent37, from33, 1)) : (null); +let last_child_on_line40 = (parent37) ? ((function () { + let G__4142 = next_children39; +let G__4143 = (squint_core.nil_QMARK_(G__4142)) ? (null) : (squint_core.take_while(every_pred((function (_PERCENT_1) { +return (n.start(_PERCENT_1) <= line_end38); +})), G__4142)); +if (squint_core.nil_QMARK_(G__4143)) { +return null;} else { +return squint_core.last(G__4143);} +})()) : (null); +let to44 = (n.string_QMARK_(parent37)) ? ((function () { + let content45 = squint_core.str(n.string(state, parent37)); +let content_from46 = subs(content45, (from33 - n.start(parent37))); +let next_newline47 = content_from46.indexOf("\n"); +if (squint_core.neg_QMARK_(next_newline47)) { +return (n.end(parent37) - 1);} else { +return (from33 + next_newline47 + 1);} +})()) : ((last_child_on_line40) ? ((n.end_edge_QMARK_(last_child_on_line40)) ? (n.start(last_child_on_line40)) : (n.end(last_child_on_line40))) : (((function () { + let G__4849 = squint_core.first(next_children39); +let G__4850 = (squint_core.nil_QMARK_(G__4849)) ? (null) : (n.start(G__4849)); +if (squint_core.nil_QMARK_(G__4850)) { +return null;} else { +return (G__4850 > line_end38);} +})()) ? (n.start(squint_core.first(next_children39))) : (null))); +if (u.node_js_QMARK_) { +null} else { +copy_to_clipboard_BANG_(n.string(state, from33, to44))}; +if (to44) { +return ({ "cursor": from33, "changes": ({ "from": from33, "to": to44 }) });}} else { +copy_to_clipboard_BANG_(n.string(state, from33, to34)); +return ({ "cursor": from33, "changes": u.from_to(from33, to34) });} +})); +}) +; +var enter_and_indent_STAR_ = (function (state) { +let ctx51 = format.make_indent_context(state); +return u.update_ranges(state, (function (p__52) { +let map__5354 = p__52; +let range55 = map__5354; +let from56 = squint_core.get(map__5354, "from"); +let to57 = squint_core.get(map__5354, "to"); +let empty58 = squint_core.get(map__5354, "empty"); +let indent_at59 = (function () { + let G__6061 = n.closest(n.tree(state, from56), some_fn(n.coll_QMARK_, n.top_QMARK_)); +let G__6062 = (squint_core.nil_QMARK_(G__6061)) ? (null) : (n.inner_span(G__6061)); +if (squint_core.nil_QMARK_(G__6062)) { +return null;} else { +return n.start(G__6062);} +})(); +let indent63 = (indent_at59) ? (format.get_indentation(ctx51, indent_at59)) : (null); +let insertion64 = squint_core.str("\n", (indent63) ? (format.spaces(state, indent63)) : (null)); +return ({ "cursor": (from56 + squint_core.count(insertion64)), "changes": [({ "from": from56, "to": to57, "insert": insertion64 })] }); +})); +}) +; +var nav_position = (function (state, from, dir) { +return ((function () { + let G__6566 = n.closest(n.tree(state, from), (function (_PERCENT_1) { +return (n.coll_QMARK_(_PERCENT_1) || n.string_QMARK_(_PERCENT_1) || n.top_QMARK_(_PERCENT_1)); +})); +let G__6567 = (squint_core.nil_QMARK_(G__6566)) ? (null) : (n.children(G__6566, from, dir)); +let G__6568 = (squint_core.nil_QMARK_(G__6567)) ? (null) : (squint_core.first(G__6567)); +if (squint_core.nil_QMARK_(G__6568)) { +return null;} else { +return j.get(G__6568, (function () { + let G__6970 = dir; +switch (G__6970) {case -1: +return "from"; +break; +case 1: +return "to"; +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__6970))} +})());} +})() || sel.constrain(state, (from + dir))); +}) +; +var nav = (function (dir) { +return function (state) { +return u.update_ranges(state, (function (p__72) { +let map__7374 = p__72; +let range75 = map__7374; +let from76 = squint_core.get(map__7374, "from"); +let to77 = squint_core.get(map__7374, "to"); +let empty78 = squint_core.get(map__7374, "empty"); +if (empty78) { +return ({ "cursor": nav_position(state, from76, dir) });} else { +return ({ "cursor": squint_core.get(u.from_to(from76, to77), (function () { + let G__7980 = dir; +switch (G__7980) {case -1: +return "from"; +break; +case 1: +return "to"; +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__7980))} +})()) });} +})); +}; +}) +; +var nav_select = (function (dir) { +return function (state) { +return u.update_ranges(state, (function (p__82) { +let map__8384 = p__82; +let range85 = map__8384; +let from86 = squint_core.get(map__8384, "from"); +let to87 = squint_core.get(map__8384, "to"); +let empty88 = squint_core.get(map__8384, "empty"); +if (empty88) { +return ({ "range": n.balanced_range(state, from86, nav_position(state, from86, dir)) });} else { +return ({ "range": (function () { + let map__8990 = u.from_to(from86, to87); +let from91 = squint_core.get(map__8990, "from"); +let to92 = squint_core.get(map__8990, "to"); +let G__9394 = dir; +switch (G__9394) {case 1: +return n.balanced_range(state, from91, nav_position(state, to92, dir)); +break; +case -1: +return n.balanced_range(state, nav_position(state, from91, dir), to92); +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__9394))} +})() });} +})); +}; +}) +; +var balance_ranges = (function (state) { +return u.update_ranges(state, (function (p__96) { +let map__9798 = p__96; +let from99 = squint_core.get(map__9798, "from"); +let to100 = squint_core.get(map__9798, "to"); +let empty101 = squint_core.get(map__9798, "empty"); +if (empty101) { +return null;} else { +return ({ "range": n.balanced_range(state, from99, to100) });} +})); +}) +; +var log = console.log +; +var slurp = (function (direction) { +return function (state) { +return u.update_ranges(state, (function (p__102) { +let map__103104 = p__102; +let range105 = map__103104; +let from106 = squint_core.get(map__103104, "from"); +let to107 = squint_core.get(map__103104, "to"); +let empty108 = squint_core.get(map__103104, "empty"); +if (empty108) { +let temp__25187__auto__109 = n.closest(n.tree(state, from106), every_pred(n.coll_QMARK_, (function (_PERCENT_1) { +return !(function () { + let G__110111 = direction; +switch (G__110111) {case 1: +let G__113114 = _PERCENT_1; +let G__113115 = (squint_core.nil_QMARK_(G__113114)) ? (null) : (n.with_prefix(G__113114)); +let G__113116 = (squint_core.nil_QMARK_(G__113115)) ? (null) : (n.right(G__113115)); +if (squint_core.nil_QMARK_(G__113116)) { +return null;} else { +return n.end_edge_QMARK_(G__113116);} +break; +case -1: +let G__117118 = _PERCENT_1; +let G__117119 = (squint_core.nil_QMARK_(G__117118)) ? (null) : (n.with_prefix(G__117118)); +let G__117120 = (squint_core.nil_QMARK_(G__117119)) ? (null) : (n.left(G__117119)); +if (squint_core.nil_QMARK_(G__117120)) { +return null;} else { +return n.start_edge_QMARK_(G__117120);} +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__110111))} +})(); +}))); +if (temp__25187__auto__109) { +let parent121 = temp__25187__auto__109; +let temp__25187__auto__122 = (function () { + let G__123124 = direction; +switch (G__123124) {case 1: +return squint_core.first(squint_core.remove(n.line_comment_QMARK_, n.rights(n.with_prefix(parent121)))); +break; +case -1: +return squint_core.first(squint_core.remove(n.line_comment_QMARK_, n.lefts(n.with_prefix(parent121)))); +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__123124))} +})(); +if (temp__25187__auto__122) { +let target126 = temp__25187__auto__122; +return ({ "cursor/mapped": from106, "changes": (function () { + let G__127128 = direction; +switch (G__127128) {case 1: +let edge130 = n.down_last(parent121); +return [({ "from": n.end(target126), "insert": n.name(edge130) }), j.assoc_BANG_(n.from_to(edge130), "insert", " ")]; +break; +case -1: +let edge131 = n.left_edge_with_prefix(state, parent121); +let start132 = n.start(n.with_prefix(parent121)); +return [({ "from": start132, "to": (start132 + squint_core.count(edge131)), "insert": " " }), ({ "from": n.start(target126), "insert": edge131 })]; +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__127128))} +})() });}}} +})); +}; +}) +; +var barf = (function (direction) { +return function (state) { +return u.update_ranges(state, (function (p__133) { +let map__134135 = p__133; +let range136 = map__134135; +let from137 = squint_core.get(map__134135, "from"); +let to138 = squint_core.get(map__134135, "to"); +let empty139 = squint_core.get(map__134135, "empty"); +if (empty139) { +let temp__25187__auto__140 = n.closest(n.tree(state, from137), n.coll_QMARK_); +if (temp__25187__auto__140) { +let parent141 = temp__25187__auto__140; +let G__142143 = direction; +switch (G__142143) {case 1: +let temp__25187__auto__145 = (function () { + let G__146147 = n.down_last(parent141); +let G__146148 = (squint_core.nil_QMARK_(G__146147)) ? (null) : (n.lefts(G__146147)); +let G__146149 = (squint_core.nil_QMARK_(G__146148)) ? (null) : (squint_core.remove(n.line_comment_QMARK_, G__146148)); +let G__146150 = (squint_core.nil_QMARK_(G__146149)) ? (null) : (squint_core.drop(1, G__146149)); +if (squint_core.nil_QMARK_(G__146150)) { +return null;} else { +return squint_core.first(G__146150);} +})(); +if (temp__25187__auto__145) { +let target151 = temp__25187__auto__145; +return ({ "cursor": min(n.end(target151), from137), "changes": [({ "from": n.end(target151), "insert": n.name(n.down_last(parent141)) }), j.assoc_BANG_(n.from_to(n.down_last(parent141)), "insert", " ")] });} +break; +case -1: +let temp__25187__auto__152 = (function () { + let G__153154 = n.down(parent141); +let G__153155 = (squint_core.nil_QMARK_(G__153154)) ? (null) : (n.rights(G__153154)); +let G__153156 = (squint_core.nil_QMARK_(G__153155)) ? (null) : (squint_core.remove(n.line_comment_QMARK_, G__153155)); +let G__153157 = (squint_core.nil_QMARK_(G__153156)) ? (null) : (squint_core.drop(1, G__153156)); +if (squint_core.nil_QMARK_(G__153157)) { +return null;} else { +return squint_core.first(G__153157);} +})(); +if (temp__25187__auto__152) { +let next_first_child158 = temp__25187__auto__152; +let left_edge159 = n.left_edge_with_prefix(state, parent141); +let left_start160 = n.start(n.with_prefix(parent141)); +return ({ "cursor": max(from137, (n.start(next_first_child158) + (squint_core.count(left_edge159) + 1))), "changes": [({ "from": n.start(next_first_child158), "insert": squint_core.str(" ", left_edge159) }), ({ "from": left_start160, "to": (left_start160 + squint_core.count(left_edge159)), "insert": format.spaces(state, squint_core.count(left_edge159)) })] });} +break; +default: +throw new Error(squint_core.str("No matching clause: ", G__142143))}}} +})); +}; +}) +; +var builtin_index = "Subset of builtin commands that compliment paredit" +; +var indent = view_command(format.format) +; +var unwrap = view_command(unwrap_STAR_) +; +var kill = scoped_view_command(kill_STAR_) +; +var nav_right = view_command(nav(1)) +; +var nav_left = view_command(nav(-1)) +; +var nav_select_right = view_command(nav_select(1)) +; +var nav_select_left = view_command(nav_select(-1)) +; +var slurp_forward = view_command(slurp(1)) +; +var slurp_backward = view_command(slurp(-1)) +; +var barf_forward = view_command(barf(1)) +; +var barf_backward = view_command(barf(-1)) +; +var selection_grow = view_command(sel_history.selection_grow_STAR_) +; +var selection_return = view_command(sel_history.selection_return_STAR_) +; +var enter_and_indent = view_command(enter_and_indent_STAR_) +; +var paredit_index = ({ "indent": indent, "nav-left": nav_left, "enter-and-indent": enter_and_indent, "selection-grow": selection_grow, "kill": kill, "slurp-forward": slurp_forward, "nav-select-right": nav_select_right, "nav-select-left": nav_select_left, "barf-forward": barf_forward, "barf-backward": barf_backward, "nav-right": nav_right, "slurp-backward": slurp_backward, "unwrap": unwrap, "selection-return": selection_return }) +; +var index = "Mapping of keyword-id to command functions" +; +var reverse_index = "Lookup keyword-id by function" +; +squint_core.prn("commands-loaded"); + +export { nav_select_left, index, view_command, barf_backward, scoped_view_command, kill_STAR_, enter_and_indent_STAR_, unwrap, enter_and_indent, log, nav_select, slurp, nav_position, indent, nav_select_right, slurp_forward, selection_grow, nav, balance_ranges, nav_left, copy_to_clipboard_BANG_, barf, builtin_index, barf_forward, paredit_index, kill, reverse_index, unwrap_STAR_, nav_right, slurp_backward, selection_return } diff --git a/src-squint/nextjournal/clojure_mode/commands.cljs b/src-squint/nextjournal/clojure_mode/commands.cljs new file mode 100644 index 00000000..855a7dfb --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/commands.cljs @@ -0,0 +1,286 @@ +(ns nextjournal.clojure-mode.commands + (:require ["@codemirror/commands" :as commands] + ["./util.mjs" :as u] + ["./selections.mjs" :as sel] + ["./node.mjs" :as n] + ["./extensions/formatting.mjs" :as format] + ["./extensions/selection_history.mjs" :as sel-history])) + + +(defn view-command [f] + (fn [^:js {:keys [^js state dispatch]}] + (some-> (f state) (dispatch)) + true)) + +;; some commands won't make sense when clojure is embedded into other languages +;; in which case we want default commands/envent-handling applied +(defn scoped-view-command [f] + (fn [^:js {:keys [^js state dispatch]}] + (if (n/within-program? state) + (do (some-> (f state) (dispatch)) + true) + false))) + +(defn unwrap* [state] + (u/update-ranges state + (fn [^:js {:as range :keys [from to empty]}] + (when empty + (when-let [nearest-balanced-coll + (some-> (n/tree state from -1) + (n/closest n/coll?) + (u/guard n/balanced?))] + {:cursor (dec from) + :changes [(n/from-to (n/down nearest-balanced-coll)) + (n/from-to (n/down-last nearest-balanced-coll))]}))))) + +(defn copy-to-clipboard! [text] + (let [^js focus-el (get js/document :activeElement) + input-el (js/document.createElement "textarea")] + (.setAttribute input-el "class" "clipboard-input") + #_:clj-kondo/ignore (assoc! input-el :innerHTML text) + (-> js/document .-body (.appendChild input-el)) + (.focus input-el #js {:preventScroll true}) + (.select input-el) + (js/document.execCommand "copy") + (.focus focus-el #js {:preventScroll true}) + (-> js/document .-body (.removeChild input-el)))) + +(defn kill* [^js state] + (u/update-ranges state + (fn [^:js {:as range :keys [from to empty]}] + (if empty + (let [node (n/tree state from) + parent (n/closest node #(or (n/coll? %) + (n/string? %) + (n/top? %))) + line-end (.-to (.lineAt (.-doc state) from)) + next-children (when parent (n/children parent from 1)) + last-child-on-line + (when parent (some->> next-children + (take-while (every-pred + #(<= (n/start %) line-end))) + last)) + to (cond (n/string? parent) (let [content (str (n/string state parent)) + content-from (subs content (- from (n/start parent))) + next-newline (.indexOf content-from \newline)] + (if (neg? next-newline) + (dec (n/end parent)) + (+ from next-newline 1))) + last-child-on-line (if (n/end-edge? last-child-on-line) + (n/start last-child-on-line) + (n/end last-child-on-line)) + (some-> (first next-children) + n/start + (> line-end)) (-> (first next-children) n/start))] + (when-not u/node-js? + (copy-to-clipboard! (n/string state from to))) + (when to + {:cursor from + :changes {:from from + :to to}})) + (do + (copy-to-clipboard! (n/string state from to)) + {:cursor from + :changes (u/from-to from to)}))))) + +(defn enter-and-indent* [^js state] + (let [ctx (format/make-indent-context state)] + (u/update-ranges state + (fn [^:js {:as range :keys [from to empty]}] + (let [indent-at (some-> (n/closest (n/tree state from) (some-fn n/coll? n/top?)) + n/inner-span + n/start) + indent (when indent-at (format/get-indentation ctx indent-at)) + insertion (str \newline (when indent (format/spaces state indent)))] + {:cursor (+ from (count insertion)) + :changes [{:from from + :to to + :insert insertion}]}))))) + +(defn nav-position [state from dir] + (or (some-> (n/closest (n/tree state from) + #(or (n/coll? %) + (n/string? %) + (n/top? %))) + (n/children from dir) + first + (j/get (case dir -1 :from 1 :to))) + (sel/constrain state (+ from dir)))) + +(defn nav [dir] + (fn [state] + (u/update-ranges state + (fn [^:js {:as range :keys [from to empty]}] + (if empty + {:cursor (nav-position state from dir)} + {:cursor (get (u/from-to from to) (case dir -1 :from 1 :to))}))))) + +(defn nav-select [dir] + (fn [^js state] + (u/update-ranges state + (fn [^:js {:as range :keys [from to empty]}] + (if empty + {:range (n/balanced-range state from (nav-position state from dir))} + {:range (let [^:js {:keys [from to]} (u/from-to from to)] + (case dir + 1 (n/balanced-range state from (nav-position state to dir)) + -1 (n/balanced-range state (nav-position state from dir) to)))}))))) + +(defn balance-ranges [^js state] + (u/update-ranges state + (fn [^:js {:keys [from to empty]}] + (when-not empty + {:range (n/balanced-range state from to)})))) + +(def log js/console.log) + +(defn slurp [direction] + (fn [^js state] + (u/update-ranges state + (fn [^:js {:as range :keys [from to empty]}] + (when empty + (when-let [parent (n/closest (n/tree state from) + (every-pred n/coll? + #(not + (case direction + 1 (some-> % n/with-prefix n/right n/end-edge?) + -1 (some-> % n/with-prefix n/left n/start-edge?)))))] + (when-let [target (case direction 1 (first (remove n/line-comment? (n/rights (n/with-prefix parent)))) + -1 (first (remove n/line-comment? (n/lefts (n/with-prefix parent)))))] + {:cursor/mapped from + :changes (case direction + 1 + (let [edge (n/down-last parent)] + [{:from (-> target n/end) + :insert (n/name edge)} + (-> edge + n/from-to + (j/assoc! :insert " "))]) + -1 + (let [^string edge (n/left-edge-with-prefix state parent) + start (n/start (n/with-prefix parent))] + [{:from start + :to (+ start (count edge)) + :insert " "} + {:from (n/start target) + :insert edge}]))}))))))) + +(defn barf [direction] + (fn [^js state] + (->> (fn [^:js {:as range :keys [from to empty]}] + (when empty + (when-let [parent (-> (n/tree state from) + (n/closest n/coll?))] + (case direction + 1 + (when-let [target (some->> (n/down-last parent) + n/lefts + (remove n/line-comment?) + (drop 1) + first)] + + {:cursor (min (n/end target) from) + :changes [{:from (n/end target) + :insert (n/name (n/down-last parent))} + (-> (n/down-last parent) + n/from-to + (j/assoc! :insert " "))]}) + -1 + (when-let [next-first-child (some->> (n/down parent) + n/rights + (remove n/line-comment?) + (drop 1) + first)] + (let [left-edge (n/left-edge-with-prefix state parent) + left-start (n/start (n/with-prefix parent))] + {:cursor (max from (+ (n/start next-first-child) (inc (count left-edge)))) + :changes [ + ;; insert left edge (prefixed by a space) in front of next-first-child + {:from (n/start next-first-child) + :insert (str " " left-edge)} + ;; replace left-edge with spaces + {:from left-start + :to (+ left-start (count left-edge)) + :insert (format/spaces state (count left-edge))}]})))))) + (u/update-ranges state)))) + +(def builtin-index + "Subset of builtin commands that compliment paredit" + {:cursorLineStart commands/cursorLineStart + :selectLineStart commands/selectLineStart + :cursorLineDown commands/cursorLineDown + :selectLineDown commands/selectLineDown + :selectAll commands/selectAll + :cursorLineBoundaryForward commands/cursorLineBoundaryForward + :selectLineBoundaryForward commands/selectLineBoundaryForward + :deleteCharBackward commands/deleteCharBackward + :insertNewlineAndIndent commands/insertNewlineAndIndent + :cursorLineBoundaryBackward commands/cursorLineBoundaryBackward + :selectLineBoundaryBackward commands/selectLineBoundaryBackward + :deleteCharForward commands/deleteCharForward + :cursorCharLeft commands/cursorCharLeft + :selectCharLeft commands/selectCharLeft + :cursorCharRight commands/cursorCharRight + :selectCharRight commands/selectCharRight + :cursorGroupForward commands/cursorGroupForward + :selectGroupForward commands/selectGroupForward + :cursorGroupBackward commands/cursorGroupBackward + :selectGroupBackward commands/selectGroupBackward + :cursorDocEnd commands/cursorDocEnd + :selectDocEnd commands/selectDocEnd + :deleteGroupBackward commands/deleteGroupBackward + :deleteGroupForward commands/deleteGroupForward + :cursorPageDown commands/cursorPageDown + :selectPageDown commands/selectPageDown + :cursorPageUp commands/cursorPageUp + :selectPageUp commands/selectPageUp + :cursorLineEnd commands/cursorLineEnd + :selectLineEnd commands/selectLineEnd + :splitLine commands/splitLine + :transposeChars commands/transposeChars + :cursorLineUp commands/cursorLineUp + :selectLineUp commands/selectLineUp + :cursorDocStart commands/cursorDocStart + :selectDocStart commands/selectDocStart}) + +(def indent (view-command format/format)) +(def unwrap (view-command unwrap*)) +(def kill (scoped-view-command kill*)) +(def nav-right (view-command (nav 1))) +(def nav-left (view-command (nav -1))) +(def nav-select-right (view-command (nav-select 1))) +(def nav-select-left (view-command (nav-select -1))) +(def slurp-forward (view-command (slurp 1))) +(def slurp-backward (view-command (slurp -1))) +(def barf-forward (view-command (barf 1))) +(def barf-backward (view-command (barf -1))) +(def selection-grow (view-command sel-history/selection-grow*)) +(def selection-return (view-command sel-history/selection-return*)) +(def enter-and-indent (view-command enter-and-indent*)) + +(def paredit-index + {:indent indent + :unwrap unwrap + :kill kill + :nav-right nav-right + :nav-left nav-left + :nav-select-right nav-select-right + :nav-select-left nav-select-left + :slurp-forward slurp-forward + :slurp-backward slurp-backward + :barf-forward barf-forward + :barf-backward barf-backward + :selection-grow selection-grow + :selection-return selection-return + :enter-and-indent enter-and-indent}) + +(def index + "Mapping of keyword-id to command functions" + (merge builtin-index + paredit-index)) + +(def reverse-index + "Lookup keyword-id by function" + (reduce-kv #(assoc %1 %3 %2) {} index)) + +(prn :commands-loaded) diff --git a/src/nextjournal/clojure_mode.cljs b/src/nextjournal/clojure_mode.cljs index 24eaf02c..b38cdbb8 100644 --- a/src/nextjournal/clojure_mode.cljs +++ b/src/nextjournal/clojure_mode.cljs @@ -6,8 +6,8 @@ [nextjournal.clojure-mode.extensions.close-brackets :as close-brackets] [nextjournal.clojure-mode.extensions.match-brackets :as match-brackets] [nextjournal.clojure-mode.extensions.formatting :as format] - ;; TODO: [nextjournal.clojure-mode.extensions.selection-history :as sel-history] + ;; TODO: [nextjournal.clojure-mode.keymap :as keymap] [nextjournal.clojure-mode.node :as n] [nextjournal.clojure-mode.test-utils :as test-utils])) From c6966d78305d53c1d8ed575a18a3185484f45b1f Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 17:34:19 +0200 Subject: [PATCH 11/80] wip --- package.json | 4 +- public/squint/js/main.mjs | 1 + .../nextjournal/clojure_mode/keymap.mjs | 48 ++++++ .../nextjournal/clojure_mode/keymap.cljs | 152 ++++++++++++++++++ yarn.lock | 8 +- 5 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/keymap.mjs create mode 100644 src-squint/nextjournal/clojure_mode/keymap.cljs diff --git a/package.json b/package.json index 3cf8f4ba..f46ea3f2 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "punycode": "2.1.1", "react": "^17.0.2", "react-dom": "^17.0.2", - "squint-cljs": "^0.1.17", "w3c-keyname": "^2.2.4" }, "scripts": { @@ -37,6 +36,7 @@ }, "devDependencies": { "shadow-cljs": "2.19.5", - "vite": "^4.4.9" + "vite": "^4.4.9", + "squint-cljs": "^0.1.18" } } diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 568b675d..0a3d5965 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -5,5 +5,6 @@ import './src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/formatting.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs'; import './src-squint/nextjournal/clojure_mode/commands.mjs'; +import './src-squint/nextjournal/clojure_mode/keymap.mjs'; console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/keymap.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/keymap.mjs new file mode 100644 index 00000000..6f75297f --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/keymap.mjs @@ -0,0 +1,48 @@ +import * as squint_core from 'squint-cljs/core.js'; +import * as commands from '@codemirror/commands'; +import * as cmd from './commands'; +var update_some = (function (m, updates) { +return squint_core.reduce_kv((function (m, k, f) { +let temp__25216__auto__1 = squint_core.get(m, k); +if (squint_core.nil_QMARK_(temp__25216__auto__1)) { +return squint_core.dissoc(m, k);} else { +let existing2 = temp__25216__auto__1; +return squint_core.assoc(m, k, f(existing2));} +}), m, updates); +}) +; +var serialize = (function (command) { +return update_some(command, ({ "run": cmd.reverse_index, "shift": cmd.reverse_index })); +}) +; +var deserialize = (function (command) { +return update_some(command, ({ "run": cmd.index, "shift": cmd.index })); +}) +; +var group = (function (commands) { +return squint_core.reduce((function (out, p__3) { +let map__45 = p__3; +let cmd6 = map__45; +let run7 = squint_core.get(map__45, "run"); +return squint_core.update(out, run7, squint_core.fnil(squint_core.conj, []), squint_core.dissoc(cmd6, "run")); +}), ({ }), squint_core.map(serialize, commands)); +}) +; +var ungroup = (function (commands) { +return squint_core.reduce_kv((function (out, k, bindings) { +return squint_core.into(out, squint_core.map((function (_PERCENT_1) { +return deserialize(squint_core.assoc(_PERCENT_1, "run", k)); +}), bindings)); +}), [], commands); +}) +; +null; +var builtin_keymap_STAR_ = ({ "cursorLineDown": [({ "key": "ArrowDown", "shift": "selectLineDown" }), ({ "mac": "Ctrl-n", "shift": "selectLineDown" })], "selectAll": [({ "key": "Mod-a" })], "cursorLineBoundaryForward": [({ "key": "End", "shift": "selectLineBoundaryForward" })], "deleteCharBackward": [({ "key": "Backspace" }), ({ "mac": "Ctrl-h" })], "cursorLineBoundaryBackward": [({ "key": "Home", "shift": "selectLineBoundaryBackward", "mac": "Ctrl-a" }), ({ "mac": "Cmd-ArrowLeft", "shift": "selectLineBoundaryBackward" })], "deleteCharForward": [({ "key": "Delete" }), ({ "mac": "Ctrl-d" })], "cursorCharLeft": [({ "key": "ArrowLeft", "shift": "selectCharLeft" }), ({ "mac": "Ctrl-b", "shift": "selectCharLeft" })], "cursorGroupBackward": [({ "mac": "Alt-b", "shift": "selectGroupBackward" })], "cursorDocEnd": [({ "mac": "Cmd-ArrowDown", "shift": "selectDocEnd" }), ({ "key": "Mod-End", "shift": "selectDocEnd" }), ({ "mac": "Alt->" })], "deleteGroupBackward": [({ "key": "Mod-Backspace", "mac": "Alt-Backspace" }), ({ "mac": "Ctrl-Alt-h" })], "deleteGroupForward": [({ "key": "Mod-Delete", "mac": "Ctrl-Alt-Backspace" }), ({ "mac": "Alt-Delete" }), ({ "mac": "Alt-d" })], "cursorPageDown": [({ "mac": "Ctrl-ArrowDown", "shift": "selectPageDown" }), ({ "key": "PageDown", "shift": "selectPageDown" }), ({ "mac": "Ctrl-v" })], "cursorPageUp": [({ "mac": "Ctrl-ArrowUp", "shift": "selectPageUp" }), ({ "key": "PageUp", "shift": "selectPageUp" }), ({ "mac": "Alt-v" })], "cursorLineEnd": [({ "mac": "Cmd-ArrowRight" }), ({ "mac": "Ctrl-e", "shift": "selectLineEnd" })], "cursorGroupForward": [({ "mac": "Alt-f", "shift": "selectGroupForward" })], "undoSelection": [({ "key": "Mod-u", "preventDefault": true })], "cursorCharRight": [({ "key": "ArrowRight", "shift": "selectCharRight" }), ({ "mac": "Ctrl-f", "shift": "selectCharRight" })], "splitLine": [({ "mac": "Ctrl-o" })], "transposeChars": [({ "mac": "Ctrl-t" })], "cursorLineUp": [({ "key": "ArrowUp", "shift": "selectLineUp" }), ({ "mac": "Ctrl-p", "shift": "selectLineUp" })], "cursorDocStart": [({ "mac": "Cmd-ArrowUp", "shift": "selectDocStart" }), ({ "key": "Mod-Home", "shift": "selectDocStart" }), ({ "mac": "Alt-<" })] }) +; +var paredit_keymap_STAR_ = ({ "indent": [({ "key": "Tab", "doc": "Indent document (or selection)" })], "nav-left": [({ "key": "Alt-ArrowLeft", "shift": "nav-select-left", "doc": "Move cursor one unit to the left (shift: selects this region)", "preventDefault": true })], "enter-and-indent": [({ "key": "Enter", "doc": "Insert newline and indent" })], "selection-grow": [({ "doc": "Grow selections", "key": "Alt-ArrowUp" }), ({ "key": "Mod-1" })], "kill": [({ "key": "Ctrl-k", "doc": "Remove all forms from cursor to end of line" })], "slurp-forward": [({ "key": "Ctrl-ArrowRight", "doc": "Expand collection to include form to the right", "preventDefault": true }), ({ "key": "Mod-Shift-k", "preventDefault": true })], "barf-forward": [({ "key": "Ctrl-ArrowLeft", "doc": "Shrink collection forwards by one form", "preventDefault": true }), ({ "key": "Mod-Shift-j", "preventDefault": true })], "barf-backward": [({ "doc": "Shrink collection backwards by one form", "key": "Ctrl-Alt-ArrowRight" })], "nav-right": [({ "key": "Alt-ArrowRight", "shift": "nav-select-right", "doc": "Move cursor one unit to the right (shift: selects this region)", "preventDefault": true })], "slurp-backward": [({ "doc": "Grow collection backwards by one form", "key": "Ctrl-Alt-ArrowLeft", "preventDefault": true })], "unwrap": [({ "key": "Alt-s", "doc": "Lift contents of collection into parent", "preventDefault": true })], "selection-return": [({ "doc": "Shrink selections", "key": "Alt-ArrowDown" }), ({ "key": "Mod-2" })] }) +; +var builtin = ungroup(builtin_keymap_STAR_) +; +null; + +export { update_some, serialize, deserialize, group, ungroup, builtin_keymap_STAR_, paredit_keymap_STAR_, builtin } diff --git a/src-squint/nextjournal/clojure_mode/keymap.cljs b/src-squint/nextjournal/clojure_mode/keymap.cljs new file mode 100644 index 00000000..e03fcb15 --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/keymap.cljs @@ -0,0 +1,152 @@ +(ns nextjournal.clojure-mode.keymap + (:require ["@codemirror/commands" :as commands] + ["./commands" :as cmd])) + +(defn update-some + "Updates keys of map when key has value" + [m updates] + (reduce-kv (fn [m k f] + (if-some [existing (get m k)] + (assoc m k (f existing)) + (dissoc m k))) m updates)) + +;; (de)serializing commands from keyword-id to function +(defn serialize [command] (update-some command {:run cmd/reverse-index :shift cmd/reverse-index})) +(defn deserialize [command] (update-some command {:run cmd/index :shift cmd/index})) + + +(defn group + "Returns a grouped map of bindings for a list of CodeMirror keymap entries" + [commands] + (->> commands + (map serialize) + (reduce (fn [out {:as cmd :keys [run]}] + (update out run (fnil conj []) (dissoc cmd :run))) {}))) + +(defn ungroup + "Returns a list of CodeMirror keymap entries for a grouped map of bindings" + [commands] + (->> commands + (reduce-kv + (fn [out k bindings] + (into out (map #(deserialize (assoc % :run k)) bindings))) []))) + +(comment + (->> [commands/standardKeymap #_historyKeymap] + (mapcat #(js->clj % :keywordize-keys true)) + group + cljs.pprint/pprint)) + +(def builtin-keymap* + {:cursorLineDown + [{:key "ArrowDown", :shift :selectLineDown} + {:mac "Ctrl-n", :shift :selectLineDown}], + :selectAll [{:key "Mod-a"}], + :cursorLineBoundaryForward + [{:key "End", :shift :selectLineBoundaryForward}], + :deleteCharBackward [{:key "Backspace"} {:mac "Ctrl-h"}], + :cursorLineBoundaryBackward + [{:key "Home", :shift :selectLineBoundaryBackward + :mac "Ctrl-a"} + {:mac "Cmd-ArrowLeft" :shift :selectLineBoundaryBackward}], + :deleteCharForward [{:key "Delete"} {:mac "Ctrl-d"}], + :cursorCharLeft + [{:key "ArrowLeft", :shift :selectCharLeft} + {:mac "Ctrl-b", :shift :selectCharLeft}], + :cursorGroupBackward [{:mac "Alt-b", :shift :selectGroupBackward}], + :cursorDocEnd + [{:mac "Cmd-ArrowDown", :shift :selectDocEnd} + {:key "Mod-End", :shift :selectDocEnd} + {:mac "Alt->"}], + :deleteGroupBackward + [{:key "Mod-Backspace", :mac "Alt-Backspace"} + {:mac "Ctrl-Alt-h"}], + :deleteGroupForward + [{:key "Mod-Delete", :mac "Ctrl-Alt-Backspace"} + {:mac "Alt-Delete"} + {:mac "Alt-d"}], + :cursorPageDown + [{:mac "Ctrl-ArrowDown", :shift :selectPageDown} + {:key "PageDown", :shift :selectPageDown} + {:mac "Ctrl-v"}], + :cursorPageUp + [{:mac "Ctrl-ArrowUp", :shift :selectPageUp} + {:key "PageUp", :shift :selectPageUp} + {:mac "Alt-v"}], + :cursorLineEnd + [{:mac "Cmd-ArrowRight"} + {:mac "Ctrl-e", :shift :selectLineEnd}], + :cursorGroupForward [{:mac "Alt-f", :shift :selectGroupForward}], + :undoSelection [{:key "Mod-u", :preventDefault true}], + :cursorCharRight + [{:key "ArrowRight", :shift :selectCharRight} + {:mac "Ctrl-f", :shift :selectCharRight}], + :splitLine [{:mac "Ctrl-o"}], + :transposeChars [{:mac "Ctrl-t"}], + :cursorLineUp + [{:key "ArrowUp", :shift :selectLineUp} + {:mac "Ctrl-p", :shift :selectLineUp}], + :cursorDocStart + [{:mac "Cmd-ArrowUp", :shift :selectDocStart} + {:key "Mod-Home", :shift :selectDocStart} + {:mac "Alt-<"}]}) + +(def paredit-keymap* + {:indent + [{:key "Tab" + :doc "Indent document (or selection)"}] + :enter-and-indent + [{:key "Enter" + :doc "Insert newline and indent"}] + :unwrap + [{:key "Alt-s" + :doc "Lift contents of collection into parent" + :preventDefault true}] + :kill + [{:key "Ctrl-k" + :doc "Remove all forms from cursor to end of line"}] + :nav-left + [{:key "Alt-ArrowLeft" + :shift :nav-select-left + :doc "Move cursor one unit to the left (shift: selects this region)" + :preventDefault true}] + :nav-right + [{:key "Alt-ArrowRight" + :shift :nav-select-right + :doc "Move cursor one unit to the right (shift: selects this region)" + :preventDefault true}] + + :slurp-forward + [{:key "Ctrl-ArrowRight" + :doc "Expand collection to include form to the right" + :preventDefault true} + {:key "Mod-Shift-k" :preventDefault true}] + :slurp-backward + [{:doc "Grow collection backwards by one form" + :key "Ctrl-Alt-ArrowLeft" + :preventDefault true}] + + :barf-forward + [{:key "Ctrl-ArrowLeft" + :doc "Shrink collection forwards by one form" + :preventDefault true} + {:key "Mod-Shift-j" :preventDefault true}] + :barf-backward + [{:doc "Shrink collection backwards by one form" + :key "Ctrl-Alt-ArrowRight"}] + + :selection-grow + [{:doc "Grow selections" + :key "Alt-ArrowUp"} + {:key "Mod-1"}] + :selection-return + [{:doc "Shrink selections" + :key "Alt-ArrowDown"} + {:key "Mod-2"}]}) + +(def builtin (ungroup builtin-keymap*)) +#_#_(def paredit (ungroup paredit-keymap*)) +(def complete (.concat paredit builtin)) + +(comment + (ungroup default-keymap)) diff --git a/yarn.lock b/yarn.lock index 8804c8e8..39275f80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1072,10 +1072,10 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -squint-cljs@^0.1.17: - version "0.1.17" - resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.1.17.tgz#a23350582a44e18a7a5134bf6f97c0eb1f8585d6" - integrity sha512-U7+sWK+NuzDiS32f26OLzMj4aITsJyFP3X8BRhaSRMabf12p0dt0X7j5FFSI6Hv81hnRNTkVyGBejidP/MRcTA== +squint-cljs@^0.1.18: + version "0.1.18" + resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.1.18.tgz#0be3a2fe824d12c76949ce31363331cb98507d70" + integrity sha512-nhwxpGbPTi7XrvVe5b5m4o4cd7uB+bV5pDCixjX5NNnNMrMBpuedv735MgV8XiSr3GwwQMpQiOwW5Op6BR7+Qw== stream-browserify@^2.0.1: version "2.0.2" From 2f8f8ffd1a65dc9aaaf40a11b1e06a3b1fd7f644 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 5 Sep 2023 19:31:45 +0200 Subject: [PATCH 12/80] wip --- public/squint/js/main.mjs | 1 + .../src-squint/nextjournal/clojure_mode.mjs | 60 ++++++++++ .../nextjournal/clojure_mode/commands.mjs | 50 +++++---- .../nextjournal/clojure_mode/keymap.mjs | 9 +- src-squint/nextjournal/clojure_mode.cljs | 103 ++++++++++++++++++ .../nextjournal/clojure_mode/commands.cljs | 15 ++- .../nextjournal/clojure_mode/keymap.cljs | 8 +- src/nextjournal/clojure_mode.cljs | 4 +- 8 files changed, 214 insertions(+), 36 deletions(-) create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode.mjs create mode 100644 src-squint/nextjournal/clojure_mode.cljs diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 0a3d5965..9b482575 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -6,5 +6,6 @@ import './src-squint/nextjournal/clojure_mode/extensions/formatting.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs'; import './src-squint/nextjournal/clojure_mode/commands.mjs'; import './src-squint/nextjournal/clojure_mode/keymap.mjs'; +import './src-squint/nextjournal/clojure_mode.mjs'; console.log('hello'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode.mjs new file mode 100644 index 00000000..ca73c329 --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode.mjs @@ -0,0 +1,60 @@ +import * as squint_core from 'squint-cljs/core.js'; +import * as highlight from '@lezer/highlight'; +import { tags } from '@lezer/highlight'; +import * as language from '@codemirror/language'; +import { LRLanguage, LanguageSupport } from '@codemirror/language'; +import * as lezer_clj from '@nextjournal/lezer-clojure'; +import * as close_brackets from './clojure_mode/extensions/close_brackets.mjs'; +import * as match_brackets from './clojure_mode/extensions/match_brackets.mjs'; +import * as format from './clojure_mode/extensions/formatting.mjs'; +import * as sel_history from './clojure_mode/extensions/selection_history.mjs'; +import * as keymap from './clojure_mode/keymap.mjs'; +import * as n from './clojure_mode/node.mjs'; +var fold_node_props = (function () { + let coll_span1 = (function (tree) { +return ({ "from": (n.start(tree) + 1), "to": (n.end(tree) - 1) }); +}); +return ({ "Vector": coll_span1, "Map": coll_span1, "List": coll_span1 }); +})() +; +var style_tags = ({ "LineComment": tags["lineComment"], "NS": tags["keyword"], "\"\\\"\"": tags["string"], "VarName/Symbol": tags.definition(tags["variableName"]), "DocString/...": tags["emphasis"], "Boolean": tags["atom"], "Keyword": tags["atom"], "Number": tags["number"], "RegExp": tags["regexp"], "StringContent": tags["string"], "Operator/Symbol": tags["keyword"], "Discard!": tags["comment"], "DefLike": tags["keyword"], "Nil": tags["null"] }) +; +var parser = lezer_clj.parser +; +null; +var syntax = (function () { + let f2 = (function (var_args) { +let G__56 = arguments["length"]; +switch (G__56) {case 0: +return f2.cljs$core$IFn$_invoke$arity$0(); +break; +case 1: +return f2.cljs$core$IFn$_invoke$arity$1((arguments[0])); +break; +default: +throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} +}); +f2["cljs$core$IFn$_invoke$arity$0"] = (function () { +return syntax(parser); +}); +f2["cljs$core$IFn$_invoke$arity$1"] = (function (parser) { +return LRLanguage.define(({ "parser": parser.configure(({ "props": [format.props, language.foldNodeProp.add(fold_node_props), highlight.styleTags(style_tags)] })) })); +}); +f2["cljs$lang$maxFixedArity"] = 1; +return f2; +})() +; +var complete_keymap = keymap.complete +; +var builtin_keymap = keymap.builtin +; +var paredit_keymap = keymap.paredit +; +var default_extensions = [syntax(lezer_clj.parser), close_brackets.extension(), match_brackets.extension(), sel_history.extension(), format.ext_format_changed_lines()] +; +var language_support = "Eases embedding clojure mode into other languages (e.g. markdown).\n See https://codemirror.net/docs/ref/#language.LanguageSupport for motivations" +; +null; +squint_core.prn("clojure-mode-loaded"); + +export { paredit_keymap, parser, style_tags, complete_keymap, default_extensions, builtin_keymap, fold_node_props, syntax, language_support } diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/commands.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/commands.mjs index c2c4c410..927b5fd2 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/commands.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/commands.mjs @@ -41,15 +41,15 @@ let from19 = squint_core.get(map__1617, "from"); let to20 = squint_core.get(map__1617, "to"); let empty21 = squint_core.get(map__1617, "empty"); if (empty21) { -let temp__25187__auto__22 = (function () { +let temp__25269__auto__22 = (function () { let G__2324 = n.tree(state, from19, -1); let G__2325 = (squint_core.nil_QMARK_(G__2324)) ? (null) : (n.closest(G__2324, n.coll_QMARK_)); if (squint_core.nil_QMARK_(G__2325)) { return null;} else { return u.guard(G__2325, n.balanced_QMARK_);} })(); -if (temp__25187__auto__22) { -let nearest_balanced_coll26 = temp__25187__auto__22; +if (temp__25269__auto__22) { +let nearest_balanced_coll26 = temp__25269__auto__22; return ({ "cursor": (from19 - 1), "changes": [n.from_to(n.down(nearest_balanced_coll26)), n.from_to(n.down_last(nearest_balanced_coll26))] });}} })); }) @@ -144,7 +144,7 @@ let G__6567 = (squint_core.nil_QMARK_(G__6566)) ? (null) : (n.children(G__6566, let G__6568 = (squint_core.nil_QMARK_(G__6567)) ? (null) : (squint_core.first(G__6567)); if (squint_core.nil_QMARK_(G__6568)) { return null;} else { -return j.get(G__6568, (function () { +return squint_core.get(G__6568, (function () { let G__6970 = dir; switch (G__6970) {case -1: return "from"; @@ -234,7 +234,7 @@ let from106 = squint_core.get(map__103104, "from"); let to107 = squint_core.get(map__103104, "to"); let empty108 = squint_core.get(map__103104, "empty"); if (empty108) { -let temp__25187__auto__109 = n.closest(n.tree(state, from106), every_pred(n.coll_QMARK_, (function (_PERCENT_1) { +let temp__25269__auto__109 = n.closest(n.tree(state, from106), every_pred(n.coll_QMARK_, (function (_PERCENT_1) { return !(function () { let G__110111 = direction; switch (G__110111) {case 1: @@ -257,9 +257,9 @@ default: throw new Error(squint_core.str("No matching clause: ", G__110111))} })(); }))); -if (temp__25187__auto__109) { -let parent121 = temp__25187__auto__109; -let temp__25187__auto__122 = (function () { +if (temp__25269__auto__109) { +let parent121 = temp__25269__auto__109; +let temp__25269__auto__122 = (function () { let G__123124 = direction; switch (G__123124) {case 1: return squint_core.first(squint_core.remove(n.line_comment_QMARK_, n.rights(n.with_prefix(parent121)))); @@ -270,13 +270,13 @@ break; default: throw new Error(squint_core.str("No matching clause: ", G__123124))} })(); -if (temp__25187__auto__122) { -let target126 = temp__25187__auto__122; +if (temp__25269__auto__122) { +let target126 = temp__25269__auto__122; return ({ "cursor/mapped": from106, "changes": (function () { let G__127128 = direction; switch (G__127128) {case 1: let edge130 = n.down_last(parent121); -return [({ "from": n.end(target126), "insert": n.name(edge130) }), j.assoc_BANG_(n.from_to(edge130), "insert", " ")]; +return [({ "from": n.end(target126), "insert": n.name(edge130) }), squint_core.assoc_BANG_(n.from_to(edge130), "insert", " ")]; break; case -1: let edge131 = n.left_edge_with_prefix(state, parent121); @@ -299,12 +299,12 @@ let from137 = squint_core.get(map__134135, "from"); let to138 = squint_core.get(map__134135, "to"); let empty139 = squint_core.get(map__134135, "empty"); if (empty139) { -let temp__25187__auto__140 = n.closest(n.tree(state, from137), n.coll_QMARK_); -if (temp__25187__auto__140) { -let parent141 = temp__25187__auto__140; +let temp__25269__auto__140 = n.closest(n.tree(state, from137), n.coll_QMARK_); +if (temp__25269__auto__140) { +let parent141 = temp__25269__auto__140; let G__142143 = direction; switch (G__142143) {case 1: -let temp__25187__auto__145 = (function () { +let temp__25269__auto__145 = (function () { let G__146147 = n.down_last(parent141); let G__146148 = (squint_core.nil_QMARK_(G__146147)) ? (null) : (n.lefts(G__146147)); let G__146149 = (squint_core.nil_QMARK_(G__146148)) ? (null) : (squint_core.remove(n.line_comment_QMARK_, G__146148)); @@ -313,12 +313,12 @@ if (squint_core.nil_QMARK_(G__146150)) { return null;} else { return squint_core.first(G__146150);} })(); -if (temp__25187__auto__145) { -let target151 = temp__25187__auto__145; -return ({ "cursor": min(n.end(target151), from137), "changes": [({ "from": n.end(target151), "insert": n.name(n.down_last(parent141)) }), j.assoc_BANG_(n.from_to(n.down_last(parent141)), "insert", " ")] });} +if (temp__25269__auto__145) { +let target151 = temp__25269__auto__145; +return ({ "cursor": min(n.end(target151), from137), "changes": [({ "from": n.end(target151), "insert": n.name(n.down_last(parent141)) }), squint_core.assoc_BANG_(n.from_to(n.down_last(parent141)), "insert", " ")] });} break; case -1: -let temp__25187__auto__152 = (function () { +let temp__25269__auto__152 = (function () { let G__153154 = n.down(parent141); let G__153155 = (squint_core.nil_QMARK_(G__153154)) ? (null) : (n.rights(G__153154)); let G__153156 = (squint_core.nil_QMARK_(G__153155)) ? (null) : (squint_core.remove(n.line_comment_QMARK_, G__153155)); @@ -327,8 +327,8 @@ if (squint_core.nil_QMARK_(G__153157)) { return null;} else { return squint_core.first(G__153157);} })(); -if (temp__25187__auto__152) { -let next_first_child158 = temp__25187__auto__152; +if (temp__25269__auto__152) { +let next_first_child158 = temp__25269__auto__152; let left_edge159 = n.left_edge_with_prefix(state, parent141); let left_start160 = n.start(n.with_prefix(parent141)); return ({ "cursor": max(from137, (n.start(next_first_child158) + (squint_core.count(left_edge159) + 1))), "changes": [({ "from": n.start(next_first_child158), "insert": squint_core.str(" ", left_edge159) }), ({ "from": left_start160, "to": (left_start160 + squint_core.count(left_edge159)), "insert": format.spaces(state, squint_core.count(left_edge159)) })] });} @@ -339,7 +339,7 @@ throw new Error(squint_core.str("No matching clause: ", G__142143))}}} }; }) ; -var builtin_index = "Subset of builtin commands that compliment paredit" +var builtin_index = ({ "cursorLineStart": commands.cursorLineStart, "cursorLineDown": commands.cursorLineDown, "selectAll": commands.selectAll, "selectLineUp": commands.selectLineUp, "cursorLineBoundaryForward": commands.cursorLineBoundaryForward, "selectLineBoundaryBackward": commands.selectLineBoundaryBackward, "deleteCharBackward": commands.deleteCharBackward, "insertNewlineAndIndent": commands.insertNewlineAndIndent, "cursorLineBoundaryBackward": commands.cursorLineBoundaryBackward, "selectCharRight": commands.selectCharRight, "selectPageUp": commands.selectPageUp, "deleteCharForward": commands.deleteCharForward, "cursorCharLeft": commands.cursorCharLeft, "cursorGroupBackward": commands.cursorGroupBackward, "selectDocStart": commands.selectDocStart, "selectGroupBackward": commands.selectGroupBackward, "cursorDocEnd": commands.cursorDocEnd, "deleteGroupBackward": commands.deleteGroupBackward, "selectLineStart": commands.selectLineStart, "deleteGroupForward": commands.deleteGroupForward, "selectDocEnd": commands.selectDocEnd, "selectPageDown": commands.selectPageDown, "cursorPageDown": commands.cursorPageDown, "cursorPageUp": commands.cursorPageUp, "selectLineBoundaryForward": commands.selectLineBoundaryForward, "cursorLineEnd": commands.cursorLineEnd, "cursorGroupForward": commands.cursorGroupForward, "cursorCharRight": commands.cursorCharRight, "selectGroupForward": commands.selectGroupForward, "selectLineEnd": commands.selectLineEnd, "selectCharLeft": commands.selectCharLeft, "splitLine": commands.splitLine, "selectLineDown": commands.selectLineDown, "transposeChars": commands.transposeChars, "cursorLineUp": commands.cursorLineUp, "cursorDocStart": commands.cursorDocStart }) ; var indent = view_command(format.format) ; @@ -371,9 +371,11 @@ var enter_and_indent = view_command(enter_and_indent_STAR_) ; var paredit_index = ({ "indent": indent, "nav-left": nav_left, "enter-and-indent": enter_and_indent, "selection-grow": selection_grow, "kill": kill, "slurp-forward": slurp_forward, "nav-select-right": nav_select_right, "nav-select-left": nav_select_left, "barf-forward": barf_forward, "barf-backward": barf_backward, "nav-right": nav_right, "slurp-backward": slurp_backward, "unwrap": unwrap, "selection-return": selection_return }) ; -var index = "Mapping of keyword-id to command functions" +var index = squint_core.merge(builtin_index, paredit_index) ; -var reverse_index = "Lookup keyword-id by function" +var reverse_index = squint_core.reduce_kv((function (_PERCENT_1, _PERCENT_2, _PERCENT_3) { +return squint_core.assoc(_PERCENT_1, _PERCENT_3, _PERCENT_2); +}), ({ }), index) ; squint_core.prn("commands-loaded"); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/keymap.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/keymap.mjs index 6f75297f..3065bd54 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/keymap.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/keymap.mjs @@ -7,7 +7,7 @@ let temp__25216__auto__1 = squint_core.get(m, k); if (squint_core.nil_QMARK_(temp__25216__auto__1)) { return squint_core.dissoc(m, k);} else { let existing2 = temp__25216__auto__1; -return squint_core.assoc(m, k, f(existing2));} +return squint_core.assoc(m, k, ((f instanceof Function)) ? (f(existing2)) : (squint_core.get(f, existing2)));} }), m, updates); }) ; @@ -43,6 +43,11 @@ var paredit_keymap_STAR_ = ({ "indent": [({ "key": "Tab", "doc": "Indent documen ; var builtin = ungroup(builtin_keymap_STAR_) ; +var paredit = ungroup(paredit_keymap_STAR_) +; +var complete = paredit.concat(builtin) +; null; +squint_core.prn("keymap-loaded"); -export { update_some, serialize, deserialize, group, ungroup, builtin_keymap_STAR_, paredit_keymap_STAR_, builtin } +export { serialize, ungroup, group, complete, paredit_keymap_STAR_, update_some, paredit, builtin, builtin_keymap_STAR_, deserialize } diff --git a/src-squint/nextjournal/clojure_mode.cljs b/src-squint/nextjournal/clojure_mode.cljs new file mode 100644 index 00000000..2641b4e2 --- /dev/null +++ b/src-squint/nextjournal/clojure_mode.cljs @@ -0,0 +1,103 @@ +(ns nextjournal.clojure-mode + (:require ["@lezer/highlight" :as highlight :refer [tags]] + ["@codemirror/language" :as language :refer [LRLanguage LanguageSupport]] + ["@nextjournal/lezer-clojure" :as lezer-clj] + ["./clojure_mode/extensions/close_brackets.mjs" :as close-brackets] + ["./clojure_mode/extensions/match_brackets.mjs" :as match-brackets] + ["./clojure_mode/extensions/formatting.mjs" :as format] + ["./clojure_mode/extensions/selection_history.mjs" :as sel-history] + ["./clojure_mode/keymap.mjs" :as keymap] + ["./clojure_mode/node.mjs" :as n] + ;; TODO: + #_[nextjournal.clojure-mode.test-utils :as test-utils])) + +(def fold-node-props + (let [coll-span (fn [^js tree] #js{:from (inc (n/start tree)) + :to (dec (n/end tree))})] + {:Vector coll-span + :Map coll-span + :List coll-span})) + +(def style-tags + {:NS (.-keyword tags) + :DefLike (.-keyword tags) + "Operator/Symbol" (.-keyword tags) + "VarName/Symbol" (.definition tags (.-variableName tags)) + :Boolean (.-atom tags) + "DocString/..." (.-emphasis tags) + :Discard! (.-comment tags) + :Number (.-number tags) + :StringContent (.-string tags) + ;; need to pass something, that returns " when being parsed as JSON + ;; also #js doesn't treat this correctly, hence clj->js above + "\"\\\"\"" (.-string tags) + :Keyword (.-atom tags) + :Nil (.-null tags) + :LineComment (.-lineComment tags) + :RegExp (.-regexp tags)}) + +(def parser lezer-clj/parser) + +(comment + ;; to build a parser \""live" from a .grammar file, + ;; rather than using a precompiled parser: + (def parser + (lg/buildParser + (shadow.resource/inline "./clojure/clojure.grammar") + #js{:externalProp n/node-prop}))) + +(defn syntax + ([] (syntax parser)) + ([^js parser] + (.define LRLanguage + #js {:parser (.configure parser #js {:props #js [format/props + (.add language/foldNodeProp fold-node-props) + (highlight/styleTags style-tags)]})}))) + +(def ^js/Array complete-keymap keymap/complete) +(def ^js/Array builtin-keymap keymap/builtin) +(def ^js/Array paredit-keymap keymap/paredit) + +(def default-extensions + #js[(syntax lezer-clj/parser) + (close-brackets/extension) + (match-brackets/extension) + (sel-history/extension) + (format/ext-format-changed-lines)]) + +(def language-support + "Eases embedding clojure mode into other languages (e.g. markdown). + See https://codemirror.net/docs/ref/#language.LanguageSupport for motivations" + (LanguageSupport. (syntax) (.. default-extensions (slice 1)))) + +(comment + + (let [state (test-utils/make-state #js[(syntax lezer-clj/parser)] "[] a")] + (-> (n/tree state) + (.resolve 2 1) ;; Symbol "a" + .-prevSibling + js/console.log)) + + (let [state (test-utils/make-state #js[(syntax lezer-clj/parser)] "\"\" :a")] + (-> state + n/tree + (n/cursor 0 1) + )) + (let [state (test-utils/make-state #js[(syntax lezer-clj/parser)] "a\n\nb")] + (-> state + (n/tree 1 1) + (->> (n/string state)) + str + )) + (let [state (test-utils/make-state #js[(syntax lezer-clj/parser)] "([]| s)")] + (-> state + n/tree + (n/terminal-cursor 3 1) + )) + + (let [state (test-utils/make-state #js[(syntax lezer-clj/parser)] "(|")] + (-> state + (close-brackets/handle-close ")") + (->> (n/string state))))) + +(prn :clojure-mode-loaded) diff --git a/src-squint/nextjournal/clojure_mode/commands.cljs b/src-squint/nextjournal/clojure_mode/commands.cljs index 855a7dfb..1969538b 100644 --- a/src-squint/nextjournal/clojure_mode/commands.cljs +++ b/src-squint/nextjournal/clojure_mode/commands.cljs @@ -104,7 +104,7 @@ (n/top? %))) (n/children from dir) first - (j/get (case dir -1 :from 1 :to))) + (get (case dir -1 :from 1 :to))) (sel/constrain state (+ from dir)))) (defn nav [dir] @@ -155,7 +155,7 @@ :insert (n/name edge)} (-> edge n/from-to - (j/assoc! :insert " "))]) + (assoc! :insert " "))]) -1 (let [^string edge (n/left-edge-with-prefix state parent) start (n/start (n/with-prefix parent))] @@ -184,7 +184,7 @@ :insert (n/name (n/down-last parent))} (-> (n/down-last parent) n/from-to - (j/assoc! :insert " "))]}) + (assoc! :insert " "))]}) -1 (when-let [next-first-child (some->> (n/down parent) n/rights @@ -205,7 +205,8 @@ (u/update-ranges state)))) (def builtin-index - "Subset of builtin commands that compliment paredit" + ;; TODO, squint, def docstring + #_"Subset of builtin commands that compliment paredit" {:cursorLineStart commands/cursorLineStart :selectLineStart commands/selectLineStart :cursorLineDown commands/cursorLineDown @@ -275,12 +276,14 @@ :enter-and-indent enter-and-indent}) (def index - "Mapping of keyword-id to command functions" + ;; TODO: squint, support def with docstring + #_"Mapping of keyword-id to command functions" (merge builtin-index paredit-index)) (def reverse-index - "Lookup keyword-id by function" + ;; TODO: squint, support def with docstring + #_"Lookup keyword-id by function" (reduce-kv #(assoc %1 %3 %2) {} index)) (prn :commands-loaded) diff --git a/src-squint/nextjournal/clojure_mode/keymap.cljs b/src-squint/nextjournal/clojure_mode/keymap.cljs index e03fcb15..7b77b2d5 100644 --- a/src-squint/nextjournal/clojure_mode/keymap.cljs +++ b/src-squint/nextjournal/clojure_mode/keymap.cljs @@ -7,7 +7,9 @@ [m updates] (reduce-kv (fn [m k f] (if-some [existing (get m k)] - (assoc m k (f existing)) + (assoc m k (if (instance? js/Function f) + (f existing) + (get f existing))) (dissoc m k))) m updates)) ;; (de)serializing commands from keyword-id to function @@ -145,8 +147,10 @@ {:key "Mod-2"}]}) (def builtin (ungroup builtin-keymap*)) -#_#_(def paredit (ungroup paredit-keymap*)) +(def paredit (ungroup paredit-keymap*)) (def complete (.concat paredit builtin)) (comment (ungroup default-keymap)) + +(prn :keymap-loaded) diff --git a/src/nextjournal/clojure_mode.cljs b/src/nextjournal/clojure_mode.cljs index b38cdbb8..aea51021 100644 --- a/src/nextjournal/clojure_mode.cljs +++ b/src/nextjournal/clojure_mode.cljs @@ -7,10 +7,10 @@ [nextjournal.clojure-mode.extensions.match-brackets :as match-brackets] [nextjournal.clojure-mode.extensions.formatting :as format] [nextjournal.clojure-mode.extensions.selection-history :as sel-history] - ;; TODO: [nextjournal.clojure-mode.keymap :as keymap] [nextjournal.clojure-mode.node :as n] - [nextjournal.clojure-mode.test-utils :as test-utils])) + ;; TODO: + #_[nextjournal.clojure-mode.test-utils :as test-utils])) (def fold-node-props (let [coll-span (fn [^js tree] #js{:from (inc (n/start tree)) From 5e9ce6cc5db919fdfeaabe1515cb8ccdc8fcf60b Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 12:14:37 +0200 Subject: [PATCH 13/80] wip --- public/squint/js/main.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 9b482575..78da34c9 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -8,4 +8,14 @@ import './src-squint/nextjournal/clojure_mode/commands.mjs'; import './src-squint/nextjournal/clojure_mode/keymap.mjs'; import './src-squint/nextjournal/clojure_mode.mjs'; +import { EditorView } from '@codemirror/view'; +import { EditorState } from '@codemirror/state'; + + +let state = EditorState.create({doc: "(+ 1 2 3)"}); +let editorElt = document.querySelector('#editor'); +let editor = new EditorView({state: state, + parent: editorElt }); + +console.log(); console.log('hello'); From adb9bf240af1297399ac21403a802685c2327f57 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 12:26:36 +0200 Subject: [PATCH 14/80] wip --- public/squint/js/main.mjs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 78da34c9..2fbf4752 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -6,16 +6,19 @@ import './src-squint/nextjournal/clojure_mode/extensions/formatting.mjs'; import './src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs'; import './src-squint/nextjournal/clojure_mode/commands.mjs'; import './src-squint/nextjournal/clojure_mode/keymap.mjs'; -import './src-squint/nextjournal/clojure_mode.mjs'; +import { default_extensions } from './src-squint/nextjournal/clojure_mode.mjs'; import { EditorView } from '@codemirror/view'; import { EditorState } from '@codemirror/state'; +import { syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language'; -let state = EditorState.create({doc: "(+ 1 2 3)"}); +console.log(default_extensions); + +let extensions = [ (syntaxHighlighting(defaultHighlightStyle)), ...default_extensions.slice(0,1) ] +let state = EditorState.create( {doc: "(+ 1 2 3)", + extensions: extensions }); let editorElt = document.querySelector('#editor'); let editor = new EditorView({state: state, parent: editorElt }); -console.log(); -console.log('hello'); From 03a4e1009c25f616a37f01c55ddf5fffbc53be89 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 13:38:10 +0200 Subject: [PATCH 15/80] wip --- package.json | 2 +- public/squint/js/main.mjs | 2 +- .../extensions/close_brackets.mjs | 18 ++++---- .../nextjournal/clojure_mode/node.mjs | 31 +++++++------- .../nextjournal/clojure_mode/util.mjs | 42 +++++++++---------- .../extensions/close_brackets.cljs | 4 +- src-squint/nextjournal/clojure_mode/node.cljs | 3 +- src-squint/nextjournal/clojure_mode/util.cljs | 7 ++-- yarn.lock | 4 +- 9 files changed, 55 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index f46ea3f2..07248a77 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,6 @@ "devDependencies": { "shadow-cljs": "2.19.5", "vite": "^4.4.9", - "squint-cljs": "^0.1.18" + "squint-cljs": "../squint" } } diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 2fbf4752..855eb307 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -15,7 +15,7 @@ import { syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language' console.log(default_extensions); -let extensions = [ (syntaxHighlighting(defaultHighlightStyle)), ...default_extensions.slice(0,1) ] +let extensions = [ (syntaxHighlighting(defaultHighlightStyle)), ...default_extensions.slice(0,2) ] let state = EditorState.create( {doc: "(+ 1 2 3)", extensions: extensions }); let editorElt = document.querySelector('#editor'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs index 8525e56c..18b3caa1 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs @@ -6,11 +6,11 @@ import * as u from '../util.mjs'; import { from_to } from '../util.mjs'; import * as str from 'squint-cljs/string.js'; var in_string_QMARK_ = (function (state, pos) { -return new Set(["StringContent", "String"])(n.name(n.tree(state, pos))); +return squint_core.contains_QMARK_(new Set(["StringContent", "String"]), n.name(n.tree(state, pos))); }) ; var escaped_QMARK_ = (function (state, pos) { -return ("\\" === state["doc"].slice(max(0, (pos - 1)), pos).toString()); +return ("\\" === state["doc"].slice(squint_core.max(0, (pos - 1)), pos).toString()); }) ; var backspace_backoff = (function (state, from, to) { @@ -62,7 +62,7 @@ return null;}}}} var coll_pairs = ({ "(": ")", "[": "]", "{": "}", "\"": "\"" }) ; var handle_open = (function (state, open) { -let close23 = coll_pairs(open); +let close23 = squint_core.get(coll_pairs, open); return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__24) { let map__2526 = p__24; let from27 = squint_core.get(map__2526, "from"); @@ -120,10 +120,10 @@ return n.end(G__5051);} if ((closing45 && (closing45 === key_name))) { return ({ "changes": ({ "from": pos49, "insert": closing45 }), "cursor": (pos49 + 1) });} })() || (function () { - let temp__25187__auto__52 = (function () { - let temp__25187__auto__53 = n.terminal_cursor(n.tree(state), head37, 1); -if (temp__25187__auto__53) { -let cursor54 = temp__25187__auto__53; + let temp__31544__auto__52 = (function () { + let temp__31544__auto__53 = n.terminal_cursor(n.tree(state), head37, 1); +if (temp__31544__auto__53) { +let cursor54 = temp__31544__auto__53; while(true){ if (n.right_edge_type_QMARK_(cursor54["type"])) { return n.end(cursor54);} else { @@ -133,8 +133,8 @@ continue; } } })(); -if (temp__25187__auto__52) { -let close_node_end55 = temp__25187__auto__52; +if (temp__31544__auto__52) { +let close_node_end55 = temp__31544__auto__52; return ({ "cursor": close_node_end55 });} })() || ({ "cursor": head37 }));}} })); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs index 907fba68..ecbe641e 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs @@ -45,7 +45,6 @@ return node["type"]; }) ; var start = (function (node) { -assert(node["from"]); return node["from"]; }) ; @@ -72,10 +71,10 @@ var depth = (function (node) { let node4 = node; let i5 = 0; while(true){ -let temp__25059__auto__6 = up(node4); -if (squint_core.nil_QMARK_(temp__25059__auto__6)) { +let temp__25216__auto__6 = up(node4); +if (squint_core.nil_QMARK_(temp__25216__auto__6)) { return i5;} else { -let parent7 = temp__25059__auto__6; +let parent7 = temp__25216__auto__6; let G__8 = parent7; let G__9 = (i5 + 1); node4 = G__8; @@ -257,18 +256,18 @@ let map__1617 = p__15; let node18 = map__1617; let firstChild19 = squint_core.get(map__1617, "firstChild"); let lastChild20 = squint_core.get(map__1617, "lastChild"); -let temp__24970__auto__21 = closed_by(firstChild19); -if (temp__24970__auto__21) { -let closing22 = temp__24970__auto__21; +let temp__25170__auto__21 = closed_by(firstChild19); +if (temp__25170__auto__21) { +let closing22 = temp__25170__auto__21; return ((closing22 === name(lastChild20)) && (end(firstChild19) !== end(lastChild20)));} else { return true;} }) ; var ancestors = (function (node) { -let temp__25231__auto__23 = up(node); -if (squint_core.nil_QMARK_(temp__25231__auto__23)) { +let temp__25350__auto__23 = up(node); +if (squint_core.nil_QMARK_(temp__25350__auto__23)) { return null;} else { -let parent24 = temp__25231__auto__23; +let parent24 = temp__25350__auto__23; return squint_core.cons(parent24, new squint_core.LazySeq((function () { return ancestors(parent24); })));} @@ -304,7 +303,7 @@ default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); f25["cljs$core$IFn$_invoke$arity$3"] = (function (parent, from, dir) { -let temp__25231__auto__31 = (function () { +let temp__25350__auto__31 = (function () { let G__3233 = dir; switch (G__3233) {case 1: return parent.childAfter(from); @@ -315,9 +314,9 @@ break; default: throw new Error(squint_core.str("No matching clause: ", G__3233))} })(); -if (squint_core.nil_QMARK_(temp__25231__auto__31)) { +if (squint_core.nil_QMARK_(temp__25350__auto__31)) { return null;} else { -let child35 = temp__25231__auto__31; +let child35 = temp__25350__auto__31; return squint_core.cons(child35, new squint_core.LazySeq((function () { return children(parent, (function () { let G__3637 = dir; @@ -622,10 +621,10 @@ return node;} }) ; var prefix = (function (node) { -let temp__25231__auto__117 = up(node); -if (squint_core.nil_QMARK_(temp__25231__auto__117)) { +let temp__25350__auto__117 = up(node); +if (squint_core.nil_QMARK_(temp__25350__auto__117)) { return null;} else { -let parent118 = temp__25231__auto__117; +let parent118 = temp__25350__auto__117; return (u.guard(parent118, prefix_container_QMARK_) || u.guard(down(parent118), prefix_edge_QMARK_));} }) ; diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs index fa55096d..835f3d39 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs @@ -64,10 +64,10 @@ default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); f7["cljs$core$IFn$_invoke$arity$1"] = (function (from) { -return deletion(max(0, (from - 1)), from); +return deletion(squint_core.max(0, (from - 1)), from); }); f7["cljs$core$IFn$_invoke$arity$2"] = (function (from, to) { -let from13 = ((from === to)) ? (max(0, (from - 1))) : (from); +let from13 = ((from === to)) ? (squint_core.max(0, (from - 1))) : (from); return ({ "cursor": from13, "changes": ({ "from": from13, "to": to }) }); }); f7["cljs$lang$maxFixedArity"] = 2; @@ -79,18 +79,16 @@ return state["doc"].lineAt(from).slice(); }) ; var map_cursor = (function (original_range, state, update_map) { -assert(map_QMARK_(update_map)); -let map__1415 = guard(update_map, map_QMARK_); +let map__1415 = guard(update_map, squint_core.map_QMARK_); let mapped16 = squint_core.get(map__1415, "cursor/mapped"); let cursor17 = squint_core.get(map__1415, "cursor"); let from_to18 = squint_core.get(map__1415, "from-to"); let range19 = squint_core.get(map__1415, "range"); let changes20 = squint_core.get(map__1415, "changes"); -let change_desc21 = (changes20) ? (state.changes(clj__GT_js(changes20))) : (null); +let change_desc21 = (changes20) ? (state.changes(changes20)) : (null); let G__2223 = ({ "range": (range19 || (mapped16) ? (sel.cursor(change_desc21.mapPos(mapped16))) : ((cursor17) ? (sel.cursor(cursor17)) : ((from_to18) ? (sel.range(from_to18(0), from_to18(1))) : (null))) || original_range) }); if (change_desc21) { -return G__2223 = "changes"; -;} else { +return squint_core.aset(G__2223, "changes", change_desc21);} else { return G__2223;} }) ; @@ -114,10 +112,10 @@ return state.update((function (_PERCENT_1) { return Object.assign(_PERCENT_1, tr_specs); })(state.changeByRange((function (range) { return ((function () { - let temp__25231__auto__30 = f(range); -if (squint_core.nil_QMARK_(temp__25231__auto__30)) { + let temp__27794__auto__30 = f(range); +if (squint_core.nil_QMARK_(temp__27794__auto__30)) { return null;} else { -let result31 = temp__25231__auto__30; +let result31 = temp__27794__auto__30; return map_cursor(range, state, result31);} })() || ({ "range": range })); })))); @@ -135,10 +133,10 @@ return dispatch(state.update(({ "changes": changes })));} var update_lines = (function () { let f32 = (function (var_args) { let args3338 = []; -let len__24329__auto__39 = arguments["length"]; +let len__26551__auto__39 = arguments["length"]; let i3440 = 0; while(true){ -if ((i3440 < len__24329__auto__39)) { +if ((i3440 < len__26551__auto__39)) { args3338.push((arguments[i3440])); let G__41 = (i3440 + 1); i3440 = G__41; @@ -146,8 +144,8 @@ continue; };break; } ; -let argseq__24575__auto__42 = ((2 < args3338["length"])) ? (args3338.slice(2)) : (null); -return f32.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__24575__auto__42); +let argseq__26872__auto__42 = ((2 < args3338["length"])) ? (args3338.slice(2)) : (null); +return f32.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__26872__auto__42); }); f32["cljs$core$IFn$_invoke$arity$variadic"] = (function (state, f, p__43) { let vec__4448 = p__43; @@ -169,9 +167,9 @@ if ((done60 || (from50 > to51))) { return state.update(Object.assign(({ "changes": state.changes(changes55) }), spec52));} else { let G__63 = iterator53.next(); let G__64 = (function () { - let temp__24970__auto__65 = (!lineBreak61 && f(from_pos56, value62, line_num57)); -if (temp__24970__auto__65) { -let change66 = temp__24970__auto__65; + let temp__27646__auto__65 = (!lineBreak61 && f(from_pos56, value62, line_num57)); +if (temp__27646__auto__65) { +let change66 = temp__27646__auto__65; let G__6768 = changes55; G__6768.push(change66); return G__6768;} else { @@ -199,8 +197,8 @@ let G__3673 = squint_core.first(seq35); let seq3574 = next(seq35); let G__3775 = squint_core.first(seq3574); let seq3576 = next(seq3574); -let self__24359__auto__77 = this; -return self__24359__auto__77.cljs$core$IFn$_invoke$arity$variadic(G__3673, G__3775, seq3576); +let self__26573__auto__77 = this; +return self__26573__auto__77.cljs$core$IFn$_invoke$arity$variadic(G__3673, G__3775, seq3576); }); return f32; })() @@ -224,11 +222,11 @@ let line_to93 = squint_core.get(map__9091, "to"); if ((line89["number"] > squint_core.deref(at_line78))) { squint_core.reset_BANG_(at_line78, line_number92); f(line89, changes88, range83)}; -let temp__24970__auto__94 = ((to85 > line_to93) && guard(doc79.lineAt((line_to93 + 1)), (function (_PERCENT_1) { +let temp__27646__auto__94 = ((to85 > line_to93) && guard(doc79.lineAt((line_to93 + 1)), (function (_PERCENT_1) { return (_PERCENT_1["number"] > line_number92); }))); -if (temp__24970__auto__94) { -let next_line95 = temp__24970__auto__94; +if (temp__27646__auto__94) { +let next_line95 = temp__27646__auto__94; let G__96 = next_line95; line89 = G__96; continue; diff --git a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs index 03993fc6..96826f97 100644 --- a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs +++ b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs @@ -9,7 +9,7 @@ [clojure.string :as str])) (defn in-string? [state pos] - (#{"StringContent" "String"} (n/name (n/tree state pos)))) + (contains? #{"StringContent" "String"} (n/name (n/tree state pos)))) (defn escaped? [state pos] (= \\ (.. state -doc (slice (max 0 (dec pos)) pos) toString))) @@ -67,7 +67,7 @@ \" \"}) (defn handle-open [^EditorState state ^string open] - (let [^string close (coll-pairs open)] + (let [^string close (get coll-pairs open)] (u/update-ranges state #js{:annotations (u/user-event-annotation "input")} (fn [^:js {:keys [from to head anchor empty]}] diff --git a/src-squint/nextjournal/clojure_mode/node.cljs b/src-squint/nextjournal/clojure_mode/node.cljs index c7a0caf3..e8c01121 100644 --- a/src-squint/nextjournal/clojure_mode/node.cljs +++ b/src-squint/nextjournal/clojure_mode/node.cljs @@ -40,7 +40,8 @@ (defn ^lz-tree/NodeType type [^js node] (.-type node)) (defn ^number start [^js node] - {:pre [(.-from node)]} + ;; TODO: fix in squint + #_{:pre [(.-from node)]} (.-from node)) (defn ^number end [^js node] diff --git a/src-squint/nextjournal/clojure_mode/util.cljs b/src-squint/nextjournal/clojure_mode/util.cljs index d80d02a6..e022a585 100644 --- a/src-squint/nextjournal/clojure_mode/util.cljs +++ b/src-squint/nextjournal/clojure_mode/util.cljs @@ -48,19 +48,20 @@ (.. state -doc (lineAt from) slice)) (defn map-cursor [^js original-range ^js state update-map] - {:pre [(map? update-map)]} + ;; TODO: fix in squint + #_{:pre [(map? update-map)]} (let [{:keys [cursor/mapped cursor from-to range changes]} (guard update-map map?) - change-desc (when changes (.changes state (clj->js changes)))] + change-desc (when changes (.changes state changes))] (cond-> #js{:range (or range (cond mapped (sel/cursor (.mapPos change-desc mapped)) cursor (sel/cursor cursor) from-to (sel/range (from-to 0) (from-to 1))) original-range)} - change-desc (set! :changes change-desc)))) + change-desc (aset :changes change-desc)))) (defn update-ranges "Applies `f` to each range in `state` (see `changeByRange`)" diff --git a/yarn.lock b/yarn.lock index 39275f80..034a08e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1072,10 +1072,8 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -squint-cljs@^0.1.18: +squint-cljs@../squint: version "0.1.18" - resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.1.18.tgz#0be3a2fe824d12c76949ce31363331cb98507d70" - integrity sha512-nhwxpGbPTi7XrvVe5b5m4o4cd7uB+bV5pDCixjX5NNnNMrMBpuedv735MgV8XiSr3GwwQMpQiOwW5Op6BR7+Qw== stream-browserify@^2.0.1: version "2.0.2" From 681e7c72094fc1b8a2edd0238d3110df7c94cfe7 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 14:12:52 +0200 Subject: [PATCH 16/80] wip --- .../extensions/close_brackets.mjs | 12 +- .../nextjournal/clojure_mode/node.mjs | 31 +- .../nextjournal/clojure_mode/util.mjs | 265 +++++++++--------- src-squint/nextjournal/clojure_mode/node.cljs | 3 +- src-squint/nextjournal/clojure_mode/util.cljs | 5 +- 5 files changed, 160 insertions(+), 156 deletions(-) diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs index 18b3caa1..76c07003 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs @@ -120,10 +120,10 @@ return n.end(G__5051);} if ((closing45 && (closing45 === key_name))) { return ({ "changes": ({ "from": pos49, "insert": closing45 }), "cursor": (pos49 + 1) });} })() || (function () { - let temp__31544__auto__52 = (function () { - let temp__31544__auto__53 = n.terminal_cursor(n.tree(state), head37, 1); -if (temp__31544__auto__53) { -let cursor54 = temp__31544__auto__53; + let temp__27701__auto__52 = (function () { + let temp__27701__auto__53 = n.terminal_cursor(n.tree(state), head37, 1); +if (temp__27701__auto__53) { +let cursor54 = temp__27701__auto__53; while(true){ if (n.right_edge_type_QMARK_(cursor54["type"])) { return n.end(cursor54);} else { @@ -133,8 +133,8 @@ continue; } } })(); -if (temp__31544__auto__52) { -let close_node_end55 = temp__31544__auto__52; +if (temp__27701__auto__52) { +let close_node_end55 = temp__27701__auto__52; return ({ "cursor": close_node_end55 });} })() || ({ "cursor": head37 }));}} })); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs index ecbe641e..2d582701 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs @@ -49,7 +49,6 @@ return node["from"]; }) ; var end = (function (node) { -assert(node["to"]); return node["to"]; }) ; @@ -71,10 +70,10 @@ var depth = (function (node) { let node4 = node; let i5 = 0; while(true){ -let temp__25216__auto__6 = up(node4); -if (squint_core.nil_QMARK_(temp__25216__auto__6)) { +let temp__27684__auto__6 = up(node4); +if (squint_core.nil_QMARK_(temp__27684__auto__6)) { return i5;} else { -let parent7 = temp__25216__auto__6; +let parent7 = temp__27684__auto__6; let G__8 = parent7; let G__9 = (i5 + 1); node4 = G__8; @@ -256,18 +255,18 @@ let map__1617 = p__15; let node18 = map__1617; let firstChild19 = squint_core.get(map__1617, "firstChild"); let lastChild20 = squint_core.get(map__1617, "lastChild"); -let temp__25170__auto__21 = closed_by(firstChild19); -if (temp__25170__auto__21) { -let closing22 = temp__25170__auto__21; +let temp__27646__auto__21 = closed_by(firstChild19); +if (temp__27646__auto__21) { +let closing22 = temp__27646__auto__21; return ((closing22 === name(lastChild20)) && (end(firstChild19) !== end(lastChild20)));} else { return true;} }) ; var ancestors = (function (node) { -let temp__25350__auto__23 = up(node); -if (squint_core.nil_QMARK_(temp__25350__auto__23)) { +let temp__27794__auto__23 = up(node); +if (squint_core.nil_QMARK_(temp__27794__auto__23)) { return null;} else { -let parent24 = temp__25350__auto__23; +let parent24 = temp__27794__auto__23; return squint_core.cons(parent24, new squint_core.LazySeq((function () { return ancestors(parent24); })));} @@ -303,7 +302,7 @@ default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); f25["cljs$core$IFn$_invoke$arity$3"] = (function (parent, from, dir) { -let temp__25350__auto__31 = (function () { +let temp__27794__auto__31 = (function () { let G__3233 = dir; switch (G__3233) {case 1: return parent.childAfter(from); @@ -314,9 +313,9 @@ break; default: throw new Error(squint_core.str("No matching clause: ", G__3233))} })(); -if (squint_core.nil_QMARK_(temp__25350__auto__31)) { +if (squint_core.nil_QMARK_(temp__27794__auto__31)) { return null;} else { -let child35 = temp__25350__auto__31; +let child35 = temp__27794__auto__31; return squint_core.cons(child35, new squint_core.LazySeq((function () { return children(parent, (function () { let G__3637 = dir; @@ -621,10 +620,10 @@ return node;} }) ; var prefix = (function (node) { -let temp__25350__auto__117 = up(node); -if (squint_core.nil_QMARK_(temp__25350__auto__117)) { +let temp__27794__auto__117 = up(node); +if (squint_core.nil_QMARK_(temp__27794__auto__117)) { return null;} else { -let parent118 = temp__25350__auto__117; +let parent118 = temp__27794__auto__117; return (u.guard(parent118, prefix_container_QMARK_) || u.guard(down(parent118), prefix_edge_QMARK_));} }) ; diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs index 835f3d39..eadb6535 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs @@ -86,42 +86,45 @@ let from_to18 = squint_core.get(map__1415, "from-to"); let range19 = squint_core.get(map__1415, "range"); let changes20 = squint_core.get(map__1415, "changes"); let change_desc21 = (changes20) ? (state.changes(changes20)) : (null); -let G__2223 = ({ "range": (range19 || (mapped16) ? (sel.cursor(change_desc21.mapPos(mapped16))) : ((cursor17) ? (sel.cursor(cursor17)) : ((from_to18) ? (sel.range(from_to18(0), from_to18(1))) : (null))) || original_range) }); +let G__2223 = ({ "range": (range19 || (mapped16) ? (sel.cursor(change_desc21.mapPos(mapped16))) : ((cursor17) ? (sel.cursor(cursor17)) : ((from_to18) ? (sel.range(squint_core.get(from_to18, 0), squint_core.get(from_to18, 1))) : (null))) || original_range) }); if (change_desc21) { -return squint_core.aset(G__2223, "changes", change_desc21);} else { +let G__2425 = G__2223; +squint_core.aset(G__2425, "changes", change_desc21); +return G__2425;} else { return G__2223;} }) ; var update_ranges = (function () { - let f24 = (function (var_args) { -let G__2728 = arguments["length"]; -switch (G__2728) {case 2: -return f24.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); + let f26 = (function (var_args) { +let G__2930 = arguments["length"]; +switch (G__2930) {case 2: +return f26.cljs$core$IFn$_invoke$arity$2((arguments[0]), (arguments[1])); break; case 3: -return f24.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); +return f26.cljs$core$IFn$_invoke$arity$3((arguments[0]), (arguments[1]), (arguments[2])); break; default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); -f24["cljs$core$IFn$_invoke$arity$2"] = (function (state, f) { +f26["cljs$core$IFn$_invoke$arity$2"] = (function (state, f) { return update_ranges(state, null, f); }); -f24["cljs$core$IFn$_invoke$arity$3"] = (function (state, tr_specs, f) { +f26["cljs$core$IFn$_invoke$arity$3"] = (function (state, tr_specs, f) { return state.update((function (_PERCENT_1) { return Object.assign(_PERCENT_1, tr_specs); })(state.changeByRange((function (range) { +console.log("range", range); return ((function () { - let temp__27794__auto__30 = f(range); -if (squint_core.nil_QMARK_(temp__27794__auto__30)) { + let temp__27794__auto__32 = f(range); +if (squint_core.nil_QMARK_(temp__27794__auto__32)) { return null;} else { -let result31 = temp__27794__auto__30; -return map_cursor(range, state, result31);} +let result33 = temp__27794__auto__32; +return map_cursor(range, state, result33);} })() || ({ "range": range })); })))); }); -f24["cljs$lang$maxFixedArity"] = 3; -return f24; +f26["cljs$lang$maxFixedArity"] = 3; +return f26; })() ; var dispatch_changes = (function (state, dispatch, changes) { @@ -131,159 +134,159 @@ return dispatch(state.update(({ "changes": changes })));} }) ; var update_lines = (function () { - let f32 = (function (var_args) { -let args3338 = []; -let len__26551__auto__39 = arguments["length"]; -let i3440 = 0; + let f34 = (function (var_args) { +let args3540 = []; +let len__26551__auto__41 = arguments["length"]; +let i3642 = 0; while(true){ -if ((i3440 < len__26551__auto__39)) { -args3338.push((arguments[i3440])); -let G__41 = (i3440 + 1); -i3440 = G__41; +if ((i3642 < len__26551__auto__41)) { +args3540.push((arguments[i3642])); +let G__43 = (i3642 + 1); +i3642 = G__43; continue; };break; } ; -let argseq__26872__auto__42 = ((2 < args3338["length"])) ? (args3338.slice(2)) : (null); -return f32.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__26872__auto__42); +let argseq__26872__auto__44 = ((2 < args3540["length"])) ? (args3540.slice(2)) : (null); +return f34.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__26872__auto__44); }); -f32["cljs$core$IFn$_invoke$arity$variadic"] = (function (state, f, p__43) { -let vec__4448 = p__43; -let map__4749 = squint_core.nth(vec__4448, 0, null); -let from50 = squint_core.get(map__4749, "from", 0); -let to51 = squint_core.get(map__4749, "to"); -let spec52 = squint_core.get(map__4749, "spec"); -let iterator53 = state["doc"].iter(); -let result54 = iterator53.next(); -let changes55 = []; -let from_pos56 = from50; -let line_num57 = 1; +f34["cljs$core$IFn$_invoke$arity$variadic"] = (function (state, f, p__45) { +let vec__4650 = p__45; +let map__4951 = squint_core.nth(vec__4650, 0, null); +let from52 = squint_core.get(map__4951, "from", 0); +let to53 = squint_core.get(map__4951, "to"); +let spec54 = squint_core.get(map__4951, "spec"); +let iterator55 = state["doc"].iter(); +let result56 = iterator55.next(); +let changes57 = []; +let from_pos58 = from52; +let line_num59 = 1; while(true){ -let map__5859 = result54; -let done60 = squint_core.get(map__5859, "done"); -let lineBreak61 = squint_core.get(map__5859, "lineBreak"); -let value62 = squint_core.get(map__5859, "value"); -if ((done60 || (from50 > to51))) { -return state.update(Object.assign(({ "changes": state.changes(changes55) }), spec52));} else { -let G__63 = iterator53.next(); -let G__64 = (function () { - let temp__27646__auto__65 = (!lineBreak61 && f(from_pos56, value62, line_num57)); -if (temp__27646__auto__65) { -let change66 = temp__27646__auto__65; -let G__6768 = changes55; -G__6768.push(change66); -return G__6768;} else { -return changes55;} +let map__6061 = result56; +let done62 = squint_core.get(map__6061, "done"); +let lineBreak63 = squint_core.get(map__6061, "lineBreak"); +let value64 = squint_core.get(map__6061, "value"); +if ((done62 || (from52 > to53))) { +return state.update(Object.assign(({ "changes": state.changes(changes57) }), spec54));} else { +let G__65 = iterator55.next(); +let G__66 = (function () { + let temp__27646__auto__67 = (!lineBreak63 && f(from_pos58, value64, line_num59)); +if (temp__27646__auto__67) { +let change68 = temp__27646__auto__67; +let G__6970 = changes57; +G__6970.push(change68); +return G__6970;} else { +return changes57;} })(); -let G__69 = (from_pos56 + squint_core.count(value62)); -let G__70 = (function () { - let G__7172 = line_num57; -if (lineBreak61) { -return (G__7172 + 1);} else { -return G__7172;} +let G__71 = (from_pos58 + squint_core.count(value64)); +let G__72 = (function () { + let G__7374 = line_num59; +if (lineBreak63) { +return (G__7374 + 1);} else { +return G__7374;} })(); -result54 = G__63; -changes55 = G__64; -from_pos56 = G__69; -line_num57 = G__70; +result56 = G__65; +changes57 = G__66; +from_pos58 = G__71; +line_num59 = G__72; continue; };break; } }); -f32["cljs$lang$maxFixedArity"] = 2; -f32["cljs$lang$applyTo"] = (function (seq35) { -let G__3673 = squint_core.first(seq35); -let seq3574 = next(seq35); -let G__3775 = squint_core.first(seq3574); -let seq3576 = next(seq3574); -let self__26573__auto__77 = this; -return self__26573__auto__77.cljs$core$IFn$_invoke$arity$variadic(G__3673, G__3775, seq3576); +f34["cljs$lang$maxFixedArity"] = 2; +f34["cljs$lang$applyTo"] = (function (seq37) { +let G__3875 = squint_core.first(seq37); +let seq3776 = next(seq37); +let G__3977 = squint_core.first(seq3776); +let seq3778 = next(seq3776); +let self__26573__auto__79 = this; +return self__26573__auto__79.cljs$core$IFn$_invoke$arity$variadic(G__3875, G__3977, seq3778); }); -return f32; +return f34; })() ; var update_selected_lines = (function (state, f) { -let at_line78 = squint_core.atom(-1); -let doc79 = state["doc"]; -return state.changeByRange((function (p__80) { -let map__8182 = p__80; -let range83 = map__8182; -let from84 = squint_core.get(map__8182, "from"); -let to85 = squint_core.get(map__8182, "to"); -let anchor86 = squint_core.get(map__8182, "anchor"); -let head87 = squint_core.get(map__8182, "head"); -let changes88 = []; -let line89 = doc79.lineAt(from84); +let at_line80 = squint_core.atom(-1); +let doc81 = state["doc"]; +return state.changeByRange((function (p__82) { +let map__8384 = p__82; +let range85 = map__8384; +let from86 = squint_core.get(map__8384, "from"); +let to87 = squint_core.get(map__8384, "to"); +let anchor88 = squint_core.get(map__8384, "anchor"); +let head89 = squint_core.get(map__8384, "head"); +let changes90 = []; +let line91 = doc81.lineAt(from86); while(true){ -let map__9091 = line89; -let line_number92 = squint_core.get(map__9091, "number"); -let line_to93 = squint_core.get(map__9091, "to"); -if ((line89["number"] > squint_core.deref(at_line78))) { -squint_core.reset_BANG_(at_line78, line_number92); -f(line89, changes88, range83)}; -let temp__27646__auto__94 = ((to85 > line_to93) && guard(doc79.lineAt((line_to93 + 1)), (function (_PERCENT_1) { -return (_PERCENT_1["number"] > line_number92); +let map__9293 = line91; +let line_number94 = squint_core.get(map__9293, "number"); +let line_to95 = squint_core.get(map__9293, "to"); +if ((line91["number"] > squint_core.deref(at_line80))) { +squint_core.reset_BANG_(at_line80, line_number94); +f(line91, changes90, range85)}; +let temp__27646__auto__96 = ((to87 > line_to95) && guard(doc81.lineAt((line_to95 + 1)), (function (_PERCENT_1) { +return (_PERCENT_1["number"] > line_number94); }))); -if (temp__27646__auto__94) { -let next_line95 = temp__27646__auto__94; -let G__96 = next_line95; -line89 = G__96; +if (temp__27646__auto__96) { +let next_line97 = temp__27646__auto__96; +let G__98 = next_line97; +line91 = G__98; continue; } else { -let change_set97 = state.changes(changes88); -return ({ "changes": changes88, "range": EditorSelection.range(change_set97.mapPos(anchor86, 1), change_set97.mapPos(head87, 1)) });};break; +let change_set99 = state.changes(changes90); +return ({ "changes": changes90, "range": EditorSelection.range(change_set99.mapPos(anchor88, 1), change_set99.mapPos(head89, 1)) });};break; } })); }) ; -var iter_changed_lines = (function (p__98, f) { -let map__99101 = p__98; -let tr102 = map__99101; -let map__100103 = squint_core.get(map__99101, "state"); -let state104 = map__100103; -let doc105 = squint_core.get(map__100103, "doc"); -let changes106 = squint_core.get(map__99101, "changes"); -let effects107 = squint_core.get(map__99101, "effects"); -let selection108 = squint_core.get(map__99101, "selection"); -let at_line109 = squint_core.atom(-1); -let next_changes110 = []; -let _111 = changes106.iterChanges((function (_from_a, _to_a, from_b, to_b, _inserted) { -let map__112113 = doc105.lineAt(from_b); -let line114 = map__112113; -let line_number115 = squint_core.get(map__112113, "number"); -let line_to116 = squint_core.get(map__112113, "to"); -let line117 = line114; +var iter_changed_lines = (function (p__100, f) { +let map__101103 = p__100; +let tr104 = map__101103; +let map__102105 = squint_core.get(map__101103, "state"); +let state106 = map__102105; +let doc107 = squint_core.get(map__102105, "doc"); +let changes108 = squint_core.get(map__101103, "changes"); +let effects109 = squint_core.get(map__101103, "effects"); +let selection110 = squint_core.get(map__101103, "selection"); +let at_line111 = squint_core.atom(-1); +let next_changes112 = []; +let _113 = changes108.iterChanges((function (_from_a, _to_a, from_b, to_b, _inserted) { +let map__114115 = doc107.lineAt(from_b); +let line116 = map__114115; +let line_number117 = squint_core.get(map__114115, "number"); +let line_to118 = squint_core.get(map__114115, "to"); +let line119 = line116; while(true){ -if ((line_number115 > squint_core.deref(at_line109))) { -squint_core.reset_BANG_(at_line109, line_number115); -f(line117, next_changes110)}; -if ((to_b <= line_to116)) { +if ((line_number117 > squint_core.deref(at_line111))) { +squint_core.reset_BANG_(at_line111, line_number117); +f(line119, next_changes112)}; +if ((to_b <= line_to118)) { return null;} else { -let next_line118 = doc105.lineAt((line_to116 + 1)); -if ((next_line118 && (next_line118["number"] > line117["number"]))) { -let G__119 = next_line118; -line117 = G__119; +let next_line120 = doc107.lineAt((line_to118 + 1)); +if ((next_line120 && (next_line120["number"] > line119["number"]))) { +let G__121 = next_line120; +line119 = G__121; continue; }};break; } })); -let next_changeset120 = state104.changes(next_changes110); -if (squint_core.seq(next_changes110)) { -let G__121122 = squint_core.assoc_BANG_(squint_core.select_keys(tr102, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes106.compose(next_changeset120)); -let G__121123 = (selection108) ? (squint_core.assoc_BANG_(G__121122, "selection", state104["selection"].map(next_changeset120))) : (G__121122); -if (effects107) { -return squint_core.assoc_BANG_(G__121123, "effects", StateEffect.mapEffects(effects107, next_changeset120));} else { -return G__121123;}} else { -return tr102;} +let next_changeset122 = state106.changes(next_changes112); +if (squint_core.seq(next_changes112)) { +let G__123124 = squint_core.assoc_BANG_(squint_core.select_keys(tr104, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes108.compose(next_changeset122)); +let G__123125 = (selection110) ? (squint_core.assoc_BANG_(G__123124, "selection", state106["selection"].map(next_changeset122))) : (G__123124); +if (effects109) { +return squint_core.assoc_BANG_(G__123125, "effects", StateEffect.mapEffects(effects109, next_changeset122));} else { +return G__123125;}} else { +return tr104;} }) ; var push_BANG_ = (function (arr, x) { -let G__124125 = arr; -G__124125.push(x); -return G__124125; +let G__126127 = arr; +G__126127.push(x); +return G__126127; }) ; squint_core.prn("util-loaded"); diff --git a/src-squint/nextjournal/clojure_mode/node.cljs b/src-squint/nextjournal/clojure_mode/node.cljs index e8c01121..3ce11861 100644 --- a/src-squint/nextjournal/clojure_mode/node.cljs +++ b/src-squint/nextjournal/clojure_mode/node.cljs @@ -45,7 +45,8 @@ (.-from node)) (defn ^number end [^js node] - {:pre [(.-to node)]} + ;; TODO: fix in squint + #_{:pre [(.-to node)]} (.-to node)) ;; a more zipper-like interface diff --git a/src-squint/nextjournal/clojure_mode/util.cljs b/src-squint/nextjournal/clojure_mode/util.cljs index e022a585..af98e45b 100644 --- a/src-squint/nextjournal/clojure_mode/util.cljs +++ b/src-squint/nextjournal/clojure_mode/util.cljs @@ -59,9 +59,9 @@ (cond-> #js{:range (or range (cond mapped (sel/cursor (.mapPos change-desc mapped)) cursor (sel/cursor cursor) - from-to (sel/range (from-to 0) (from-to 1))) + from-to (sel/range (get from-to 0) (get from-to 1))) original-range)} - change-desc (aset :changes change-desc)))) + change-desc (doto (aset :changes change-desc))))) (defn update-ranges "Applies `f` to each range in `state` (see `changeByRange`)" @@ -69,6 +69,7 @@ (update-ranges state nil f)) ([^js state tr-specs f ] (->> (fn [range] + (js/console.log "range" range) (or (when-some [result (f range)] (map-cursor range state result)) #js{:range range})) From 3157c2df513c25fdc0698d156847b05cc52e30c8 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 15:07:18 +0200 Subject: [PATCH 17/80] wip --- bb.edn | 14 +- .../extensions/close_brackets.mjs | 172 +++++++------ .../nextjournal/clojure_mode/node.mjs | 2 - .../nextjournal/clojure_mode/util.mjs | 241 +++++++++--------- .../extensions/close_brackets.cljs | 167 ++++++------ src-squint/nextjournal/clojure_mode/node.cljs | 5 +- src-squint/nextjournal/clojure_mode/util.cljs | 8 +- .../extensions/close_brackets.cljs | 5 +- src/nextjournal/clojure_mode/util.cljs | 7 +- 9 files changed, 318 insertions(+), 303 deletions(-) diff --git a/bb.edn b/bb.edn index 7d507516..da252738 100644 --- a/bb.edn +++ b/bb.edn @@ -26,15 +26,15 @@ (doseq [path paths] (fs/delete path))) #_#_compile {:doc "Use squintjs to compile all cljs files recursively" - :depends [yarn-install] - :task (shell {:std :inherit :err :inherit} - (apply str (cons "yarn squint compile " - (interpose " " (get-paths :cljs)))))} + :depends [yarn-install] + :task (shell {:std :inherit :err :inherit} + (apply str (cons "yarn squint compile " + (interpose " " (get-paths :cljs)))))} #_#_build {:doc "Compiles cljs files with squint and builds from mjs sources with vite" - :depends [compile] - :task (shell {:std :inherit :err :inherit} - "yarn build")} + :depends [compile] + :task (shell {:std :inherit :err :inherit} + "yarn build")} watch-cljs (t/watch-cljs) diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs index 76c07003..00afe906 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs @@ -1,9 +1,9 @@ import * as squint_core from 'squint-cljs/core.js'; -import * as view from '@codemirror/view'; -import { EditorState, Prec } from '@codemirror/state'; import * as n from '../node.mjs'; import * as u from '../util.mjs'; import { from_to } from '../util.mjs'; +import { EditorState, Prec } from '@codemirror/state'; +import * as view from '@codemirror/view'; import * as str from 'squint-cljs/string.js'; var in_string_QMARK_ = (function (state, pos) { return squint_core.contains_QMARK_(new Set(["StringContent", "String"]), n.name(n.tree(state, pos))); @@ -35,12 +35,12 @@ return (range8["empty"] && (0 === range8["from"])); return null;} else { return u.update_ranges(state6, ({ "annotations": u.user_event_annotation("delete") }), (function (p__9) { let map__1011 = p__9; -let range12 = map__1011; +let _range12 = map__1011; let head13 = squint_core.get(map__1011, "head"); let empty14 = squint_core.get(map__1011, "empty"); let anchor15 = squint_core.get(map__1011, "anchor"); let map__1617 = from_to(head13, anchor15); -let range18 = map__1617; +let _range18 = map__1617; let from19 = squint_core.get(map__1617, "from"); let to20 = squint_core.get(map__1617, "to"); let node_BAR_21 = n.tree(state6).resolveInner(from19, -1); @@ -51,7 +51,9 @@ if ((n.right_edge_QMARK_(node_BAR_21) && (from19 == n.end(parent22)))) { return ({ "cursor": (from19 - 1) });} else { if (((n.start_edge_QMARK_(node_BAR_21) || n.same_edge_QMARK_(node_BAR_21)) && (n.start(node_BAR_21) == n.start(parent22)))) { if (n.empty_QMARK_(n.up(node_BAR_21))) { -return ({ "cursor": n.start(parent22), "changes": [from_to(n.start(parent22), n.end(parent22))] });} else { +let G__2324 = ({ "cursor": n.start(parent22), "changes": [from_to(n.start(parent22), n.end(parent22))] }); +squint_core.println(G__2324); +return G__2324;} else { return ({ "cursor": from19 });}} else { if ("else") { return backspace_backoff(state6, from19, to20);} else { @@ -62,126 +64,126 @@ return null;}}}} var coll_pairs = ({ "(": ")", "[": "]", "{": "}", "\"": "\"" }) ; var handle_open = (function (state, open) { -let close23 = squint_core.get(coll_pairs, open); -return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__24) { -let map__2526 = p__24; -let from27 = squint_core.get(map__2526, "from"); -let to28 = squint_core.get(map__2526, "to"); -let head29 = squint_core.get(map__2526, "head"); -let anchor30 = squint_core.get(map__2526, "anchor"); -let empty31 = squint_core.get(map__2526, "empty"); -if (in_string_QMARK_(state, from27)) { +let close25 = squint_core.get(coll_pairs, open); +return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__26) { +let map__2728 = p__26; +let from29 = squint_core.get(map__2728, "from"); +let to30 = squint_core.get(map__2728, "to"); +let head31 = squint_core.get(map__2728, "head"); +let anchor32 = squint_core.get(map__2728, "anchor"); +let empty33 = squint_core.get(map__2728, "empty"); +if (in_string_QMARK_(state, from29)) { if ((open === "\"")) { -return u.insertion(head29, "\\\"");} else { -return u.insertion(from27, to28, open);}} else { -if (escaped_QMARK_(state, from27)) { -return u.insertion(from27, to28, open);} else { +return u.insertion(head31, "\\\"");} else { +return u.insertion(from29, to30, open);}} else { +if (escaped_QMARK_(state, from29)) { +return u.insertion(from29, to30, open);} else { if ("else") { -if (empty31) { -return ({ "changes": ({ "insert": squint_core.str(open, close23), "from": head29 }), "cursor": (head29 + squint_core.count(open)) });} else { -return ({ "changes": [({ "insert": open, "from": from27 }), ({ "insert": close23, "from": to28 })], "from-to": [(anchor30 + squint_core.count(open)), (head29 + squint_core.count(open))] });}} else { +if (empty33) { +return ({ "changes": ({ "insert": squint_core.str(open, close25), "from": head31 }), "cursor": (head31 + squint_core.count(open)) });} else { +return ({ "changes": [({ "insert": open, "from": from29 }), ({ "insert": close25, "from": to30 })], "from-to": [(anchor32 + squint_core.count(open)), (head31 + squint_core.count(open))] });}} else { return null;}}} })); }) ; var handle_close = (function (state, key_name) { -return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__32) { -let map__3334 = p__32; -let range35 = map__3334; -let empty36 = squint_core.get(map__3334, "empty"); -let head37 = squint_core.get(map__3334, "head"); -let from38 = squint_core.get(map__3334, "from"); -let to39 = squint_core.get(map__3334, "to"); -if ((in_string_QMARK_(state, from38) || escaped_QMARK_(state, from38))) { -return u.insertion(from38, to39, key_name);} else { -if (empty36) { +return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__34) { +let map__3536 = p__34; +let _range37 = map__3536; +let empty38 = squint_core.get(map__3536, "empty"); +let head39 = squint_core.get(map__3536, "head"); +let from40 = squint_core.get(map__3536, "from"); +let to41 = squint_core.get(map__3536, "to"); +if ((in_string_QMARK_(state, from40) || escaped_QMARK_(state, from40))) { +return u.insertion(from40, to41, key_name);} else { +if (empty38) { return ((function () { - let unbalanced40 = (function () { - let G__4142 = n.tree(state, head37, -1); -let G__4143 = (squint_core.nil_QMARK_(G__4142)) ? (null) : (n.ancestors(G__4142)); -let G__4144 = (squint_core.nil_QMARK_(G__4143)) ? (null) : (squint_core.filter(every_pred(n.coll_QMARK_, squint_core.complement(n.balanced_QMARK_)), G__4143)); -if (squint_core.nil_QMARK_(G__4144)) { + let unbalanced42 = (function () { + let G__4344 = n.tree(state, head39, -1); +let G__4345 = (squint_core.nil_QMARK_(G__4344)) ? (null) : (n.ancestors(G__4344)); +let G__4346 = (squint_core.nil_QMARK_(G__4345)) ? (null) : (squint_core.filter(every_pred(n.coll_QMARK_, squint_core.complement(n.balanced_QMARK_)), G__4345)); +if (squint_core.nil_QMARK_(G__4346)) { return null;} else { -return squint_core.first(G__4144);} +return squint_core.first(G__4346);} })(); -let closing45 = (function () { - let G__4647 = unbalanced40; -let G__4648 = (squint_core.nil_QMARK_(G__4647)) ? (null) : (n.down(G__4647)); -if (squint_core.nil_QMARK_(G__4648)) { +let closing47 = (function () { + let G__4849 = unbalanced42; +let G__4850 = (squint_core.nil_QMARK_(G__4849)) ? (null) : (n.down(G__4849)); +if (squint_core.nil_QMARK_(G__4850)) { return null;} else { -return n.closed_by(G__4648);} +return n.closed_by(G__4850);} })(); -let pos49 = (function () { - let G__5051 = unbalanced40; -if (squint_core.nil_QMARK_(G__5051)) { +let pos51 = (function () { + let G__5253 = unbalanced42; +if (squint_core.nil_QMARK_(G__5253)) { return null;} else { -return n.end(G__5051);} +return n.end(G__5253);} })(); -if ((closing45 && (closing45 === key_name))) { -return ({ "changes": ({ "from": pos49, "insert": closing45 }), "cursor": (pos49 + 1) });} +if ((closing47 && (closing47 === key_name))) { +return ({ "changes": ({ "from": pos51, "insert": closing47 }), "cursor": (pos51 + 1) });} })() || (function () { - let temp__27701__auto__52 = (function () { - let temp__27701__auto__53 = n.terminal_cursor(n.tree(state), head37, 1); -if (temp__27701__auto__53) { -let cursor54 = temp__27701__auto__53; + let temp__27701__auto__54 = (function () { + let temp__27701__auto__55 = n.terminal_cursor(n.tree(state), head39, 1); +if (temp__27701__auto__55) { +let cursor56 = temp__27701__auto__55; while(true){ -if (n.right_edge_type_QMARK_(cursor54["type"])) { -return n.end(cursor54);} else { -if (cursor54.next()) { +if (n.right_edge_type_QMARK_(cursor56["type"])) { +return n.end(cursor56);} else { +if (cursor56.next()) { continue; }};break; } } })(); -if (temp__27701__auto__52) { -let close_node_end55 = temp__27701__auto__52; -return ({ "cursor": close_node_end55 });} -})() || ({ "cursor": head37 }));}} +if (temp__27701__auto__54) { +let close_node_end57 = temp__27701__auto__54; +return ({ "cursor": close_node_end57 });} +})() || ({ "cursor": head39 }));}} })); }) ; -var handle_backspace_cmd = (function (p__56) { -let map__5758 = p__56; -let view59 = map__5758; -let state60 = squint_core.get(map__5758, "state"); -return u.dispatch_some(view59, handle_backspace(state60)); +var handle_backspace_cmd = (function (p__58) { +let map__5960 = p__58; +let view61 = map__5960; +let state62 = squint_core.get(map__5960, "state"); +return u.dispatch_some(view61, handle_backspace(state62)); }) ; var handle_open_cmd = (function (key_name) { -return function (p__61) { -let map__6263 = p__61; -let view64 = map__6263; -let state65 = squint_core.get(map__6263, "state"); -return u.dispatch_some(view64, handle_open(state65, key_name)); +return function (p__63) { +let map__6465 = p__63; +let view66 = map__6465; +let state67 = squint_core.get(map__6465, "state"); +return u.dispatch_some(view66, handle_open(state67, key_name)); }; }) ; var handle_close_cmd = (function (key_name) { -return function (p__66) { -let map__6768 = p__66; -let view69 = map__6768; -let state70 = squint_core.get(map__6768, "state"); -return u.dispatch_some(view69, handle_close(state70, key_name)); +return function (p__68) { +let map__6970 = p__68; +let view71 = map__6970; +let state72 = squint_core.get(map__6970, "state"); +return u.dispatch_some(view71, handle_close(state72, key_name)); }; }) ; var guard_scope = (function (cmd) { -return function (p__71) { -let map__7273 = p__71; -let view74 = map__7273; -let state75 = squint_core.get(map__7273, "state"); -if ((n.embedded_QMARK_(state75) || n.within_program_QMARK_(state75))) { -return cmd(view74);} else { +return function (p__73) { +let map__7475 = p__73; +let view76 = map__7475; +let state77 = squint_core.get(map__7475, "state"); +if ((n.embedded_QMARK_(state77) || n.within_program_QMARK_(state77))) { +return cmd(view76);} else { return false;} }; }) ; var extension = (function () { -return Prec.high(view.keymap.of([({ "key": "Backspace", "run": guard_scope((function (p__76) { -let map__7778 = p__76; -let view79 = map__7778; -let state80 = squint_core.get(map__7778, "state"); -return u.dispatch_some(view79, handle_backspace(state80)); +return Prec.high(view.keymap.of([({ "key": "Backspace", "run": guard_scope((function (p__78) { +let map__7980 = p__78; +let view81 = map__7980; +let state82 = squint_core.get(map__7980, "state"); +return u.dispatch_some(view81, handle_backspace(state82)); })) }), ({ "key": "(", "run": guard_scope(handle_open_cmd("(")) }), ({ "key": "[", "run": guard_scope(handle_open_cmd("[")) }), ({ "key": "{", "run": guard_scope(handle_open_cmd("{")) }), ({ "key": "\"", "run": guard_scope(handle_open_cmd("\"")) }), ({ "key": ")", "run": guard_scope(handle_close_cmd(")")) }), ({ "key": "]", "run": guard_scope(handle_close_cmd("]")) }), ({ "key": "}", "run": guard_scope(handle_close_cmd("}")) })])); }) ; diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs index 2d582701..40a34dcc 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs @@ -57,12 +57,10 @@ return node["parent"]; }) ; var down = (function (node) { -assert(!fn_QMARK_(node["lastChild"])); return node["firstChild"]; }) ; var down_last = (function (node) { -assert(!fn_QMARK_(node["lastChild"])); return node["lastChild"]; }) ; diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs index eadb6535..e75d0806 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs @@ -86,7 +86,10 @@ let from_to18 = squint_core.get(map__1415, "from-to"); let range19 = squint_core.get(map__1415, "range"); let changes20 = squint_core.get(map__1415, "changes"); let change_desc21 = (changes20) ? (state.changes(changes20)) : (null); -let G__2223 = ({ "range": (range19 || (mapped16) ? (sel.cursor(change_desc21.mapPos(mapped16))) : ((cursor17) ? (sel.cursor(cursor17)) : ((from_to18) ? (sel.range(squint_core.get(from_to18, 0), squint_core.get(from_to18, 1))) : (null))) || original_range) }); +console.log("map-cursor range", range19); +console.log("mapped?", mapped16); +console.log("curos?", cursor17); +let G__2223 = ({ "range": (range19 || (mapped16) ? (sel.cursor(change_desc21.mapPos(mapped16))) : ((squint_core.some_QMARK_(cursor17)) ? (sel.cursor(cursor17)) : ((from_to18) ? (sel.range(squint_core.get(from_to18, 0), squint_core.get(from_to18, 1))) : (null))) || original_range) }); if (change_desc21) { let G__2425 = G__2223; squint_core.aset(G__2425, "changes", change_desc21); @@ -119,7 +122,9 @@ return ((function () { if (squint_core.nil_QMARK_(temp__27794__auto__32)) { return null;} else { let result33 = temp__27794__auto__32; -return map_cursor(range, state, result33);} +let G__3435 = map_cursor(range, state, result33); +squint_core.println("mapped", G__3435); +return G__3435;} })() || ({ "range": range })); })))); }); @@ -134,159 +139,159 @@ return dispatch(state.update(({ "changes": changes })));} }) ; var update_lines = (function () { - let f34 = (function (var_args) { -let args3540 = []; -let len__26551__auto__41 = arguments["length"]; -let i3642 = 0; + let f36 = (function (var_args) { +let args3742 = []; +let len__26551__auto__43 = arguments["length"]; +let i3844 = 0; while(true){ -if ((i3642 < len__26551__auto__41)) { -args3540.push((arguments[i3642])); -let G__43 = (i3642 + 1); -i3642 = G__43; +if ((i3844 < len__26551__auto__43)) { +args3742.push((arguments[i3844])); +let G__45 = (i3844 + 1); +i3844 = G__45; continue; };break; } ; -let argseq__26872__auto__44 = ((2 < args3540["length"])) ? (args3540.slice(2)) : (null); -return f34.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__26872__auto__44); +let argseq__26872__auto__46 = ((2 < args3742["length"])) ? (args3742.slice(2)) : (null); +return f36.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__26872__auto__46); }); -f34["cljs$core$IFn$_invoke$arity$variadic"] = (function (state, f, p__45) { -let vec__4650 = p__45; -let map__4951 = squint_core.nth(vec__4650, 0, null); -let from52 = squint_core.get(map__4951, "from", 0); -let to53 = squint_core.get(map__4951, "to"); -let spec54 = squint_core.get(map__4951, "spec"); -let iterator55 = state["doc"].iter(); -let result56 = iterator55.next(); -let changes57 = []; -let from_pos58 = from52; -let line_num59 = 1; +f36["cljs$core$IFn$_invoke$arity$variadic"] = (function (state, f, p__47) { +let vec__4852 = p__47; +let map__5153 = squint_core.nth(vec__4852, 0, null); +let from54 = squint_core.get(map__5153, "from", 0); +let to55 = squint_core.get(map__5153, "to"); +let spec56 = squint_core.get(map__5153, "spec"); +let iterator57 = state["doc"].iter(); +let result58 = iterator57.next(); +let changes59 = []; +let from_pos60 = from54; +let line_num61 = 1; while(true){ -let map__6061 = result56; -let done62 = squint_core.get(map__6061, "done"); -let lineBreak63 = squint_core.get(map__6061, "lineBreak"); -let value64 = squint_core.get(map__6061, "value"); -if ((done62 || (from52 > to53))) { -return state.update(Object.assign(({ "changes": state.changes(changes57) }), spec54));} else { -let G__65 = iterator55.next(); -let G__66 = (function () { - let temp__27646__auto__67 = (!lineBreak63 && f(from_pos58, value64, line_num59)); -if (temp__27646__auto__67) { -let change68 = temp__27646__auto__67; -let G__6970 = changes57; -G__6970.push(change68); -return G__6970;} else { -return changes57;} +let map__6263 = result58; +let done64 = squint_core.get(map__6263, "done"); +let lineBreak65 = squint_core.get(map__6263, "lineBreak"); +let value66 = squint_core.get(map__6263, "value"); +if ((done64 || (from54 > to55))) { +return state.update(Object.assign(({ "changes": state.changes(changes59) }), spec56));} else { +let G__67 = iterator57.next(); +let G__68 = (function () { + let temp__27646__auto__69 = (!lineBreak65 && f(from_pos60, value66, line_num61)); +if (temp__27646__auto__69) { +let change70 = temp__27646__auto__69; +let G__7172 = changes59; +G__7172.push(change70); +return G__7172;} else { +return changes59;} })(); -let G__71 = (from_pos58 + squint_core.count(value64)); -let G__72 = (function () { - let G__7374 = line_num59; -if (lineBreak63) { -return (G__7374 + 1);} else { -return G__7374;} +let G__73 = (from_pos60 + squint_core.count(value66)); +let G__74 = (function () { + let G__7576 = line_num61; +if (lineBreak65) { +return (G__7576 + 1);} else { +return G__7576;} })(); -result56 = G__65; -changes57 = G__66; -from_pos58 = G__71; -line_num59 = G__72; +result58 = G__67; +changes59 = G__68; +from_pos60 = G__73; +line_num61 = G__74; continue; };break; } }); -f34["cljs$lang$maxFixedArity"] = 2; -f34["cljs$lang$applyTo"] = (function (seq37) { -let G__3875 = squint_core.first(seq37); -let seq3776 = next(seq37); -let G__3977 = squint_core.first(seq3776); -let seq3778 = next(seq3776); -let self__26573__auto__79 = this; -return self__26573__auto__79.cljs$core$IFn$_invoke$arity$variadic(G__3875, G__3977, seq3778); +f36["cljs$lang$maxFixedArity"] = 2; +f36["cljs$lang$applyTo"] = (function (seq39) { +let G__4077 = squint_core.first(seq39); +let seq3978 = next(seq39); +let G__4179 = squint_core.first(seq3978); +let seq3980 = next(seq3978); +let self__26573__auto__81 = this; +return self__26573__auto__81.cljs$core$IFn$_invoke$arity$variadic(G__4077, G__4179, seq3980); }); -return f34; +return f36; })() ; var update_selected_lines = (function (state, f) { -let at_line80 = squint_core.atom(-1); -let doc81 = state["doc"]; -return state.changeByRange((function (p__82) { -let map__8384 = p__82; -let range85 = map__8384; -let from86 = squint_core.get(map__8384, "from"); -let to87 = squint_core.get(map__8384, "to"); -let anchor88 = squint_core.get(map__8384, "anchor"); -let head89 = squint_core.get(map__8384, "head"); -let changes90 = []; -let line91 = doc81.lineAt(from86); +let at_line82 = squint_core.atom(-1); +let doc83 = state["doc"]; +return state.changeByRange((function (p__84) { +let map__8586 = p__84; +let range87 = map__8586; +let from88 = squint_core.get(map__8586, "from"); +let to89 = squint_core.get(map__8586, "to"); +let anchor90 = squint_core.get(map__8586, "anchor"); +let head91 = squint_core.get(map__8586, "head"); +let changes92 = []; +let line93 = doc83.lineAt(from88); while(true){ -let map__9293 = line91; -let line_number94 = squint_core.get(map__9293, "number"); -let line_to95 = squint_core.get(map__9293, "to"); -if ((line91["number"] > squint_core.deref(at_line80))) { -squint_core.reset_BANG_(at_line80, line_number94); -f(line91, changes90, range85)}; -let temp__27646__auto__96 = ((to87 > line_to95) && guard(doc81.lineAt((line_to95 + 1)), (function (_PERCENT_1) { -return (_PERCENT_1["number"] > line_number94); +let map__9495 = line93; +let line_number96 = squint_core.get(map__9495, "number"); +let line_to97 = squint_core.get(map__9495, "to"); +if ((line93["number"] > squint_core.deref(at_line82))) { +squint_core.reset_BANG_(at_line82, line_number96); +f(line93, changes92, range87)}; +let temp__27646__auto__98 = ((to89 > line_to97) && guard(doc83.lineAt((line_to97 + 1)), (function (_PERCENT_1) { +return (_PERCENT_1["number"] > line_number96); }))); -if (temp__27646__auto__96) { -let next_line97 = temp__27646__auto__96; -let G__98 = next_line97; -line91 = G__98; +if (temp__27646__auto__98) { +let next_line99 = temp__27646__auto__98; +let G__100 = next_line99; +line93 = G__100; continue; } else { -let change_set99 = state.changes(changes90); -return ({ "changes": changes90, "range": EditorSelection.range(change_set99.mapPos(anchor88, 1), change_set99.mapPos(head89, 1)) });};break; +let change_set101 = state.changes(changes92); +return ({ "changes": changes92, "range": EditorSelection.range(change_set101.mapPos(anchor90, 1), change_set101.mapPos(head91, 1)) });};break; } })); }) ; -var iter_changed_lines = (function (p__100, f) { -let map__101103 = p__100; -let tr104 = map__101103; -let map__102105 = squint_core.get(map__101103, "state"); -let state106 = map__102105; -let doc107 = squint_core.get(map__102105, "doc"); -let changes108 = squint_core.get(map__101103, "changes"); -let effects109 = squint_core.get(map__101103, "effects"); -let selection110 = squint_core.get(map__101103, "selection"); -let at_line111 = squint_core.atom(-1); -let next_changes112 = []; -let _113 = changes108.iterChanges((function (_from_a, _to_a, from_b, to_b, _inserted) { -let map__114115 = doc107.lineAt(from_b); -let line116 = map__114115; -let line_number117 = squint_core.get(map__114115, "number"); -let line_to118 = squint_core.get(map__114115, "to"); -let line119 = line116; +var iter_changed_lines = (function (p__102, f) { +let map__103105 = p__102; +let tr106 = map__103105; +let map__104107 = squint_core.get(map__103105, "state"); +let state108 = map__104107; +let doc109 = squint_core.get(map__104107, "doc"); +let changes110 = squint_core.get(map__103105, "changes"); +let effects111 = squint_core.get(map__103105, "effects"); +let selection112 = squint_core.get(map__103105, "selection"); +let at_line113 = squint_core.atom(-1); +let next_changes114 = []; +let _115 = changes110.iterChanges((function (_from_a, _to_a, from_b, to_b, _inserted) { +let map__116117 = doc109.lineAt(from_b); +let line118 = map__116117; +let line_number119 = squint_core.get(map__116117, "number"); +let line_to120 = squint_core.get(map__116117, "to"); +let line121 = line118; while(true){ -if ((line_number117 > squint_core.deref(at_line111))) { -squint_core.reset_BANG_(at_line111, line_number117); -f(line119, next_changes112)}; -if ((to_b <= line_to118)) { +if ((line_number119 > squint_core.deref(at_line113))) { +squint_core.reset_BANG_(at_line113, line_number119); +f(line121, next_changes114)}; +if ((to_b <= line_to120)) { return null;} else { -let next_line120 = doc107.lineAt((line_to118 + 1)); -if ((next_line120 && (next_line120["number"] > line119["number"]))) { -let G__121 = next_line120; -line119 = G__121; +let next_line122 = doc109.lineAt((line_to120 + 1)); +if ((next_line122 && (next_line122["number"] > line121["number"]))) { +let G__123 = next_line122; +line121 = G__123; continue; }};break; } })); -let next_changeset122 = state106.changes(next_changes112); -if (squint_core.seq(next_changes112)) { -let G__123124 = squint_core.assoc_BANG_(squint_core.select_keys(tr104, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes108.compose(next_changeset122)); -let G__123125 = (selection110) ? (squint_core.assoc_BANG_(G__123124, "selection", state106["selection"].map(next_changeset122))) : (G__123124); -if (effects109) { -return squint_core.assoc_BANG_(G__123125, "effects", StateEffect.mapEffects(effects109, next_changeset122));} else { -return G__123125;}} else { -return tr104;} +let next_changeset124 = state108.changes(next_changes114); +if (squint_core.seq(next_changes114)) { +let G__125126 = squint_core.assoc_BANG_(squint_core.select_keys(tr106, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes110.compose(next_changeset124)); +let G__125127 = (selection112) ? (squint_core.assoc_BANG_(G__125126, "selection", state108["selection"].map(next_changeset124))) : (G__125126); +if (effects111) { +return squint_core.assoc_BANG_(G__125127, "effects", StateEffect.mapEffects(effects111, next_changeset124));} else { +return G__125127;}} else { +return tr106;} }) ; var push_BANG_ = (function (arr, x) { -let G__126127 = arr; -G__126127.push(x); -return G__126127; +let G__128129 = arr; +G__128129.push(x); +return G__128129; }) ; squint_core.prn("util-loaded"); diff --git a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs index 96826f97..2ebd4518 100644 --- a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs +++ b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs @@ -1,10 +1,10 @@ (ns nextjournal.clojure-mode.extensions.close-brackets - (:require ["@codemirror/view" :as view] + (:require ["../node.mjs" :as n] + ["../util.mjs" :as u :refer [from-to]] ["@codemirror/state" :refer [EditorState Prec]] - ["../node.mjs" :as n] + ["@codemirror/view" :as view] #_[nextjournal.clojure-mode.node :as n] - ["../util.mjs" :as u :refer [from-to]] #_[nextjournal.clojure-mode.util :as u :refer [from-to]] [clojure.string :as str])) @@ -33,33 +33,32 @@ (let [^js range (get-in state [:selection :ranges 0])] (and (.-empty range) (= 0 (.-from range))))) (u/update-ranges state - #js{:annotations (u/user-event-annotation "delete")} - (fn [^:js {:as range :keys [head empty anchor]}] - (let [^:js {:as range from :from to :to} (from-to head anchor) - ^js node| (.resolveInner (n/tree state) from -1) ;; node immediately to the left of cursor - ^js parent (.-parent node|)] - (cond - - (or (not empty) ;; selection - (= "StringContent" (n/name (n/tree state from -1))) ;; inside a string - (and parent (not (n/balanced? parent)) (n/left-edge? node|))) ;; unbalanced left-paren - (u/deletion from to) - - ;; entering right edge of collection - skip - (and (n/right-edge? node|) (== from (n/end parent))) - {:cursor (dec from)} - - ;; inside left edge of collection - remove or stop - (and (or (n/start-edge? node|) - (n/same-edge? node|)) (== (n/start node|) (n/start parent))) - (if (n/empty? (n/up node|)) - ;; remove empty collection - {:cursor (n/start parent) - :changes [(from-to (n/start parent) (n/end parent))]} - ;; stop cursor at inner-left of collection - {:cursor from}) - - :else (backspace-backoff state from to))))))) + #js{:annotations (u/user-event-annotation "delete")} + (fn [^:js {:as _range :keys [head empty anchor]}] + (let [^:js {:as _range from :from to :to} (from-to head anchor) + ^js node| (.resolveInner (n/tree state) from -1) ;; node immediately to the left of cursor + ^js parent (.-parent node|)] + (cond + (or (not empty) ;; selection + (= "StringContent" (n/name (n/tree state from -1))) ;; inside a string + (and parent (not (n/balanced? parent)) (n/left-edge? node|))) ;; unbalanced left-paren + (u/deletion from to) + + ;; entering right edge of collection - skip + (and (n/right-edge? node|) (== from (n/end parent))) + {:cursor (dec from)} + + ;; inside left edge of collection - remove or stop + (and (or (n/start-edge? node|) + (n/same-edge? node|)) (== (n/start node|) (n/start parent))) + (if (n/empty? (n/up node|)) + ;; remove empty collection + (doto {:cursor (n/start parent) + :changes [(from-to (n/start parent) (n/end parent))]} + println) + ;; stop cursor at inner-left of collection + {:cursor from}) + :else (backspace-backoff state from to))))))) (def coll-pairs {"(" ")" "[" "]" @@ -69,61 +68,61 @@ (defn handle-open [^EditorState state ^string open] (let [^string close (get coll-pairs open)] (u/update-ranges state - #js{:annotations (u/user-event-annotation "input")} - (fn [^:js {:keys [from to head anchor empty]}] - (cond - (in-string? state from) - (if (= open \") - (u/insertion head "\\\"") - (u/insertion from to open)) + #js{:annotations (u/user-event-annotation "input")} + (fn [^:js {:keys [from to head anchor empty]}] + (cond + (in-string? state from) + (if (= open \") + (u/insertion head "\\\"") + (u/insertion from to open)) ;; allow typing escaped bracket - (escaped? state from) - (u/insertion from to open) - :else - (if empty - {:changes {:insert (str open close) - :from head} - :cursor (+ head (count open))} + (escaped? state from) + (u/insertion from to open) + :else + (if empty + {:changes {:insert (str open close) + :from head} + :cursor (+ head (count open))} ;; wrap selections with brackets - {:changes [{:insert open :from from} - {:insert close :from to}] - :from-to [(+ anchor (count open)) (+ head (count open))]})))))) + {:changes [{:insert open :from from} + {:insert close :from to}] + :from-to [(+ anchor (count open)) (+ head (count open))]})))))) (defn handle-close [state key-name] (u/update-ranges state - #js{:annotations (u/user-event-annotation "input")} - (fn [^:js {:as range :keys [empty head from to]}] - (if (or (in-string? state from) - (escaped? state from)) - (u/insertion from to key-name) - (when empty - (or - ;; close unbalanced (open) collection - (let [unbalanced (some-> - (n/tree state head -1) - (n/ancestors) - (->> (filter (every-pred n/coll? (complement n/balanced?)))) - first) - closing (some-> unbalanced n/down n/closed-by) - pos (some-> unbalanced n/end)] - (when (and closing (= closing key-name)) - {:changes {:from pos - :insert closing} - :cursor (inc pos)})) - - ;; jump to next closing bracket - (when-let [close-node-end - (when-let [^js cursor (-> state n/tree - (n/terminal-cursor head 1))] - (loop [] - (if (n/right-edge-type? (.-type cursor)) - (n/end cursor) - (when (.next cursor) - (recur)))))] - {:cursor close-node-end}) - ;; no-op - {:cursor head} - #_(u/insertion head key-name))))))) + #js{:annotations (u/user-event-annotation "input")} + (fn [^:js {:as _range :keys [empty head from to]}] + (if (or (in-string? state from) + (escaped? state from)) + (u/insertion from to key-name) + (when empty + (or + ;; close unbalanced (open) collection + (let [unbalanced (some-> + (n/tree state head -1) + (n/ancestors) + (->> (filter (every-pred n/coll? (complement n/balanced?)))) + first) + closing (some-> unbalanced n/down n/closed-by) + pos (some-> unbalanced n/end)] + (when (and closing (= closing key-name)) + {:changes {:from pos + :insert closing} + :cursor (inc pos)})) + + ;; jump to next closing bracket + (when-let [close-node-end + (when-let [^js cursor (-> state n/tree + (n/terminal-cursor head 1))] + (loop [] + (if (n/right-edge-type? (.-type cursor)) + (n/end cursor) + (when (.next cursor) + (recur)))))] + {:cursor close-node-end}) + ;; no-op + {:cursor head} + #_(u/insertion head key-name))))))) (defn handle-backspace-cmd [^:js {:as view :keys [state]}] (u/dispatch-some view (handle-backspace state))) @@ -156,9 +155,9 @@ {:key "(" :run (guard-scope (handle-open-cmd "("))} {:key "[" :run (guard-scope (handle-open-cmd "["))} {:key "{" :run (guard-scope (handle-open-cmd "{"))} - {:key \" :run (guard-scope (handle-open-cmd \"))} - {:key \) :run (guard-scope (handle-close-cmd \)))} - {:key \] :run (guard-scope (handle-close-cmd \]))} - {:key \} :run (guard-scope (handle-close-cmd \}))}]))) + {:key \" :run (guard-scope (handle-open-cmd \"))} + {:key \) :run (guard-scope (handle-close-cmd \)))} + {:key \] :run (guard-scope (handle-close-cmd \]))} + {:key \} :run (guard-scope (handle-close-cmd \}))}]))) (prn :close-brackets-loaded) diff --git a/src-squint/nextjournal/clojure_mode/node.cljs b/src-squint/nextjournal/clojure_mode/node.cljs index 3ce11861..c92af5a3 100644 --- a/src-squint/nextjournal/clojure_mode/node.cljs +++ b/src-squint/nextjournal/clojure_mode/node.cljs @@ -53,11 +53,12 @@ (defn ^js up [node] (.-parent ^js node)) (defn ^js down [node] - {:pre [(not (fn? (.-lastChild ^js node)))]} + ;; TODO: fix in squint + #_{:pre [(not (fn? (.-lastChild ^js node)))]} (.-firstChild ^js node)) (defn ^js down-last [node] - {:pre [(not (fn? (.-lastChild ^js node)))]} + #_{:pre [(not (fn? (.-lastChild ^js node)))]} (.-lastChild ^js node)) (defn ^number depth [^js node] diff --git a/src-squint/nextjournal/clojure_mode/util.cljs b/src-squint/nextjournal/clojure_mode/util.cljs index af98e45b..60b830e7 100644 --- a/src-squint/nextjournal/clojure_mode/util.cljs +++ b/src-squint/nextjournal/clojure_mode/util.cljs @@ -56,9 +56,12 @@ range changes]} (guard update-map map?) change-desc (when changes (.changes state changes))] + (js/console.log "map-cursor range" range) + (js/console.log "mapped?" mapped) + (js/console.log "curos?" cursor) (cond-> #js{:range (or range (cond mapped (sel/cursor (.mapPos change-desc mapped)) - cursor (sel/cursor cursor) + (some? cursor) (sel/cursor cursor) from-to (sel/range (get from-to 0) (get from-to 1))) original-range)} change-desc (doto (aset :changes change-desc))))) @@ -71,7 +74,8 @@ (->> (fn [range] (js/console.log "range" range) (or (when-some [result (f range)] - (map-cursor range state result)) + (doto (map-cursor range state result) + (->> (println "mapped")))) #js{:range range})) (.changeByRange state) (#(js/Object.assign % tr-specs)) diff --git a/src/nextjournal/clojure_mode/extensions/close_brackets.cljs b/src/nextjournal/clojure_mode/extensions/close_brackets.cljs index d79d9dcc..a27142c6 100644 --- a/src/nextjournal/clojure_mode/extensions/close_brackets.cljs +++ b/src/nextjournal/clojure_mode/extensions/close_brackets.cljs @@ -58,8 +58,9 @@ (n/same-edge? node|)) (== (n/start node|) (n/start parent))) (if (n/empty? (n/up node|)) ;; remove empty collection - {:cursor (n/start parent) - :changes [(from-to (n/start parent) (n/end parent))]} + (doto {:cursor (n/start parent) + :changes [(from-to (n/start parent) (n/end parent))]} + (-> clj->js js/console.log)) ;; stop cursor at inner-left of collection {:cursor from}) diff --git a/src/nextjournal/clojure_mode/util.cljs b/src/nextjournal/clojure_mode/util.cljs index 8f021f36..93aeb0c5 100644 --- a/src/nextjournal/clojure_mode/util.cljs +++ b/src/nextjournal/clojure_mode/util.cljs @@ -61,6 +61,9 @@ range changes]} (guard update-map map?) change-desc (when changes (.changes state (clj->js changes)))] + (js/console.log "map-cursor range" range) + (js/console.log "mapped?" mapped) + (js/console.log "curos?" cursor) (cond-> #js{:range (or range (cond mapped (sel/cursor (.mapPos change-desc mapped)) cursor (sel/cursor cursor) @@ -74,8 +77,10 @@ (update-ranges state nil f)) ([^js state tr-specs f ] (->> (fn [range] + (js/console.log "range" range) (or (when-some [result (f range)] - (map-cursor range state result)) + (doto (map-cursor range state result) + (->> (js/console.log "mapped")))) #js{:range range})) (.changeByRange state) (#(j/extend! % tr-specs)) From 8cc9c4e853a43954b6fc295fb6264529e861dcb3 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 15:10:36 +0200 Subject: [PATCH 18/80] remove println --- .../nextjournal/clojure_mode/util.mjs | 240 +++++++++--------- src-squint/nextjournal/clojure_mode/util.cljs | 7 +- src/nextjournal/clojure_mode/util.cljs | 7 +- 3 files changed, 119 insertions(+), 135 deletions(-) diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs index e75d0806..12ce9b6e 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/util.mjs @@ -86,9 +86,6 @@ let from_to18 = squint_core.get(map__1415, "from-to"); let range19 = squint_core.get(map__1415, "range"); let changes20 = squint_core.get(map__1415, "changes"); let change_desc21 = (changes20) ? (state.changes(changes20)) : (null); -console.log("map-cursor range", range19); -console.log("mapped?", mapped16); -console.log("curos?", cursor17); let G__2223 = ({ "range": (range19 || (mapped16) ? (sel.cursor(change_desc21.mapPos(mapped16))) : ((squint_core.some_QMARK_(cursor17)) ? (sel.cursor(cursor17)) : ((from_to18) ? (sel.range(squint_core.get(from_to18, 0), squint_core.get(from_to18, 1))) : (null))) || original_range) }); if (change_desc21) { let G__2425 = G__2223; @@ -116,15 +113,12 @@ f26["cljs$core$IFn$_invoke$arity$3"] = (function (state, tr_specs, f) { return state.update((function (_PERCENT_1) { return Object.assign(_PERCENT_1, tr_specs); })(state.changeByRange((function (range) { -console.log("range", range); return ((function () { let temp__27794__auto__32 = f(range); if (squint_core.nil_QMARK_(temp__27794__auto__32)) { return null;} else { let result33 = temp__27794__auto__32; -let G__3435 = map_cursor(range, state, result33); -squint_core.println("mapped", G__3435); -return G__3435;} +return map_cursor(range, state, result33);} })() || ({ "range": range })); })))); }); @@ -139,159 +133,159 @@ return dispatch(state.update(({ "changes": changes })));} }) ; var update_lines = (function () { - let f36 = (function (var_args) { -let args3742 = []; -let len__26551__auto__43 = arguments["length"]; -let i3844 = 0; + let f34 = (function (var_args) { +let args3540 = []; +let len__26551__auto__41 = arguments["length"]; +let i3642 = 0; while(true){ -if ((i3844 < len__26551__auto__43)) { -args3742.push((arguments[i3844])); -let G__45 = (i3844 + 1); -i3844 = G__45; +if ((i3642 < len__26551__auto__41)) { +args3540.push((arguments[i3642])); +let G__43 = (i3642 + 1); +i3642 = G__43; continue; };break; } ; -let argseq__26872__auto__46 = ((2 < args3742["length"])) ? (args3742.slice(2)) : (null); -return f36.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__26872__auto__46); +let argseq__26872__auto__44 = ((2 < args3540["length"])) ? (args3540.slice(2)) : (null); +return f34.cljs$core$IFn$_invoke$arity$variadic((arguments[0]), (arguments[1]), argseq__26872__auto__44); }); -f36["cljs$core$IFn$_invoke$arity$variadic"] = (function (state, f, p__47) { -let vec__4852 = p__47; -let map__5153 = squint_core.nth(vec__4852, 0, null); -let from54 = squint_core.get(map__5153, "from", 0); -let to55 = squint_core.get(map__5153, "to"); -let spec56 = squint_core.get(map__5153, "spec"); -let iterator57 = state["doc"].iter(); -let result58 = iterator57.next(); -let changes59 = []; -let from_pos60 = from54; -let line_num61 = 1; +f34["cljs$core$IFn$_invoke$arity$variadic"] = (function (state, f, p__45) { +let vec__4650 = p__45; +let map__4951 = squint_core.nth(vec__4650, 0, null); +let from52 = squint_core.get(map__4951, "from", 0); +let to53 = squint_core.get(map__4951, "to"); +let spec54 = squint_core.get(map__4951, "spec"); +let iterator55 = state["doc"].iter(); +let result56 = iterator55.next(); +let changes57 = []; +let from_pos58 = from52; +let line_num59 = 1; while(true){ -let map__6263 = result58; -let done64 = squint_core.get(map__6263, "done"); -let lineBreak65 = squint_core.get(map__6263, "lineBreak"); -let value66 = squint_core.get(map__6263, "value"); -if ((done64 || (from54 > to55))) { -return state.update(Object.assign(({ "changes": state.changes(changes59) }), spec56));} else { -let G__67 = iterator57.next(); -let G__68 = (function () { - let temp__27646__auto__69 = (!lineBreak65 && f(from_pos60, value66, line_num61)); -if (temp__27646__auto__69) { -let change70 = temp__27646__auto__69; -let G__7172 = changes59; -G__7172.push(change70); -return G__7172;} else { -return changes59;} +let map__6061 = result56; +let done62 = squint_core.get(map__6061, "done"); +let lineBreak63 = squint_core.get(map__6061, "lineBreak"); +let value64 = squint_core.get(map__6061, "value"); +if ((done62 || (from52 > to53))) { +return state.update(Object.assign(({ "changes": state.changes(changes57) }), spec54));} else { +let G__65 = iterator55.next(); +let G__66 = (function () { + let temp__27646__auto__67 = (!lineBreak63 && f(from_pos58, value64, line_num59)); +if (temp__27646__auto__67) { +let change68 = temp__27646__auto__67; +let G__6970 = changes57; +G__6970.push(change68); +return G__6970;} else { +return changes57;} })(); -let G__73 = (from_pos60 + squint_core.count(value66)); -let G__74 = (function () { - let G__7576 = line_num61; -if (lineBreak65) { -return (G__7576 + 1);} else { -return G__7576;} +let G__71 = (from_pos58 + squint_core.count(value64)); +let G__72 = (function () { + let G__7374 = line_num59; +if (lineBreak63) { +return (G__7374 + 1);} else { +return G__7374;} })(); -result58 = G__67; -changes59 = G__68; -from_pos60 = G__73; -line_num61 = G__74; +result56 = G__65; +changes57 = G__66; +from_pos58 = G__71; +line_num59 = G__72; continue; };break; } }); -f36["cljs$lang$maxFixedArity"] = 2; -f36["cljs$lang$applyTo"] = (function (seq39) { -let G__4077 = squint_core.first(seq39); -let seq3978 = next(seq39); -let G__4179 = squint_core.first(seq3978); -let seq3980 = next(seq3978); -let self__26573__auto__81 = this; -return self__26573__auto__81.cljs$core$IFn$_invoke$arity$variadic(G__4077, G__4179, seq3980); +f34["cljs$lang$maxFixedArity"] = 2; +f34["cljs$lang$applyTo"] = (function (seq37) { +let G__3875 = squint_core.first(seq37); +let seq3776 = next(seq37); +let G__3977 = squint_core.first(seq3776); +let seq3778 = next(seq3776); +let self__26573__auto__79 = this; +return self__26573__auto__79.cljs$core$IFn$_invoke$arity$variadic(G__3875, G__3977, seq3778); }); -return f36; +return f34; })() ; var update_selected_lines = (function (state, f) { -let at_line82 = squint_core.atom(-1); -let doc83 = state["doc"]; -return state.changeByRange((function (p__84) { -let map__8586 = p__84; -let range87 = map__8586; -let from88 = squint_core.get(map__8586, "from"); -let to89 = squint_core.get(map__8586, "to"); -let anchor90 = squint_core.get(map__8586, "anchor"); -let head91 = squint_core.get(map__8586, "head"); -let changes92 = []; -let line93 = doc83.lineAt(from88); +let at_line80 = squint_core.atom(-1); +let doc81 = state["doc"]; +return state.changeByRange((function (p__82) { +let map__8384 = p__82; +let range85 = map__8384; +let from86 = squint_core.get(map__8384, "from"); +let to87 = squint_core.get(map__8384, "to"); +let anchor88 = squint_core.get(map__8384, "anchor"); +let head89 = squint_core.get(map__8384, "head"); +let changes90 = []; +let line91 = doc81.lineAt(from86); while(true){ -let map__9495 = line93; -let line_number96 = squint_core.get(map__9495, "number"); -let line_to97 = squint_core.get(map__9495, "to"); -if ((line93["number"] > squint_core.deref(at_line82))) { -squint_core.reset_BANG_(at_line82, line_number96); -f(line93, changes92, range87)}; -let temp__27646__auto__98 = ((to89 > line_to97) && guard(doc83.lineAt((line_to97 + 1)), (function (_PERCENT_1) { -return (_PERCENT_1["number"] > line_number96); +let map__9293 = line91; +let line_number94 = squint_core.get(map__9293, "number"); +let line_to95 = squint_core.get(map__9293, "to"); +if ((line91["number"] > squint_core.deref(at_line80))) { +squint_core.reset_BANG_(at_line80, line_number94); +f(line91, changes90, range85)}; +let temp__27646__auto__96 = ((to87 > line_to95) && guard(doc81.lineAt((line_to95 + 1)), (function (_PERCENT_1) { +return (_PERCENT_1["number"] > line_number94); }))); -if (temp__27646__auto__98) { -let next_line99 = temp__27646__auto__98; -let G__100 = next_line99; -line93 = G__100; +if (temp__27646__auto__96) { +let next_line97 = temp__27646__auto__96; +let G__98 = next_line97; +line91 = G__98; continue; } else { -let change_set101 = state.changes(changes92); -return ({ "changes": changes92, "range": EditorSelection.range(change_set101.mapPos(anchor90, 1), change_set101.mapPos(head91, 1)) });};break; +let change_set99 = state.changes(changes90); +return ({ "changes": changes90, "range": EditorSelection.range(change_set99.mapPos(anchor88, 1), change_set99.mapPos(head89, 1)) });};break; } })); }) ; -var iter_changed_lines = (function (p__102, f) { -let map__103105 = p__102; -let tr106 = map__103105; -let map__104107 = squint_core.get(map__103105, "state"); -let state108 = map__104107; -let doc109 = squint_core.get(map__104107, "doc"); -let changes110 = squint_core.get(map__103105, "changes"); -let effects111 = squint_core.get(map__103105, "effects"); -let selection112 = squint_core.get(map__103105, "selection"); -let at_line113 = squint_core.atom(-1); -let next_changes114 = []; -let _115 = changes110.iterChanges((function (_from_a, _to_a, from_b, to_b, _inserted) { -let map__116117 = doc109.lineAt(from_b); -let line118 = map__116117; -let line_number119 = squint_core.get(map__116117, "number"); -let line_to120 = squint_core.get(map__116117, "to"); -let line121 = line118; +var iter_changed_lines = (function (p__100, f) { +let map__101103 = p__100; +let tr104 = map__101103; +let map__102105 = squint_core.get(map__101103, "state"); +let state106 = map__102105; +let doc107 = squint_core.get(map__102105, "doc"); +let changes108 = squint_core.get(map__101103, "changes"); +let effects109 = squint_core.get(map__101103, "effects"); +let selection110 = squint_core.get(map__101103, "selection"); +let at_line111 = squint_core.atom(-1); +let next_changes112 = []; +let _113 = changes108.iterChanges((function (_from_a, _to_a, from_b, to_b, _inserted) { +let map__114115 = doc107.lineAt(from_b); +let line116 = map__114115; +let line_number117 = squint_core.get(map__114115, "number"); +let line_to118 = squint_core.get(map__114115, "to"); +let line119 = line116; while(true){ -if ((line_number119 > squint_core.deref(at_line113))) { -squint_core.reset_BANG_(at_line113, line_number119); -f(line121, next_changes114)}; -if ((to_b <= line_to120)) { +if ((line_number117 > squint_core.deref(at_line111))) { +squint_core.reset_BANG_(at_line111, line_number117); +f(line119, next_changes112)}; +if ((to_b <= line_to118)) { return null;} else { -let next_line122 = doc109.lineAt((line_to120 + 1)); -if ((next_line122 && (next_line122["number"] > line121["number"]))) { -let G__123 = next_line122; -line121 = G__123; +let next_line120 = doc107.lineAt((line_to118 + 1)); +if ((next_line120 && (next_line120["number"] > line119["number"]))) { +let G__121 = next_line120; +line119 = G__121; continue; }};break; } })); -let next_changeset124 = state108.changes(next_changes114); -if (squint_core.seq(next_changes114)) { -let G__125126 = squint_core.assoc_BANG_(squint_core.select_keys(tr106, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes110.compose(next_changeset124)); -let G__125127 = (selection112) ? (squint_core.assoc_BANG_(G__125126, "selection", state108["selection"].map(next_changeset124))) : (G__125126); -if (effects111) { -return squint_core.assoc_BANG_(G__125127, "effects", StateEffect.mapEffects(effects111, next_changeset124));} else { -return G__125127;}} else { -return tr106;} +let next_changeset122 = state106.changes(next_changes112); +if (squint_core.seq(next_changes112)) { +let G__123124 = squint_core.assoc_BANG_(squint_core.select_keys(tr104, ["annotations", "scrollIntoView", "reconfigure"]), "changes", changes108.compose(next_changeset122)); +let G__123125 = (selection110) ? (squint_core.assoc_BANG_(G__123124, "selection", state106["selection"].map(next_changeset122))) : (G__123124); +if (effects109) { +return squint_core.assoc_BANG_(G__123125, "effects", StateEffect.mapEffects(effects109, next_changeset122));} else { +return G__123125;}} else { +return tr104;} }) ; var push_BANG_ = (function (arr, x) { -let G__128129 = arr; -G__128129.push(x); -return G__128129; +let G__126127 = arr; +G__126127.push(x); +return G__126127; }) ; squint_core.prn("util-loaded"); diff --git a/src-squint/nextjournal/clojure_mode/util.cljs b/src-squint/nextjournal/clojure_mode/util.cljs index 60b830e7..fc7d4479 100644 --- a/src-squint/nextjournal/clojure_mode/util.cljs +++ b/src-squint/nextjournal/clojure_mode/util.cljs @@ -56,9 +56,6 @@ range changes]} (guard update-map map?) change-desc (when changes (.changes state changes))] - (js/console.log "map-cursor range" range) - (js/console.log "mapped?" mapped) - (js/console.log "curos?" cursor) (cond-> #js{:range (or range (cond mapped (sel/cursor (.mapPos change-desc mapped)) (some? cursor) (sel/cursor cursor) @@ -72,10 +69,8 @@ (update-ranges state nil f)) ([^js state tr-specs f ] (->> (fn [range] - (js/console.log "range" range) (or (when-some [result (f range)] - (doto (map-cursor range state result) - (->> (println "mapped")))) + (map-cursor range state result)) #js{:range range})) (.changeByRange state) (#(js/Object.assign % tr-specs)) diff --git a/src/nextjournal/clojure_mode/util.cljs b/src/nextjournal/clojure_mode/util.cljs index 93aeb0c5..8f021f36 100644 --- a/src/nextjournal/clojure_mode/util.cljs +++ b/src/nextjournal/clojure_mode/util.cljs @@ -61,9 +61,6 @@ range changes]} (guard update-map map?) change-desc (when changes (.changes state (clj->js changes)))] - (js/console.log "map-cursor range" range) - (js/console.log "mapped?" mapped) - (js/console.log "curos?" cursor) (cond-> #js{:range (or range (cond mapped (sel/cursor (.mapPos change-desc mapped)) cursor (sel/cursor cursor) @@ -77,10 +74,8 @@ (update-ranges state nil f)) ([^js state tr-specs f ] (->> (fn [range] - (js/console.log "range" range) (or (when-some [result (f range)] - (doto (map-cursor range state result) - (->> (js/console.log "mapped")))) + (map-cursor range state result)) #js{:range range})) (.changeByRange state) (#(j/extend! % tr-specs)) From 32cc525e1d3d8480cc388be6cf97f7d6c95ada78 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 15:12:25 +0200 Subject: [PATCH 19/80] wip --- .../extensions/close_brackets.mjs | 164 +++++++++--------- .../extensions/close_brackets.cljs | 7 +- .../extensions/close_brackets.cljs | 5 +- 3 files changed, 86 insertions(+), 90 deletions(-) diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs index 00afe906..c89cb95a 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs @@ -51,9 +51,7 @@ if ((n.right_edge_QMARK_(node_BAR_21) && (from19 == n.end(parent22)))) { return ({ "cursor": (from19 - 1) });} else { if (((n.start_edge_QMARK_(node_BAR_21) || n.same_edge_QMARK_(node_BAR_21)) && (n.start(node_BAR_21) == n.start(parent22)))) { if (n.empty_QMARK_(n.up(node_BAR_21))) { -let G__2324 = ({ "cursor": n.start(parent22), "changes": [from_to(n.start(parent22), n.end(parent22))] }); -squint_core.println(G__2324); -return G__2324;} else { +return ({ "cursor": n.start(parent22), "changes": [from_to(n.start(parent22), n.end(parent22))] });} else { return ({ "cursor": from19 });}} else { if ("else") { return backspace_backoff(state6, from19, to20);} else { @@ -64,126 +62,126 @@ return null;}}}} var coll_pairs = ({ "(": ")", "[": "]", "{": "}", "\"": "\"" }) ; var handle_open = (function (state, open) { -let close25 = squint_core.get(coll_pairs, open); -return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__26) { -let map__2728 = p__26; -let from29 = squint_core.get(map__2728, "from"); -let to30 = squint_core.get(map__2728, "to"); -let head31 = squint_core.get(map__2728, "head"); -let anchor32 = squint_core.get(map__2728, "anchor"); -let empty33 = squint_core.get(map__2728, "empty"); -if (in_string_QMARK_(state, from29)) { +let close23 = squint_core.get(coll_pairs, open); +return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__24) { +let map__2526 = p__24; +let from27 = squint_core.get(map__2526, "from"); +let to28 = squint_core.get(map__2526, "to"); +let head29 = squint_core.get(map__2526, "head"); +let anchor30 = squint_core.get(map__2526, "anchor"); +let empty31 = squint_core.get(map__2526, "empty"); +if (in_string_QMARK_(state, from27)) { if ((open === "\"")) { -return u.insertion(head31, "\\\"");} else { -return u.insertion(from29, to30, open);}} else { -if (escaped_QMARK_(state, from29)) { -return u.insertion(from29, to30, open);} else { +return u.insertion(head29, "\\\"");} else { +return u.insertion(from27, to28, open);}} else { +if (escaped_QMARK_(state, from27)) { +return u.insertion(from27, to28, open);} else { if ("else") { -if (empty33) { -return ({ "changes": ({ "insert": squint_core.str(open, close25), "from": head31 }), "cursor": (head31 + squint_core.count(open)) });} else { -return ({ "changes": [({ "insert": open, "from": from29 }), ({ "insert": close25, "from": to30 })], "from-to": [(anchor32 + squint_core.count(open)), (head31 + squint_core.count(open))] });}} else { +if (empty31) { +return ({ "changes": ({ "insert": squint_core.str(open, close23), "from": head29 }), "cursor": (head29 + squint_core.count(open)) });} else { +return ({ "changes": [({ "insert": open, "from": from27 }), ({ "insert": close23, "from": to28 })], "from-to": [(anchor30 + squint_core.count(open)), (head29 + squint_core.count(open))] });}} else { return null;}}} })); }) ; var handle_close = (function (state, key_name) { -return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__34) { -let map__3536 = p__34; -let _range37 = map__3536; -let empty38 = squint_core.get(map__3536, "empty"); -let head39 = squint_core.get(map__3536, "head"); -let from40 = squint_core.get(map__3536, "from"); -let to41 = squint_core.get(map__3536, "to"); -if ((in_string_QMARK_(state, from40) || escaped_QMARK_(state, from40))) { -return u.insertion(from40, to41, key_name);} else { -if (empty38) { +return u.update_ranges(state, ({ "annotations": u.user_event_annotation("input") }), (function (p__32) { +let map__3334 = p__32; +let _range35 = map__3334; +let empty36 = squint_core.get(map__3334, "empty"); +let head37 = squint_core.get(map__3334, "head"); +let from38 = squint_core.get(map__3334, "from"); +let to39 = squint_core.get(map__3334, "to"); +if ((in_string_QMARK_(state, from38) || escaped_QMARK_(state, from38))) { +return u.insertion(from38, to39, key_name);} else { +if (empty36) { return ((function () { - let unbalanced42 = (function () { - let G__4344 = n.tree(state, head39, -1); -let G__4345 = (squint_core.nil_QMARK_(G__4344)) ? (null) : (n.ancestors(G__4344)); -let G__4346 = (squint_core.nil_QMARK_(G__4345)) ? (null) : (squint_core.filter(every_pred(n.coll_QMARK_, squint_core.complement(n.balanced_QMARK_)), G__4345)); -if (squint_core.nil_QMARK_(G__4346)) { + let unbalanced40 = (function () { + let G__4142 = n.tree(state, head37, -1); +let G__4143 = (squint_core.nil_QMARK_(G__4142)) ? (null) : (n.ancestors(G__4142)); +let G__4144 = (squint_core.nil_QMARK_(G__4143)) ? (null) : (squint_core.filter(every_pred(n.coll_QMARK_, squint_core.complement(n.balanced_QMARK_)), G__4143)); +if (squint_core.nil_QMARK_(G__4144)) { return null;} else { -return squint_core.first(G__4346);} +return squint_core.first(G__4144);} })(); -let closing47 = (function () { - let G__4849 = unbalanced42; -let G__4850 = (squint_core.nil_QMARK_(G__4849)) ? (null) : (n.down(G__4849)); -if (squint_core.nil_QMARK_(G__4850)) { +let closing45 = (function () { + let G__4647 = unbalanced40; +let G__4648 = (squint_core.nil_QMARK_(G__4647)) ? (null) : (n.down(G__4647)); +if (squint_core.nil_QMARK_(G__4648)) { return null;} else { -return n.closed_by(G__4850);} +return n.closed_by(G__4648);} })(); -let pos51 = (function () { - let G__5253 = unbalanced42; -if (squint_core.nil_QMARK_(G__5253)) { +let pos49 = (function () { + let G__5051 = unbalanced40; +if (squint_core.nil_QMARK_(G__5051)) { return null;} else { -return n.end(G__5253);} +return n.end(G__5051);} })(); -if ((closing47 && (closing47 === key_name))) { -return ({ "changes": ({ "from": pos51, "insert": closing47 }), "cursor": (pos51 + 1) });} +if ((closing45 && (closing45 === key_name))) { +return ({ "changes": ({ "from": pos49, "insert": closing45 }), "cursor": (pos49 + 1) });} })() || (function () { - let temp__27701__auto__54 = (function () { - let temp__27701__auto__55 = n.terminal_cursor(n.tree(state), head39, 1); -if (temp__27701__auto__55) { -let cursor56 = temp__27701__auto__55; + let temp__27701__auto__52 = (function () { + let temp__27701__auto__53 = n.terminal_cursor(n.tree(state), head37, 1); +if (temp__27701__auto__53) { +let cursor54 = temp__27701__auto__53; while(true){ -if (n.right_edge_type_QMARK_(cursor56["type"])) { -return n.end(cursor56);} else { -if (cursor56.next()) { +if (n.right_edge_type_QMARK_(cursor54["type"])) { +return n.end(cursor54);} else { +if (cursor54.next()) { continue; }};break; } } })(); -if (temp__27701__auto__54) { -let close_node_end57 = temp__27701__auto__54; -return ({ "cursor": close_node_end57 });} -})() || ({ "cursor": head39 }));}} +if (temp__27701__auto__52) { +let close_node_end55 = temp__27701__auto__52; +return ({ "cursor": close_node_end55 });} +})() || ({ "cursor": head37 }));}} })); }) ; -var handle_backspace_cmd = (function (p__58) { -let map__5960 = p__58; -let view61 = map__5960; -let state62 = squint_core.get(map__5960, "state"); -return u.dispatch_some(view61, handle_backspace(state62)); +var handle_backspace_cmd = (function (p__56) { +let map__5758 = p__56; +let view59 = map__5758; +let state60 = squint_core.get(map__5758, "state"); +return u.dispatch_some(view59, handle_backspace(state60)); }) ; var handle_open_cmd = (function (key_name) { -return function (p__63) { -let map__6465 = p__63; -let view66 = map__6465; -let state67 = squint_core.get(map__6465, "state"); -return u.dispatch_some(view66, handle_open(state67, key_name)); +return function (p__61) { +let map__6263 = p__61; +let view64 = map__6263; +let state65 = squint_core.get(map__6263, "state"); +return u.dispatch_some(view64, handle_open(state65, key_name)); }; }) ; var handle_close_cmd = (function (key_name) { -return function (p__68) { -let map__6970 = p__68; -let view71 = map__6970; -let state72 = squint_core.get(map__6970, "state"); -return u.dispatch_some(view71, handle_close(state72, key_name)); +return function (p__66) { +let map__6768 = p__66; +let view69 = map__6768; +let state70 = squint_core.get(map__6768, "state"); +return u.dispatch_some(view69, handle_close(state70, key_name)); }; }) ; var guard_scope = (function (cmd) { -return function (p__73) { -let map__7475 = p__73; -let view76 = map__7475; -let state77 = squint_core.get(map__7475, "state"); -if ((n.embedded_QMARK_(state77) || n.within_program_QMARK_(state77))) { -return cmd(view76);} else { +return function (p__71) { +let map__7273 = p__71; +let view74 = map__7273; +let state75 = squint_core.get(map__7273, "state"); +if ((n.embedded_QMARK_(state75) || n.within_program_QMARK_(state75))) { +return cmd(view74);} else { return false;} }; }) ; var extension = (function () { -return Prec.high(view.keymap.of([({ "key": "Backspace", "run": guard_scope((function (p__78) { -let map__7980 = p__78; -let view81 = map__7980; -let state82 = squint_core.get(map__7980, "state"); -return u.dispatch_some(view81, handle_backspace(state82)); +return Prec.high(view.keymap.of([({ "key": "Backspace", "run": guard_scope((function (p__76) { +let map__7778 = p__76; +let view79 = map__7778; +let state80 = squint_core.get(map__7778, "state"); +return u.dispatch_some(view79, handle_backspace(state80)); })) }), ({ "key": "(", "run": guard_scope(handle_open_cmd("(")) }), ({ "key": "[", "run": guard_scope(handle_open_cmd("[")) }), ({ "key": "{", "run": guard_scope(handle_open_cmd("{")) }), ({ "key": "\"", "run": guard_scope(handle_open_cmd("\"")) }), ({ "key": ")", "run": guard_scope(handle_close_cmd(")")) }), ({ "key": "]", "run": guard_scope(handle_close_cmd("]")) }), ({ "key": "}", "run": guard_scope(handle_close_cmd("}")) })])); }) ; diff --git a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs index 2ebd4518..8efb2495 100644 --- a/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs +++ b/src-squint/nextjournal/clojure_mode/extensions/close_brackets.cljs @@ -53,10 +53,9 @@ (n/same-edge? node|)) (== (n/start node|) (n/start parent))) (if (n/empty? (n/up node|)) ;; remove empty collection - (doto {:cursor (n/start parent) - :changes [(from-to (n/start parent) (n/end parent))]} - println) - ;; stop cursor at inner-left of collection + {:cursor (n/start parent) + :changes [(from-to (n/start parent) (n/end parent))]} + ;; stop cursor at inner-left of collection {:cursor from}) :else (backspace-backoff state from to))))))) diff --git a/src/nextjournal/clojure_mode/extensions/close_brackets.cljs b/src/nextjournal/clojure_mode/extensions/close_brackets.cljs index a27142c6..d79d9dcc 100644 --- a/src/nextjournal/clojure_mode/extensions/close_brackets.cljs +++ b/src/nextjournal/clojure_mode/extensions/close_brackets.cljs @@ -58,9 +58,8 @@ (n/same-edge? node|)) (== (n/start node|) (n/start parent))) (if (n/empty? (n/up node|)) ;; remove empty collection - (doto {:cursor (n/start parent) - :changes [(from-to (n/start parent) (n/end parent))]} - (-> clj->js js/console.log)) + {:cursor (n/start parent) + :changes [(from-to (n/start parent) (n/end parent))]} ;; stop cursor at inner-left of collection {:cursor from}) From 4a0ce8a688302da9c5c2bb088566918a7dfe47ae Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 15:15:06 +0200 Subject: [PATCH 20/80] depend on squint --- package.json | 2 +- yarn.lock | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 07248a77..57f3c99c 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,6 @@ "devDependencies": { "shadow-cljs": "2.19.5", "vite": "^4.4.9", - "squint-cljs": "../squint" + "squint-cljs": "0.1.19" } } diff --git a/yarn.lock b/yarn.lock index 034a08e2..a4d25766 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1072,8 +1072,10 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -squint-cljs@../squint: - version "0.1.18" +squint-cljs@0.1.19: + version "0.1.19" + resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.1.19.tgz#646aa78190d6c34619ad402fd646cf323c35524a" + integrity sha512-dB+RbCArxRZrOaAK7PMdbEjlXmUxBt7irPg5SMeyOIy81xRwBJn6ya9pHJZ9TrV4LPxwSxlJRNQsQK5Rpm8Dpg== stream-browserify@^2.0.1: version "2.0.2" From d860c7f62bb8ac9bfc3d8d1e4c385deaec66f039 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 15:15:39 +0200 Subject: [PATCH 21/80] runtime dep on squint --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 57f3c99c..c35dfb85 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "punycode": "2.1.1", "react": "^17.0.2", "react-dom": "^17.0.2", - "w3c-keyname": "^2.2.4" + "w3c-keyname": "^2.2.4", + "squint-cljs": "0.1.19" }, "scripts": { "watch": "bb copy-viewer-css && shadow-cljs -A:demo watch demo livedoc test", @@ -36,7 +37,6 @@ }, "devDependencies": { "shadow-cljs": "2.19.5", - "vite": "^4.4.9", - "squint-cljs": "0.1.19" + "vite": "^4.4.9" } } From 35dcb84454d1e22a62a7d5996b8be549e568674e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 17:11:36 +0200 Subject: [PATCH 22/80] wip --- package.json | 2 +- public/squint/js/main.mjs | 2 +- .../extensions/match_brackets.mjs | 24 +++--- .../extensions/selection_history.mjs | 81 ++++++++++++------- .../nextjournal/clojure_mode/node.mjs | 36 ++++----- .../extensions/match_brackets.cljs | 12 +-- .../extensions/selection_history.cljs | 3 +- src-squint/nextjournal/clojure_mode/node.cljs | 2 +- yarn.lock | 4 +- 9 files changed, 96 insertions(+), 70 deletions(-) diff --git a/package.json b/package.json index c35dfb85..d5144e28 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "w3c-keyname": "^2.2.4", - "squint-cljs": "0.1.19" + "squint-cljs": "../squint" }, "scripts": { "watch": "bb copy-viewer-css && shadow-cljs -A:demo watch demo livedoc test", diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 855eb307..904ddc5b 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -15,7 +15,7 @@ import { syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language' console.log(default_extensions); -let extensions = [ (syntaxHighlighting(defaultHighlightStyle)), ...default_extensions.slice(0,2) ] +let extensions = [ (syntaxHighlighting(defaultHighlightStyle)), ...default_extensions.slice(0,4) ] let state = EditorState.create( {doc: "(+ 1 2 3)", extensions: extensions }); let editorElt = document.querySelector('#editor'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs index 4f959d4b..e2dadac9 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs @@ -1,8 +1,8 @@ import * as squint_core from 'squint-cljs/core.js'; -import { StateField } from '@codemirror/state'; -import { EditorView, Decoration } from '@codemirror/view'; import * as n from '../node.mjs'; import * as u from '../util.mjs'; +import { StateField } from '@codemirror/state'; +import { EditorView, Decoration } from '@codemirror/view'; var base_theme = EditorView.baseTheme(({ "$matchingBracket": ({ "color": "#0b0" }), "$nonmatchingBracket": ({ "color": "#a22" }) })) ; var matching_mark = Decoration.mark(({ "class": "cm-matchingBracket" })) @@ -25,26 +25,26 @@ let map__1011 = p__9; let head12 = squint_core.get(map__1011, "head"); let empty13 = squint_core.get(map__1011, "empty"); return ((function () { - let temp__25187__auto__14 = (empty13 && squint_core.first(squint_core.filter(some_fn(n.start_edge_QMARK_, n.end_edge_QMARK_), [n.tree(state5, head12, -1), n.tree(state5, head12, 1)]))); -if (temp__25187__auto__14) { -let bracket15 = temp__25187__auto__14; -let temp__24970__auto__16 = ((n.start_edge_QMARK_(bracket15) && (n.start(bracket15) === n.start(n.up(bracket15))))) ? (u.guard(n.down_last(n.up(bracket15)), (function (_PERCENT_1) { + let temp__32100__auto__14 = (empty13 && squint_core.first(squint_core.filter(squint_core.some_fn(n.start_edge_QMARK_, n.end_edge_QMARK_), [n.tree(state5, head12, -1), n.tree(state5, head12, 1)]))); +if (temp__32100__auto__14) { +let bracket15 = temp__32100__auto__14; +let temp__32037__auto__16 = ((n.start_edge_QMARK_(bracket15) && (n.start(bracket15) === n.start(n.up(bracket15))))) ? (u.guard(n.down_last(n.up(bracket15)), (function (_PERCENT_1) { return (n.name(_PERCENT_1) === n.closed_by(bracket15)); }))) : (((n.end_edge_QMARK_(bracket15) && (n.end(bracket15) === n.end(n.up(bracket15))))) ? (u.guard(n.down(n.up(bracket15)), (function (_PERCENT_1) { return (n.name(_PERCENT_1) === n.opened_by(bracket15)); }))) : (null)); -if (temp__24970__auto__16) { -let other_bracket17 = temp__24970__auto__16; +if (temp__32037__auto__16) { +let other_bracket17 = temp__32037__auto__16; return squint_core.conj(out, mark_node(bracket15, matching_mark), mark_node(other_bracket17, matching_mark));} else { return squint_core.conj(out, mark_node(bracket15, nonmatching_mark));}} })() || (function () { - let temp__25187__auto__18 = (!n.closest(n.tree(state5, head12), n.string_QMARK_) && new Set(["]", ")", "}"])(tr4["state"]["doc"].slice(head12, (head12 + 1)).toString())); -if (temp__25187__auto__18) { -let _unparsed_bracket19 = temp__25187__auto__18; + let temp__32100__auto__18 = (!n.closest(n.tree(state5, head12), n.string_QMARK_) && squint_core.contains_QMARK_(new Set(["]", ")", "}"]), tr4["state"]["doc"].slice(head12, (head12 + 1)).toString())); +if (temp__32100__auto__18) { +let _unparsed_bracket19 = temp__32100__auto__18; return squint_core.conj(out, mark_node(n.from_to(head12, (head12 + 1)), nonmatching_mark));} })() || out); }), [], tr4["state"]["selection"]["ranges"]); -return Decoration.set(into_array(decos8), true);} else { +return Decoration.set(squint_core.into_array(decos8), true);} else { return deco;} }) })) ; diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs index 607a8ef2..d60f00b8 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs @@ -20,7 +20,34 @@ return !_PERCENT_1["empty"]; }), selection["ranges"]); }) ; -var selection_history_field = "Stores selection history" +var selection_history_field = StateField.define(({ "create": (function (state) { +return squint_core.list(({ "selection": state["selection"] })); +}), "update": (function (stack, p__1) { +let map__24 = p__1; +let tr5 = map__24; +let map__36 = squint_core.get(map__24, "state"); +let selection7 = squint_core.get(map__36, "selection"); +let docChanged8 = squint_core.get(map__24, "docChanged"); +let previous_position9 = squint_core.first(keep_indexed((function (i, x) { +if (sel.eq_QMARK_(squint_core.get(x, "selection"), selection7)) { +return i;} +}), stack)); +if (docChanged8) { +return squint_core.list(({ "selection": selection7, "event": u.get_user_event_annotation(tr5) }));} else { +if (!something_selected_QMARK_(selection7)) { +return squint_core.list(({ "selection": selection7, "event": u.get_user_event_annotation(tr5) }));} else { +if (previous_position9) { +let vec__1013 = squint_core.drop(previous_position9, stack); +let seq__1114 = squint_core.seq(vec__1013); +let first__1215 = squint_core.first(seq__1114); +let seq__1116 = next(seq__1114); +let f17 = first__1215; +let more18 = seq__1116; +return squint_core.cons(squint_core.assoc(f17, "prev-event", squint_core.get(squint_core.first(stack), "event")), more18);} else { +if ("else") { +return squint_core.cons(({ "selection": selection7, "event": u.get_user_event_annotation(tr5) }), stack);} else { +return null;}}}} +}) })) ; var extension = (function () { return selection_history_field; @@ -31,43 +58,43 @@ return state.field(selection_history_field); }) ; var grow_1 = (function (state, start, end) { -let node1 = n.nearest_touching(state, end, -1); -return squint_core.first(squint_core.filter((function (p__2) { -let map__34 = p__2; -let a_start5 = squint_core.get(map__34, "from"); -let a_end6 = squint_core.get(map__34, "to"); -return ((a_start5 <= start) && (a_end6 >= end) && !((a_start5 == start) && (a_end6 == end))); -}), squint_core.cons(node1, squint_core.mapcat(juxt(n.inner_span, squint_core.identity), n.ancestors(node1))))); +let node19 = n.nearest_touching(state, end, -1); +return squint_core.first(squint_core.filter((function (p__20) { +let map__2122 = p__20; +let a_start23 = squint_core.get(map__2122, "from"); +let a_end24 = squint_core.get(map__2122, "to"); +return ((a_start23 <= start) && (a_end24 >= end) && !((a_start23 == start) && (a_end24 == end))); +}), squint_core.cons(node19, squint_core.mapcat(juxt(n.inner_span, squint_core.identity), n.ancestors(node19))))); }) ; var selection_grow_STAR_ = (function (state) { -return u.update_ranges(state, ({ "annotations": event_annotation }), (function (p__7) { -let map__89 = p__7; -let range10 = map__89; -let from11 = squint_core.get(map__89, "from"); -let to12 = squint_core.get(map__89, "to"); -let empty13 = squint_core.get(map__89, "empty"); -if (empty13) { +return u.update_ranges(state, ({ "annotations": event_annotation }), (function (p__25) { +let map__2627 = p__25; +let range28 = map__2627; +let from29 = squint_core.get(map__2627, "from"); +let to30 = squint_core.get(map__2627, "to"); +let empty31 = squint_core.get(map__2627, "empty"); +if (empty31) { return ({ "range": ((function () { - let G__1415 = n.nearest_touching(state, from11, -1); -if (squint_core.nil_QMARK_(G__1415)) { + let G__3233 = n.nearest_touching(state, from29, -1); +if (squint_core.nil_QMARK_(G__3233)) { return null;} else { -return n.balanced_range(state, G__1415);} -})() || range10) });} else { +return n.balanced_range(state, G__3233);} +})() || range28) });} else { return ({ "range": ((function () { - let G__1617 = grow_1(state, from11, to12); -if (squint_core.nil_QMARK_(G__1617)) { + let G__3435 = grow_1(state, from29, to30); +if (squint_core.nil_QMARK_(G__3435)) { return null;} else { -return n.range(G__1617);} -})() || range10) });} +return n.range(G__3435);} +})() || range28) });} })); }) ; var selection_return_STAR_ = (function (state) { -let temp__24970__auto__18 = squint_core.get(squint_core.second(stack(state)), "selection"); -if (temp__24970__auto__18) { -let selection19 = temp__24970__auto__18; -return state.update(({ "selection": selection19, "annotations": event_annotation }));} else { +let temp__32037__auto__36 = squint_core.get(squint_core.second(stack(state)), "selection"); +if (temp__32037__auto__36) { +let selection37 = temp__32037__auto__36; +return state.update(({ "selection": selection37, "annotations": event_annotation }));} else { return u.update_ranges(state, ({ "annotations": event_annotation }), (function (range) { return ({ "cursor": range["from"] }); }));} diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs index 40a34dcc..e00d621d 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/node.mjs @@ -68,10 +68,10 @@ var depth = (function (node) { let node4 = node; let i5 = 0; while(true){ -let temp__27684__auto__6 = up(node4); -if (squint_core.nil_QMARK_(temp__27684__auto__6)) { +let temp__32064__auto__6 = up(node4); +if (squint_core.nil_QMARK_(temp__32064__auto__6)) { return i5;} else { -let parent7 = temp__27684__auto__6; +let parent7 = temp__32064__auto__6; let G__8 = parent7; let G__9 = (i5 + 1); node4 = G__8; @@ -250,21 +250,21 @@ return null;}}}}}}} ; var balanced_QMARK_ = (function (p__15) { let map__1617 = p__15; -let node18 = map__1617; +let _node18 = map__1617; let firstChild19 = squint_core.get(map__1617, "firstChild"); let lastChild20 = squint_core.get(map__1617, "lastChild"); -let temp__27646__auto__21 = closed_by(firstChild19); -if (temp__27646__auto__21) { -let closing22 = temp__27646__auto__21; +let temp__32037__auto__21 = closed_by(firstChild19); +if (temp__32037__auto__21) { +let closing22 = temp__32037__auto__21; return ((closing22 === name(lastChild20)) && (end(firstChild19) !== end(lastChild20)));} else { return true;} }) ; var ancestors = (function (node) { -let temp__27794__auto__23 = up(node); -if (squint_core.nil_QMARK_(temp__27794__auto__23)) { +let temp__32185__auto__23 = up(node); +if (squint_core.nil_QMARK_(temp__32185__auto__23)) { return null;} else { -let parent24 = temp__27794__auto__23; +let parent24 = temp__32185__auto__23; return squint_core.cons(parent24, new squint_core.LazySeq((function () { return ancestors(parent24); })));} @@ -300,7 +300,7 @@ default: throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} }); f25["cljs$core$IFn$_invoke$arity$3"] = (function (parent, from, dir) { -let temp__27794__auto__31 = (function () { +let temp__32185__auto__31 = (function () { let G__3233 = dir; switch (G__3233) {case 1: return parent.childAfter(from); @@ -311,9 +311,9 @@ break; default: throw new Error(squint_core.str("No matching clause: ", G__3233))} })(); -if (squint_core.nil_QMARK_(temp__27794__auto__31)) { +if (squint_core.nil_QMARK_(temp__32185__auto__31)) { return null;} else { -let child35 = temp__27794__auto__31; +let child35 = temp__32185__auto__31; return squint_core.cons(child35, new squint_core.LazySeq((function () { return children(parent, (function () { let G__3637 = dir; @@ -618,10 +618,10 @@ return node;} }) ; var prefix = (function (node) { -let temp__27794__auto__117 = up(node); -if (squint_core.nil_QMARK_(temp__27794__auto__117)) { +let temp__32185__auto__117 = up(node); +if (squint_core.nil_QMARK_(temp__32185__auto__117)) { return null;} else { -let parent118 = temp__27794__auto__117; +let parent118 = temp__32185__auto__117; return (u.guard(parent118, prefix_container_QMARK_) || u.guard(down(parent118), prefix_edge_QMARK_));} }) ; @@ -683,12 +683,12 @@ return (pos === from140); let mid141 = tree(state, pos); let G__142143 = dir; switch (G__142143) {case 1: -return (u.guard(R134, every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { +return (u.guard(R134, squint_core.every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { return (same_edge_QMARK_(_PERCENT_1) || !right_edge_QMARK_(_PERCENT_1)); }))) || L127 || R134 || mid141); break; case -1: -return (u.guard(L127, every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { +return (u.guard(L127, squint_core.every_pred(squint_core.some_QMARK_, (function (_PERCENT_1) { return (same_edge_QMARK_(_PERCENT_1) || !left_edge_QMARK_(_PERCENT_1)); }))) || R134 || L127 || mid141); break; diff --git a/src-squint/nextjournal/clojure_mode/extensions/match_brackets.cljs b/src-squint/nextjournal/clojure_mode/extensions/match_brackets.cljs index 6ab5f34e..ab7ecd99 100644 --- a/src-squint/nextjournal/clojure_mode/extensions/match_brackets.cljs +++ b/src-squint/nextjournal/clojure_mode/extensions/match_brackets.cljs @@ -1,18 +1,18 @@ (ns nextjournal.clojure-mode.extensions.match-brackets (:require + ["../node.mjs" :as n] + ["../util.mjs" :as u] ["@codemirror/state" :refer [StateField]] ["@codemirror/view" :refer [EditorView Decoration]] - ["../node.mjs" :as n] #_[nextjournal.clojure-mode.node :as n] - ["../util.mjs" :as u] #_[nextjournal.clojure-mode.util :as u :refer [from-to]])) (def base-theme (->> {:$matchingBracket {:color "#0b0"} :$nonmatchingBracket {:color "#a22"}} - (.baseTheme EditorView))) + (.baseTheme EditorView))) (def ^js matching-mark (.mark Decoration {:class "cm-matchingBracket"})) (def ^js nonmatching-mark (.mark Decoration {:class "cm-nonmatchingBracket"})) @@ -64,9 +64,9 @@ ;; unmatched bracket is sitting in front of the cursor. (when-let [_unparsed-bracket (and ;; skip this check if we're inside a string - (not (-> (n/tree state head) (n/closest n/string?))) - (-> (.. tr -state -doc (slice head (inc head)) toString) - (#{\] \) \}})))] + (not (-> (n/tree state head) (n/closest n/string?))) + (->> (.. tr -state -doc (slice head (inc head)) toString) + (contains? #{\] \) \}})))] (conj out (mark-node (n/from-to head (inc head)) nonmatching-mark))) out)) []))] (.set Decoration (into-array decos) true)) diff --git a/src-squint/nextjournal/clojure_mode/extensions/selection_history.cljs b/src-squint/nextjournal/clojure_mode/extensions/selection_history.cljs index 9c86f877..d0e718fc 100644 --- a/src-squint/nextjournal/clojure_mode/extensions/selection_history.cljs +++ b/src-squint/nextjournal/clojure_mode/extensions/selection_history.cljs @@ -24,7 +24,8 @@ (-> selection .-ranges (->> (some #(not (.-empty ^js %)))))) (def selection-history-field - "Stores selection history" + ;; TODO: fix squint, docstring + #_"Stores selection history" (.define StateField #js{:create (fn [^js state] (list {:selection (.-selection state)})) :update diff --git a/src-squint/nextjournal/clojure_mode/node.cljs b/src-squint/nextjournal/clojure_mode/node.cljs index c92af5a3..e045f560 100644 --- a/src-squint/nextjournal/clojure_mode/node.cljs +++ b/src-squint/nextjournal/clojure_mode/node.cljs @@ -164,7 +164,7 @@ (identical? "ConstructorCall" (name node-type)) false :else true)) -(defn balanced? [^:js {:as node :keys [^js firstChild ^js lastChild]}] +(defn balanced? [^:js {:as _node :keys [^js firstChild ^js lastChild]}] (if-let [closing (closed-by firstChild)] (and (= closing (name lastChild)) (not= (end firstChild) (end lastChild))) diff --git a/yarn.lock b/yarn.lock index a4d25766..2d079bb7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1072,10 +1072,8 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -squint-cljs@0.1.19: +squint-cljs@../squint: version "0.1.19" - resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.1.19.tgz#646aa78190d6c34619ad402fd646cf323c35524a" - integrity sha512-dB+RbCArxRZrOaAK7PMdbEjlXmUxBt7irPg5SMeyOIy81xRwBJn6ya9pHJZ9TrV4LPxwSxlJRNQsQK5Rpm8Dpg== stream-browserify@^2.0.1: version "2.0.2" From f75d74ee94bde8985dc5396d1aab32fd11e9c1d4 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 17:24:06 +0200 Subject: [PATCH 23/80] bump squint --- package.json | 2 +- public/squint/js/main.mjs | 2 +- .../clojure_mode/extensions/selection_history.mjs | 8 ++++---- yarn.lock | 6 ++++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index d5144e28..45300a3a 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "w3c-keyname": "^2.2.4", - "squint-cljs": "../squint" + "squint-cljs": "0.1.20" }, "scripts": { "watch": "bb copy-viewer-css && shadow-cljs -A:demo watch demo livedoc test", diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 904ddc5b..360eb33d 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -15,7 +15,7 @@ import { syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language' console.log(default_extensions); -let extensions = [ (syntaxHighlighting(defaultHighlightStyle)), ...default_extensions.slice(0,4) ] +let extensions = [ (syntaxHighlighting(defaultHighlightStyle)), ...default_extensions ] let state = EditorState.create( {doc: "(+ 1 2 3)", extensions: extensions }); let editorElt = document.querySelector('#editor'); diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs index d60f00b8..2f8bdbef 100644 --- a/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs @@ -28,7 +28,7 @@ let tr5 = map__24; let map__36 = squint_core.get(map__24, "state"); let selection7 = squint_core.get(map__36, "selection"); let docChanged8 = squint_core.get(map__24, "docChanged"); -let previous_position9 = squint_core.first(keep_indexed((function (i, x) { +let previous_position9 = squint_core.first(squint_core.keep_indexed((function (i, x) { if (sel.eq_QMARK_(squint_core.get(x, "selection"), selection7)) { return i;} }), stack)); @@ -91,9 +91,9 @@ return n.range(G__3435);} }) ; var selection_return_STAR_ = (function (state) { -let temp__32037__auto__36 = squint_core.get(squint_core.second(stack(state)), "selection"); -if (temp__32037__auto__36) { -let selection37 = temp__32037__auto__36; +let temp__27662__auto__36 = squint_core.get(squint_core.second(stack(state)), "selection"); +if (temp__27662__auto__36) { +let selection37 = temp__27662__auto__36; return state.update(({ "selection": selection37, "annotations": event_annotation }));} else { return u.update_ranges(state, ({ "annotations": event_annotation }), (function (range) { return ({ "cursor": range["from"] }); diff --git a/yarn.lock b/yarn.lock index 2d079bb7..b6869bbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1072,8 +1072,10 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -squint-cljs@../squint: - version "0.1.19" +squint-cljs@0.1.20: + version "0.1.20" + resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.1.20.tgz#ea2b86a37242de85952398675c0147c92d911dbf" + integrity sha512-f60XK1mwcpb84v6TMz4138/orPuvbPYVwCJ55te4OMCnOlwBmn8We1vB9kfSEekHHlPY4jv+dEBQX5mHSJO4Ng== stream-browserify@^2.0.1: version "2.0.2" From fffcd3cdaaa7f0019723037bebce7703fb046bef Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 17:35:07 +0200 Subject: [PATCH 24/80] css not working --- public/squint/js/main.mjs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs index 360eb33d..fcbb9ca1 100644 --- a/public/squint/js/main.mjs +++ b/public/squint/js/main.mjs @@ -7,15 +7,16 @@ import './src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs'; import './src-squint/nextjournal/clojure_mode/commands.mjs'; import './src-squint/nextjournal/clojure_mode/keymap.mjs'; import { default_extensions } from './src-squint/nextjournal/clojure_mode.mjs'; +import { theme } from './src-squint/nextjournal/clojure_mode/demo.mjs'; import { EditorView } from '@codemirror/view'; import { EditorState } from '@codemirror/state'; -import { syntaxHighlighting, defaultHighlightStyle } from '@codemirror/language'; +import { syntaxHighlighting, defaultHighlightStyle, foldGutter } from '@codemirror/language'; +let extensions = [ theme, foldGutter(), + (syntaxHighlighting(defaultHighlightStyle)), + ...default_extensions ]; -console.log(default_extensions); - -let extensions = [ (syntaxHighlighting(defaultHighlightStyle)), ...default_extensions ] let state = EditorState.create( {doc: "(+ 1 2 3)", extensions: extensions }); let editorElt = document.querySelector('#editor'); From de473a5b2603daeb1216b775695b2cb49b4a40ab Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 17:35:07 +0200 Subject: [PATCH 25/80] css not working --- .../nextjournal/clojure_mode/demo.mjs | 7 ++++++ src-squint/nextjournal/clojure_mode/demo.cljs | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 public/squint/js/src-squint/nextjournal/clojure_mode/demo.mjs create mode 100644 src-squint/nextjournal/clojure_mode/demo.cljs diff --git a/public/squint/js/src-squint/nextjournal/clojure_mode/demo.mjs b/public/squint/js/src-squint/nextjournal/clojure_mode/demo.mjs new file mode 100644 index 00000000..54ea50cc --- /dev/null +++ b/public/squint/js/src-squint/nextjournal/clojure_mode/demo.mjs @@ -0,0 +1,7 @@ +import * as squint_core from 'squint-cljs/core.js'; +import * as view from '@codemirror/view'; +import { EditorView } from '@codemirror/view'; +var theme = EditorView.theme(({ ".cm-content": ({ "white-space": "pre-wrap", "padding": "10px 0", "flex": "1 1 0" }), "&.cm-focused": ({ "outline": "0 !important" }), ".cm-line": ({ "padding": "0 9px", "line-height": "1.6", "font-size": "16px", "font-family": "var(--code-font)" }), ".cm-matchingBracket": ({ "border-bottom": "1px solid var(--teal-color)", "color": "inherit" }), ".cm-gutters": ({ "background": "transparent", "border": "none" }), ".cm-gutterElement": ({ "margin-left": "5px" }), ".cm-cursor": ({ "visibility": "hidden" }), "&.cm-focused .cm-cursor": ({ "visibility": "visible" }) })) +; + +export { theme } diff --git a/src-squint/nextjournal/clojure_mode/demo.cljs b/src-squint/nextjournal/clojure_mode/demo.cljs new file mode 100644 index 00000000..ceb281a2 --- /dev/null +++ b/src-squint/nextjournal/clojure_mode/demo.cljs @@ -0,0 +1,22 @@ +(ns nextjournal.clojure-mode.demo + (:require ["@codemirror/view" :as view :refer [EditorView]])) + +(def theme + (.theme EditorView + {".cm-content" {:white-space "pre-wrap" + :padding "10px 0" + :flex "1 1 0"} + + "&.cm-focused" {:outline "0 !important"} + ".cm-line" {:padding "0 9px" + :line-height "1.6" + :font-size "16px" + :font-family "var(--code-font)"} + ".cm-matchingBracket" {:border-bottom "1px solid var(--teal-color)" + :color "inherit"} + ".cm-gutters" {:background "transparent" + :border "none"} + ".cm-gutterElement" {:margin-left "5px"} + ;; only show cursor when focused + ".cm-cursor" {:visibility "hidden"} + "&.cm-focused .cm-cursor" {:visibility "visible"}})) From 29b7c2bbe833eb61507740bf0d6e3cda1597060e Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Mon, 11 Sep 2023 18:14:15 +0200 Subject: [PATCH 26/80] css --- public/squint/index.html | 3 ++- public/squint/js/main.mjs | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/public/squint/index.html b/public/squint/index.html index 30da2298..f49fc794 100644 --- a/public/squint/index.html +++ b/public/squint/index.html @@ -92,7 +92,8 @@

Try evaluating an

In-browser eval is powered by Sci.

-
+
+
- + diff --git a/public/squint/js/demo.mjs b/public/squint/js/demo.mjs new file mode 100644 index 00000000..0912a3f7 --- /dev/null +++ b/public/squint/js/demo.mjs @@ -0,0 +1,38 @@ +import { default_extensions, complete_keymap } from '@nextjournal/clojure-mode'; +import { EditorView, drawSelection, keymap } from '@codemirror/view'; +import { EditorState } from '@codemirror/state'; +import { syntaxHighlighting, defaultHighlightStyle, foldGutter } from '@codemirror/language'; + +let theme = EditorView.theme({ + ".cm-content": {whitespace: "pre-wrap", + passing: "10px 0", + flex: "1 1 0"}, + + "&.cm-focused": {outline: "0 !important"}, + ".cm-line": {"padding": "0 9px", + "line-height": "1.6", + "font-size": "16px", + "font-family": "var(--code-font)"}, + ".cm-matchingBracket": {"border-bottom": "1px solid var(--teal-color)", + "color": "inherit"}, + ".cm-gutters": {background: "transparent", + border: "none"}, + ".cm-gutterElement": {"margin-left": "5px"}, + // only show cursor when focused + ".cm-cursor": {visibility: "hidden"}, + "&.cm-focused .cm-cursor": {visibility: "visible"} +}); + +let extensions = [ theme, foldGutter(), + syntaxHighlighting(defaultHighlightStyle), + drawSelection(), + keymap.of(complete_keymap), + ...default_extensions + ]; + +let state = EditorState.create( {doc: "(+ 1 2 3)", + extensions: extensions }); +let editorElt = document.querySelector('#editor'); +let editor = new EditorView({state: state, + parent: editorElt, + extensions: extensions }); diff --git a/public/squint/js/main.mjs b/public/squint/js/main.mjs deleted file mode 100644 index 245cf611..00000000 --- a/public/squint/js/main.mjs +++ /dev/null @@ -1,33 +0,0 @@ -// import './src-squint/nextjournal/clojure_mode/node.mjs'; -// import './src-squint/nextjournal/clojure_mode/extensions/close_brackets.mjs'; -// import './src-squint/nextjournal/clojure_mode/extensions/match_brackets.mjs'; -// import './src-squint/nextjournal/clojure_mode/extensions/formatting.mjs'; -// import './src-squint/nextjournal/clojure_mode/extensions/selection_history.mjs'; -// import './src-squint/nextjournal/clojure_mode/commands.mjs'; -// import './src-squint/nextjournal/clojure_mode/keymap.mjs'; -import { default_extensions, complete_keymap } from './nextjournal/clojure_mode.mjs'; -import { theme } from './nextjournal/clojure_mode/demo.mjs'; - -import { EditorView, drawSelection, keymap } from '@codemirror/view'; -import { EditorState } from '@codemirror/state'; -import { syntaxHighlighting, defaultHighlightStyle, foldGutter } from '@codemirror/language'; - -let extensions = [ theme, foldGutter(), - syntaxHighlighting(defaultHighlightStyle), - drawSelection(), - keymap.of(complete_keymap), - ...default_extensions - ]; - -let state = EditorState.create( {doc: "(+ 1 2 3)", - extensions: extensions }); -let editorElt = document.querySelector('#editor'); -let editor = new EditorView({state: state, - parent: editorElt, - extensions: extensions }); - - -// - [ ] resolve symbolic namespaces to local JS files -// and transitively compile them? -// - [ ] tests -// - [ ] bun loader experiment diff --git a/squint.edn b/squint.edn index 4b822d86..3d76b43d 100644 --- a/squint.edn +++ b/squint.edn @@ -1,2 +1,2 @@ {:paths ["src-shared" "src-squint"] - :output-dir "public/squint/js"} + :output-dir "dist"} diff --git a/vite.config.js b/vite.config.js index d5485036..8b7f9204 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,7 +1,14 @@ +import analyze from "rollup-plugin-analyzer"; + export default { optimizeDeps: { // avoids loading deps multiple time exclude: ['prosemirror-model', 'y-prosemirror', 'y-websocket'], // root: "demo" - } + }, + build: { + rollupOptions: { + plugins: [analyze()] + } + }, }; diff --git a/yarn.lock b/yarn.lock index 1b2f90d4..674f965e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -317,6 +317,10 @@ "@lezer/common" "^1.0.0" "@lezer/highlight" "^1.0.0" +"@nextjournal/clojure-mode@link:.": + version "0.0.0" + uid "" + "@nextjournal/lezer-clojure@1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@nextjournal/lezer-clojure/-/lezer-clojure-1.0.0.tgz" @@ -1240,6 +1244,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rollup-plugin-analyzer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-analyzer/-/rollup-plugin-analyzer-4.0.0.tgz#96b757ed64a098b59d72f085319e68cdd86d5798" + integrity sha512-LL9GEt3bkXp6Wa19SNR5MWcvHNMvuTFYg+eYBZN2OIFhSWN+pEJUQXEKu5BsOeABob3x9PDaLKW7w5iOJnsESQ== + rollup@^3.27.1: version "3.28.1" resolved "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz" From 991794d66cdda9a5dfb155e88a9adfa53ae49a3c Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Oct 2023 15:12:14 +0200 Subject: [PATCH 69/80] remove demo --- public/squint/js/demo.mjs | 38 -------------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 public/squint/js/demo.mjs diff --git a/public/squint/js/demo.mjs b/public/squint/js/demo.mjs deleted file mode 100644 index 0912a3f7..00000000 --- a/public/squint/js/demo.mjs +++ /dev/null @@ -1,38 +0,0 @@ -import { default_extensions, complete_keymap } from '@nextjournal/clojure-mode'; -import { EditorView, drawSelection, keymap } from '@codemirror/view'; -import { EditorState } from '@codemirror/state'; -import { syntaxHighlighting, defaultHighlightStyle, foldGutter } from '@codemirror/language'; - -let theme = EditorView.theme({ - ".cm-content": {whitespace: "pre-wrap", - passing: "10px 0", - flex: "1 1 0"}, - - "&.cm-focused": {outline: "0 !important"}, - ".cm-line": {"padding": "0 9px", - "line-height": "1.6", - "font-size": "16px", - "font-family": "var(--code-font)"}, - ".cm-matchingBracket": {"border-bottom": "1px solid var(--teal-color)", - "color": "inherit"}, - ".cm-gutters": {background: "transparent", - border: "none"}, - ".cm-gutterElement": {"margin-left": "5px"}, - // only show cursor when focused - ".cm-cursor": {visibility: "hidden"}, - "&.cm-focused .cm-cursor": {visibility: "visible"} -}); - -let extensions = [ theme, foldGutter(), - syntaxHighlighting(defaultHighlightStyle), - drawSelection(), - keymap.of(complete_keymap), - ...default_extensions - ]; - -let state = EditorState.create( {doc: "(+ 1 2 3)", - extensions: extensions }); -let editorElt = document.querySelector('#editor'); -let editor = new EditorView({state: state, - parent: editorElt, - extensions: extensions }); From 1912ab921dbfcb51b7be623fdf0fdf373b7455be Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Oct 2023 15:15:39 +0200 Subject: [PATCH 70/80] fix test --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa312969..5cb6f98a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,7 +27,7 @@ jobs: - name: ๐Ÿงช Run squint tests run: | yarn squint compile - node public/squint/js/nextjournal/clojure_mode_tests.mjs + node dist/nextjournal/clojure_mode_tests.mjs snapshot: name: Static App / Build From 377954b9558fd69e4f6cbd07e1e6d667e78daeba Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Oct 2023 15:17:29 +0200 Subject: [PATCH 71/80] remove demo.mjs --- public/squint/js/demo.mjs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 public/squint/js/demo.mjs diff --git a/public/squint/js/demo.mjs b/public/squint/js/demo.mjs new file mode 100644 index 00000000..0912a3f7 --- /dev/null +++ b/public/squint/js/demo.mjs @@ -0,0 +1,38 @@ +import { default_extensions, complete_keymap } from '@nextjournal/clojure-mode'; +import { EditorView, drawSelection, keymap } from '@codemirror/view'; +import { EditorState } from '@codemirror/state'; +import { syntaxHighlighting, defaultHighlightStyle, foldGutter } from '@codemirror/language'; + +let theme = EditorView.theme({ + ".cm-content": {whitespace: "pre-wrap", + passing: "10px 0", + flex: "1 1 0"}, + + "&.cm-focused": {outline: "0 !important"}, + ".cm-line": {"padding": "0 9px", + "line-height": "1.6", + "font-size": "16px", + "font-family": "var(--code-font)"}, + ".cm-matchingBracket": {"border-bottom": "1px solid var(--teal-color)", + "color": "inherit"}, + ".cm-gutters": {background: "transparent", + border: "none"}, + ".cm-gutterElement": {"margin-left": "5px"}, + // only show cursor when focused + ".cm-cursor": {visibility: "hidden"}, + "&.cm-focused .cm-cursor": {visibility: "visible"} +}); + +let extensions = [ theme, foldGutter(), + syntaxHighlighting(defaultHighlightStyle), + drawSelection(), + keymap.of(complete_keymap), + ...default_extensions + ]; + +let state = EditorState.create( {doc: "(+ 1 2 3)", + extensions: extensions }); +let editorElt = document.querySelector('#editor'); +let editor = new EditorView({state: state, + parent: editorElt, + extensions: extensions }); From 19ceb91c74f385449c024cadd172064713ad65e5 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Oct 2023 15:18:28 +0200 Subject: [PATCH 72/80] build --- .github/workflows/main.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5cb6f98a..f1ae447c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -59,6 +59,9 @@ jobs: - name: ๐Ÿงถ Yarn Build run: | yarn build + + - name: ๐Ÿงถ Squint build + run: | yarn squint compile yarn vite:build From 8cfb2a20e7ea203056c47ebd80b7f4dd50a27e40 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Oct 2023 15:26:05 +0200 Subject: [PATCH 73/80] fix base dir --- vite.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/vite.config.js b/vite.config.js index 8b7f9204..9891ff8a 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,6 +1,7 @@ import analyze from "rollup-plugin-analyzer"; export default { + base: './', optimizeDeps: { // avoids loading deps multiple time exclude: ['prosemirror-model', 'y-prosemirror', 'y-websocket'], From 74523e6b656b32169d8506f214bfc18ac8a8166d Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Oct 2023 15:35:23 +0200 Subject: [PATCH 74/80] Add name --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c417a4d1..2d6b9ea2 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ -{ +{ "name": "@nextjournal/clojure-mode", + "files": ["dist"], "dependencies": { "@codemirror/autocomplete": "^6.0.2", "@codemirror/commands": "^6.0.0", From 60ff5cfb99da8c0c5d9e90d2228fa379a3d63637 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Oct 2023 16:00:51 +0200 Subject: [PATCH 75/80] simplify gitignore --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 234139f3..c576685d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,4 @@ node_modules public/test *.iml out -public/squint/js/nextjournal -public/squint/js/applied_science dist From 60cb060f9fd540ea5d243de017fcec9a879c03dc Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Wed, 25 Oct 2023 16:01:38 +0200 Subject: [PATCH 76/80] remove garbage --- nextjournal/clojure_mode.mjs | 61 ------------------------------------ 1 file changed, 61 deletions(-) delete mode 100644 nextjournal/clojure_mode.mjs diff --git a/nextjournal/clojure_mode.mjs b/nextjournal/clojure_mode.mjs deleted file mode 100644 index 90d9045a..00000000 --- a/nextjournal/clojure_mode.mjs +++ /dev/null @@ -1,61 +0,0 @@ -import * as squint_core from 'squint-cljs/core.js'; -import * as language from '@codemirror/language'; -import { LRLanguage, LanguageSupport } from '@codemirror/language'; -import * as highlight from '@lezer/highlight'; -import { tags } from '@lezer/highlight'; -import * as lezer_clj from '@nextjournal/lezer-clojure'; -import * as j from './../applied_science/js_interop.mjs'; -import * as close_brackets from './clojure_mode/extensions/close_brackets.mjs'; -import * as format from './clojure_mode/extensions/formatting.mjs'; -import * as match_brackets from './clojure_mode/extensions/match_brackets.mjs'; -import * as sel_history from './clojure_mode/extensions/selection_history.mjs'; -import * as keymap from './clojure_mode/keymap.mjs'; -import * as n from './clojure_mode/node.mjs'; -var fold_node_props = (function () { - let coll_span1 = (function (tree) { -return ({ "from": (n.start(tree) + 1), "to": (n.end(tree) - 1) }); -}); -return j.lit(({ "Vector": coll_span1, "Map": coll_span1, "List": coll_span1 })); -})() -; -var style_tags = ({ "LineComment": tags["lineComment"], "NS": tags["keyword"], "\"\\\"\"": tags["string"], "VarName/Symbol": tags.definition(tags["variableName"]), "DocString/...": tags["emphasis"], "Boolean": tags["atom"], "Keyword": tags["atom"], "Number": tags["number"], "RegExp": tags["regexp"], "StringContent": tags["string"], "Operator/Symbol": tags["keyword"], "Discard!": tags["comment"], "DefLike": tags["keyword"], "Nil": tags["null"] }) -; -var parser = lezer_clj.parser -; -null; -var syntax = (function () { - let f2 = (function (var_args) { -let G__56 = arguments["length"]; -switch (G__56) {case 0: -return f2.cljs$core$IFn$_invoke$arity$0(); -break; -case 1: -return f2.cljs$core$IFn$_invoke$arity$1((arguments[0])); -break; -default: -throw new Error(squint_core.str("Invalid arity: ", squint_core.alength(arguments)))} -}); -f2["cljs$core$IFn$_invoke$arity$0"] = (function () { -return syntax(parser); -}); -f2["cljs$core$IFn$_invoke$arity$1"] = (function (parser) { -return LRLanguage.define(({ "parser": parser.configure(({ "props": [format.props, language.foldNodeProp.add(fold_node_props), highlight.styleTags(style_tags)] })) })); -}); -f2["cljs$lang$maxFixedArity"] = 1; -return f2; -})() -; -var complete_keymap = keymap.complete -; -var builtin_keymap = keymap.builtin -; -var paredit_keymap = keymap.paredit -; -var default_extensions = [syntax(lezer_clj.parser), close_brackets.extension(), match_brackets.extension(), sel_history.extension(), format.ext_format_changed_lines()] -; -var language_support = "Eases embedding clojure mode into other languages (e.g. markdown).\n See https://codemirror.net/docs/ref/#language.LanguageSupport for motivations" -; -null; -squint_core.prn("clojure-mode-loaded"); - -export { paredit_keymap, parser, style_tags, complete_keymap, default_extensions, builtin_keymap, fold_node_props, syntax, language_support } From 9ef3da3a3435d53bc6ce1618ad5082563d8e4874 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Oct 2023 14:20:57 +0100 Subject: [PATCH 77/80] upgrade squint --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 2d6b9ea2..f5341193 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "punycode": "2.1.1", "react": "^17.0.2", "react-dom": "^17.0.2", - "squint-cljs": "0.3.35", + "squint-cljs": "0.3.36", "w3c-keyname": "^2.2.4" }, "comments": { diff --git a/yarn.lock b/yarn.lock index 674f965e..3c2627ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1338,10 +1338,10 @@ source-map@^0.5.6: resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -squint-cljs@0.3.35: - version "0.3.35" - resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.3.35.tgz#734d4bb20b9181966b410c25cfc1cc5e4654bdf3" - integrity sha512-x9cZq9oDIzv4TOKsS1tbTPG10YXG84pzy5jHaDt8pRPc2yqtgS70TlxrsRn8xvHFUNL/B6Za/ouv6D04eDJu3Q== +squint-cljs@0.3.36: + version "0.3.36" + resolved "https://registry.yarnpkg.com/squint-cljs/-/squint-cljs-0.3.36.tgz#ac319675963f8fecc04d3e8708c1dee53ef3f96d" + integrity sha512-z9nJY3aGlWZdUwT7VP+6c4rbtVjOBzVaDhPeIiGQ7bhhfb4I/z1KCN43DZvIFos8AGVN2v9FC8jL8NiBLlDJnw== dependencies: chokidar "^3.5.3" glob "^10.3.10" From dcc92cc36a8380daf81d6a14063a20b298425eb0 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Oct 2023 14:51:24 +0100 Subject: [PATCH 78/80] Port tests --- squint.edn | 2 +- .../nextjournal/clojure_mode/test_utils.cljc | 10 +- .../nextjournal/clojure_mode_tests.cljs | 455 ------------------ .../clojure_mode_tests/macros.cljc | 15 +- ...ode_tests.cljs => clojure_mode_tests.cljc} | 51 +- 5 files changed, 47 insertions(+), 486 deletions(-) rename src/nextjournal/clojure_mode/test_utils.cljs => src-shared/nextjournal/clojure_mode/test_utils.cljc (88%) delete mode 100644 src-squint/nextjournal/clojure_mode_tests.cljs rename test/nextjournal/{clojure_mode_tests.cljs => clojure_mode_tests.cljc} (86%) diff --git a/squint.edn b/squint.edn index 3d76b43d..187a09bf 100644 --- a/squint.edn +++ b/squint.edn @@ -1,2 +1,2 @@ -{:paths ["src-shared" "src-squint"] +{:paths ["src-shared" "src-squint" "test"] :output-dir "dist"} diff --git a/src/nextjournal/clojure_mode/test_utils.cljs b/src-shared/nextjournal/clojure_mode/test_utils.cljc similarity index 88% rename from src/nextjournal/clojure_mode/test_utils.cljs rename to src-shared/nextjournal/clojure_mode/test_utils.cljc index 8d6a83ae..554842cb 100644 --- a/src/nextjournal/clojure_mode/test_utils.cljs +++ b/src-shared/nextjournal/clojure_mode/test_utils.cljc @@ -1,10 +1,10 @@ (ns nextjournal.clojure-mode.test-utils (:require ["@codemirror/state" :as cm-state - :refer [EditorState EditorSelection Extension StateCommand - ChangeSet ChangeDesc TransactionSpec StrictTransactionSpec]] - [applied-science.js-interop :as j] - [clojure.string :as str] - [nextjournal.clojure-mode.extensions.formatting :as format])) + :refer [EditorState EditorSelection]] + #?@(:squint [] + :cljs [[applied-science.js-interop :as j]]) + [clojure.string :as str]) + (:require-macros [applied-science.js-interop :as j])) ;; (de)serialize cursors| and for testing diff --git a/src-squint/nextjournal/clojure_mode_tests.cljs b/src-squint/nextjournal/clojure_mode_tests.cljs deleted file mode 100644 index 53d700cc..00000000 --- a/src-squint/nextjournal/clojure_mode_tests.cljs +++ /dev/null @@ -1,455 +0,0 @@ -(ns nextjournal.clojure-mode-tests - (:require ["./clojure_mode.mjs" :as cm-clojure] - ["./clojure_mode/commands.mjs" :as commands] - ["./clojure_mode/extensions/close_brackets.mjs" :as close-brackets] - ["./clojure_mode/extensions/formatting.mjs" :as format] - ["@codemirror/state" :as cm-state - :refer [EditorState EditorSelection]] - ["assert" :as assert] - #_[nextjournal.clojure-mode.test-utils :as test-utils]) - (:require-macros [nextjournal.clojure-mode-tests.macros :refer [deftest are testing]])) - -#_(assert/equal 1 2) - -(defn make-state [extensions doc] - (let [[doc ranges] (->> (re-seq #"\||<[^>]*?>|[^<>|]+" doc) - (reduce (fn [[^string doc ranges] match] - (cond (= match "|") - [doc (conj ranges (.cursor EditorSelection (count doc)))] - - (.startsWith match "<") - [(str doc (subs match 1 (dec (count match)))) - (conj ranges (.range EditorSelection - (count doc) - (+ (count doc) (- (count match) 2))))] - :else - [(str doc match) ranges])) ["" []]))] - (.create EditorState - #js{:doc doc - :selection (if (seq ranges) - (.create EditorSelection (into-array ranges)) - js/undefined) - :extensions (cond-> #js[(.. EditorState -allowMultipleSelections (of true))] - extensions - (doto (.push extensions)))}))) - -(defn state-str [^js state] - (let [doc (str (.-doc state))] - (->> (.. state -selection -ranges) - reverse - (reduce (fn [doc ^:js {:keys [empty from to]}] - (if empty - (str (subs doc 0 from) "|" (subs doc from)) - (str (subs doc 0 from) "<" (subs doc from to) ">" (subs doc to)))) doc)))) - -(defn apply-f* [extensions cmd doc] - ;; TODO: fix in squint - #_{:pre [(array? extensions) - (fn? cmd) - (string? doc)]} - (let [state (make-state extensions doc) - tr (cmd state)] - (state-str (if tr (.-state tr) state)))) - -(defn apply-cmd* [extensions cmd doc] - (let [state (make-state extensions doc) - !tr (atom nil) - _ (cmd #js{:state state - :dispatch #(reset! !tr %)}) - tr @!tr] - (state-str (get tr :state)))) - -(def extensions - cm-clojure/default-extensions - ;; optionally test with live grammar - #_#js[(cm-clojure/syntax live-grammar/parser) - (.slice cm-clojure/default-extensions 1)]) - -(def apply-f (partial apply-f* extensions)) -(def apply-cmd (partial apply-cmd* extensions)) - -;; nav -(doseq [[input dir expected] [["|()" 1 "()|"] - ["()|" -1 "|()"] - ["a|b" 1 "ab|"] - ["a|b" -1 "|ab"] - ["| ab" 1 " ab|"] - ["ab |" -1 "|ab "] - ["(|)" 1 "()|"] - ["(|)" -1 "|()"] - ["a|\nb" 1 "a\nb|"]]] - (assert.equal (apply-f (commands/nav dir) input) - expected)) - -;; nav-select -(doseq [[input dir expected] [["|()" 1 "<()>"] - ["()|" -1 "<()>"] - ["a|b" 1 "a"] - ["(|)" 1 "<()>"] - ["\"a|b\"" 1 "\"a\""] - ["\"a\"" 1 "<\"ab\">"] - ["a|b" -1 "b"] - ["| ab" 1 "< ab>"] - ["ab |" -1 ""] - ["(|)" 1 "<()>"] - ["(|)" -1 "<()>"] - ["a|\nb" 1 "a<\nb>"]]] - (assert.equal (apply-f (commands/nav-select dir) input) - expected)) - -;; close brackets > handle open -(doseq [[input insert expected] - (partition 3 ["|" \( "(|)" ;; auto-close brackets - "(|" \( "((|)" - "|(" \( "(|)(" - "|)" \( "(|))" - "#|" \( "#(|)" - "\"|\"" \( "\"(|\"" ;; no auto-close inside strings - ])] - (assert.equal (apply-f #(close-brackets/handle-open % insert) input) - expected)) - -;; close brackets > handle close -(doseq [[input bracket expected] - (partition 3 ["|" \) "|" - "|(" \) "|(" - "|)" \) ")|" - "(|)" \) "()|" - "() |()" \) "() ()|" - "[(|)]" \) "[()|]" - "[()|]" \) "[()]|" - "([]| s)" \) "([] s)|" - "(|" \) "()|" ;; close unclosed parent - "[(|]" \} "[(]|" ;; non-matching bracket doesn't close ancestor - "((|)" \] "(()|" ;; non-matching bracket doesn't close ancestor - "((|)" \) "(())|" ;; a bit weird - it finds an unclosed ancestor, and closes that. - "\"|\"" \) "\")|\"" ;; normal behaviour inside strings - ])] - (assert.equal (apply-f #(close-brackets/handle-close % bracket) input) - expected)) - -;; close brackets > handle open string -(doseq [[input expected] - (partition 2 ["|" "\"|\"" ;; auto-close strings - "\"|\"" "\"\\\"|\"" ;; insert quoted " inside strings - ] - )] - (assert.equal (apply-f #(close-brackets/handle-open % \") input) expected)) - -;; close brackets > handle backspace -(doseq [[input expected] - (partition 2 ["|" "|" - "(|" "|" ;; delete an unbalanced paren - "()|" "(|)" ;; enter a form from the right (do not "unbalance") - "#|()" "|()" ;; delete prefix form - "[[]]|" "[[]|]" - "(| )" "|" ;; delete empty form - "(| a)" "(| a)" ;; don't delete non-empty forms - "@|" "|" ;; delete @ - "@|x" "|x" - "\"|\"" "|" ;; delete empty string - "\"\"|" "\"|\"" - "\"| \"" "\"| \"" ;; do not delete string with whitespace - ":x :a |" ":x :a|" ;; do not format on backspace - "\"[|]\"" "\"|]\"" ;; normal deletion inside strings - ])] - (assert.equal (apply-f close-brackets/handle-backspace input) - expected)) - -;; indent selection -(doseq [[input expected] - (partition 2 [" ()" "()" ;; top-level => 0 indent - "(\n)" "(\n )" - "(b\n)" "(b\n )" ;; operator gets extra indent (symbol in 1st position) - "(0\n)" "(0\n )" ;; a number is not operator - "(:a\n)" "(:a\n )" ;; a keyword is not operator - "(a\n\nb)" "(a\n \n b)" ;; empty lines get indent - ])] - (assert.equal (apply-f format/format (str "<" input ">")) - (str "<" expected ">"))) - -;; nav -(doseq [[input dir expected] - (partition 3 - ["|()" 1 "()|" - "()|" -1 "|()" - "a|b" 1 "ab|" - "a|b" -1 "|ab" - "| ab" 1 " ab|" - "ab |" -1 "|ab " - "(|)" 1 "()|" - "(|)" -1 "|()" - "a|\nb" 1 "a\nb|"])] - (assert.equal (apply-f (commands/nav dir) input) - expected)) -;; nav-select -(doseq [[input dir expected] - (partition 3 ["|()" 1 "<()>" - "()|" -1 "<()>" - "a|b" 1 "a" - "(|)" 1 "<()>" - "\"a|b\"" 1 "\"a\"" - "\"a\"" 1 "<\"ab\">" - "a|b" -1 "b" - "| ab" 1 "< ab>" - "ab |" -1 "" - "(|)" 1 "<()>" - "(|)" -1 "<()>" - "a|\nb" 1 "a<\nb>" - ])] - (assert.equal (apply-f (commands/nav-select dir) input) - expected)) - -;; close-brackets -(doseq [[input insert expected] - (partition 3 ["|" \( "(|)" ;; auto-close brackets - "(|" \( "((|)" - "|(" \( "(|)(" - "|)" \( "(|))" - "#|" \( "#(|)" - "\"|\"" \( "\"(|\"" ;; no auto-close inside strings - ])] - (assert.equal (apply-f #(close-brackets/handle-open % insert) input) - expected)) - -;; handle-close -(doseq [[input bracket expected] - (partition 3 ["|" \) "|" - "|(" \) "|(" - "|)" \) ")|" - "(|)" \) "()|" - "() |()" \) "() ()|" - "[(|)]" \) "[()|]" - "[()|]" \) "[()]|" - "([]| s)" \) "([] s)|" - "(|" \) "()|" ;; close unclosed parent - "[(|]" \} "[(]|" ;; non-matching bracket doesn't close ancestor - "((|)" \] "(()|" ;; non-matching bracket doesn't close ancestor - "((|)" \) "(())|" ;; a bit weird - it finds an unclosed ancestor, and closes that. - "\"|\"" \) "\")|\"" ;; normal behaviour inside strings - ])] - (assert.equal (apply-f #(close-brackets/handle-close % bracket) input) - expected)) - -(deftest close-brackets - (testing "handle-open" - ) - - (testing "handle-close" - ) - - (testing "handle-open string" - (are [input expected] - (= (apply-f #(close-brackets/handle-open % \") input) expected) - "|" "\"|\"" ;; auto-close strings - "\"|\"" "\"\\\"|\"" ;; insert quoted " inside strings - )) - - (testing "handle-backspace" - (are [input expected] - (= (apply-f close-brackets/handle-backspace input) - expected) - "|" "|" - "(|" "|" ;; delete an unbalanced paren - "()|" "(|)" ;; enter a form from the right (do not "unbalance") - "#|()" "|()" ;; delete prefix form - "[[]]|" "[[]|]" - "(| )" "|" ;; delete empty form - "(| a)" "(| a)" ;; don't delete non-empty forms - "@|" "|" ;; delete @ - "@|x" "|x" - "\"|\"" "|" ;; delete empty string - "\"\"|" "\"|\"" - "\"| \"" "\"| \"" ;; do not delete string with whitespace - ":x :a |" ":x :a|" ;; do not format on backspace - "\"[|]\"" "\"|]\"" ;; normal deletion inside strings - )) - - #_(testing "handle backspace (embedded)" - (are [input expected] - (= (apply-embedded-f close-brackets/handle-backspace input) - expected) - "```\n()|\n```" "```\n(|)\n```" - "```\n[[]]|\n```" "```\n[[]|]\n```" - "```\n(| )\n```" "```\n|\n```"))) - -(do - - - - (deftest indentSelection - - (are [input expected] - (= (apply-f format/format (str "<" input ">")) - (str "<" expected ">")) - " ()" "()" ;; top-level => 0 indent - "(\n)" "(\n )" - "(b\n)" "(b\n )" ;; operator gets extra indent (symbol in 1st position) - "(0\n)" "(0\n )" ;; a number is not operator - "(:a\n)" "(:a\n )" ;; a keyword is not operator - "(a\n\nb)" "(a\n \n b)" ;; empty lines get indent - ) - - (testing "prefix-all" - (are [before after] - (= (apply-f (partial format/prefix-all "a") before) - after) - "z|z\nzz|\n|zz" "az|z\nazz|\n|azz" - "z\nz" "az\naz"))) - - (deftest indent-all ;; same as indentSelection but applies to entire doc - (are [input expected] - (= (apply-f format/indent-all input) - expected) - "| ()" "|()" - "|()[\n]" "|()[\n ]" - "|(\n)" "|(\n )" - "(\n)" "(\n )" - "|(0\nx<)>" "|(0\n x<)>" - "<(:a\n)>" "<(:a\n )>" - "|(a\n\nb)" "|(a\n\n b)")) - - (deftest format-all - (are [input expected] - (= (apply-f format/format-all input) - expected) - "a :b 3 |" "a :b 3|" ;; remove extra spaces - "\"\" |:a " "\"\" |:a" - "(|a )" "(|a)" - "| ( )" "|()" - "|()a" "|() a" ;; add needed spaces - "() |a" "() |a" ;; cursor position - "()| a" "()| a" - "() | a" "() |a" - "|(\n )" "|(\n )" - "(\n)" "(\n )" - "<(:a\n)>" "<(:a\n )>" - "|(a\n\nb)" "|(a\n\n b)" - "|\"a\"" "|\"a\"" - "#_a|" "#_a|" - "[ | ]" "[|]" - "|[] " "|[]" - "#(|a )" "#(|a)" - - "|@ a" "|@a" - "|&" "|&" - "[_ & |_]" "[_ & |_]" - - "|[a [\n]]" "|[a [\n ]]" - "|[a [\n]]" "|[a [\n ]]" - - "|[ a \n]" "|[a\n ]" - "|[ a [\n]]" "|[a [\n ]]" - "|[ \n[ \n[ ]]]" "|[\n [\n []]]" - "|()[\n]" "|() [\n ]" ;; closing-bracket 1 space in front of opening-bracket - "|()[\n]" "|() [\n ]")) - - (deftest format-selection - (are [input expected] - (= (apply-f format/format input) - expected) - "\nc d" "\nc d" ;; only selected lines are formatted - " c \na b" " c \na b" ;; multiple selectons on one line - )) - - (deftest kill - (are [input expected] - (= (apply-cmd commands/kill input) - expected) - "| ()\nx" "|\nx" ;; top-level - " \"ab|c\" " "\"ab|\"" ;; kill to end of string - " \"|a\nb\"" "\"|b\"" ;; TODO - stop at newline within string - "(|)" "(|)" ;; no-op in empty coll - "(| x y [])" "(|)" ;; kill all coll contents - "a| \nb" "a|b" ;; bring next line up - )) - - (deftest unwrap - (are [input expected] - (= (apply-cmd commands/unwrap input) - expected) - "(|)" "|" - "[a | b]" "a |b" - "a|b" "a|b")) - - (deftest balance-ranges - (are [input expected] - (= (apply-f commands/balance-ranges input) - expected) - "" "" - "a" "a" - " \"a<\"> " " <\"a\"> " - "(<)>" "<()>" - "(" "<(a) b>")) - - (deftest slurp - (are [input dir expected] - (= (apply-f (commands/slurp dir) input) expected) - "(|) a" 1 "(|a)" - "((|)) a" 1 "((|) a)" - "(|) ;;comment\na" 1 "(|;;comment\n a)" ;; slurp around comments - "a(|)" -1 "(a|)" - "a ;; hello\n(|)" -1 "(a ;; hello\n | )" - "a #:b{|}" -1 "#:b{a|}" - - "a #(|)" -1 "#(a|)" - "#(|) a" 1 "#(|a)" - "@(|) a" 1 "@(|a)" - "#::a{|:a} 1" 1 "#::a{|:a 1}" - "'(|) 1" 1 "'(|1)" - - "^{|} :x :a " 1 "^{|:x} :a" - "^{|} :x 1" 1 "^{|:x} 1" - "^{} [|] :x" 1 "^{} [|:x]" - - "('is-d|ata) :x" 1 "('is-d|ata :x)" - "('xy|z 1) 2" 1 "('xy|z 1 2)" - "'ab|c 1" 1 "'ab|c 1")) - - #_(deftest slurp-embedded - (are [input dir expected] - (= (apply-embedded-f (commands/slurp dir) input) expected) - "```\n(|) a\n```" 1 "```\n(|a)\n```" - "```\n((|)) a\n```" 1 "```\n((|) a)\n```" - "```\n(|) ;;comment\na\n```" 1 "```\n(|;;comment\n a)\n```" - "```\n('xy|z 1) 2\n```" 1 "```\n('xy|z 1 2)\n```")) - - (deftest barf - (are [input dir expected] - (= (apply-f (commands/barf dir) input) expected) - "(|a)" 1 "(|) a" - "(|a)" -1 "a (|)" - "((|)a)" 1 "((|)a)" - - "#(|a)" -1 "a #(|)" - "#(|a)" 1 "#(|) a" - - "#:b{a|}" -1 "a #:b{|}")) - - (deftest grow-selections - (are [input expected] - (= (apply-cmd commands/selection-grow input) expected) - - "(|)" "<()>" - "(|a)" "()" - "(a|)" "()" - "\"|\"" "<\"\">" - "\"a|b\"" "\"\"" - "[|]" "<[]>" - ";; hell|o" "<;; hello>" - - "( a|)" "( )" - "( )" "(< a>)" - "(< a>)" "<( a)>" - - "@" "<@deref>")) - - (deftest enter-and-indent - (are [input expected] - (= (apply-cmd commands/enter-and-indent input) expected) - - "(|)" "(\n |)" - "((|))" "((\n |))" - "(()|)" "(()\n |)" - "(a |b)" "(a\n |b)" - "(a b|c)" "(a b\n |c)"))) diff --git a/src-squint/nextjournal/clojure_mode_tests/macros.cljc b/src-squint/nextjournal/clojure_mode_tests/macros.cljc index 97b1b327..fd40bacd 100644 --- a/src-squint/nextjournal/clojure_mode_tests/macros.cljc +++ b/src-squint/nextjournal/clojure_mode_tests/macros.cljc @@ -1,8 +1,10 @@ (ns nextjournal.clojure-mode-tests.macros (:require [clojure.walk :as walk])) -(defmacro deftest [_var-name & body] - `(do ~@body)) +(defmacro deftest [var-name & body] + `(do + (~'js* "// ~{}\n" ~var-name) + ~@body)) (defmacro testing [_str & body] `(do ~@body)) @@ -63,7 +65,12 @@ (and (pos? (count argv)) (pos? (count args)) (zero? (mod (count args) (count argv))))) - `(do ~@(map (fn [a] (apply-template argv (->assert expr) a)) - (partition (count args) args))) + (let [processed (map (fn [a] + (apply-template argv (->assert expr) a)) + (partition (count argv) args))] + #_(println "======") + #_(println args) + #_(println processed) + `(do ~@processed)) #?(:clj (throw (IllegalArgumentException. "The number of args doesn't match are's argv.")) :cljs (throw (js/Error "The number of args doesn't match are's argv."))))) diff --git a/test/nextjournal/clojure_mode_tests.cljs b/test/nextjournal/clojure_mode_tests.cljc similarity index 86% rename from test/nextjournal/clojure_mode_tests.cljs rename to test/nextjournal/clojure_mode_tests.cljc index 130bfbca..b5ad414b 100644 --- a/test/nextjournal/clojure_mode_tests.cljs +++ b/test/nextjournal/clojure_mode_tests.cljc @@ -1,12 +1,15 @@ (ns nextjournal.clojure-mode-tests - (:require [cljs.test :refer [is are testing deftest]] + (:require #?@(:squint [] + :cljs [[cljs.test :refer [are testing deftest]]]) [nextjournal.clojure-mode :as cm-clojure] [nextjournal.clojure-mode.test-utils :as test-utils] [nextjournal.clojure-mode.extensions.close-brackets :as close-brackets] [nextjournal.clojure-mode.commands :as commands] [nextjournal.clojure-mode.extensions.formatting :as format] - [nextjournal.livedoc :as livedoc] - [nextjournal.clojure-mode.live-grammar :as live-grammar])) + #?@(:squint [] + :cljs [[nextjournal.livedoc :as livedoc]]) + #?(:squint ["assert" :as assert])) + #?(:squint (:require-macros [nextjournal.clojure-mode-tests.macros :refer [deftest are testing]]))) (def extensions cm-clojure/default-extensions @@ -18,8 +21,11 @@ (def apply-f (partial test-utils/apply-f extensions)) (def apply-cmd (partial test-utils/apply-cmd extensions)) -(def apply-embedded-f (partial test-utils/apply-f #js [livedoc/markdown-language-support])) -(def apply-embedded-cmd (partial test-utils/apply-cmd #js [livedoc/markdown-language-support])) +#?(:squint nil + :cljs (def apply-embedded-f (partial test-utils/apply-f #js [livedoc/markdown-language-support]))) + +#?(:squint nil + :cljs (def apply-embedded-cmd (partial test-utils/apply-cmd #js [livedoc/markdown-language-support]))) (do (deftest nav @@ -117,14 +123,15 @@ "\"[|]\"" "\"|]\"" ;; normal deletion inside strings )) - (testing "handle backspace (embedded)" - (are [input expected] - (= (apply-embedded-f close-brackets/handle-backspace input) - expected) - "```\n()|\n```" "```\n(|)\n```" - "```\n[[]]|\n```" "```\n[[]|]\n```" - "```\n(| )\n```" "```\n|\n```" - ))) + #?(:squint nil + :cljs (testing "handle backspace (embedded)" + (are [input expected] + (= (apply-embedded-f close-brackets/handle-backspace input) + expected) + "```\n()|\n```" "```\n(|)\n```" + "```\n[[]]|\n```" "```\n[[]|]\n```" + "```\n(| )\n```" "```\n|\n```" + )))) (deftest indentSelection @@ -263,14 +270,16 @@ "'ab|c 1" 1 "'ab|c 1" )) - (deftest slurp-embedded - (are [input dir expected] - (= (apply-embedded-f (commands/slurp dir) input) expected) - "```\n(|) a\n```" 1 "```\n(|a)\n```" - "```\n((|)) a\n```" 1 "```\n((|) a)\n```" - "```\n(|) ;;comment\na\n```" 1 "```\n(|;;comment\n a)\n```" - "```\n('xy|z 1) 2\n```" 1 "```\n('xy|z 1 2)\n```" - )) + #?(:squint nil + :cljs + (deftest slurp-embedded + (are [input dir expected] + (= (apply-embedded-f (commands/slurp dir) input) expected) + "```\n(|) a\n```" 1 "```\n(|a)\n```" + "```\n((|)) a\n```" 1 "```\n((|) a)\n```" + "```\n(|) ;;comment\na\n```" 1 "```\n(|;;comment\n a)\n```" + "```\n('xy|z 1) 2\n```" 1 "```\n('xy|z 1 2)\n```" + ))) (deftest barf (are [input dir expected] From 9cbda27fc3e274569f58ca15185ab7524a41ad50 Mon Sep 17 00:00:00 2001 From: Michiel Borkent Date: Tue, 31 Oct 2023 15:35:12 +0100 Subject: [PATCH 79/80] Add clj-kondo config --- .clj-kondo/config.edn | 4 ++++ .gitignore | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 .clj-kondo/config.edn diff --git a/.clj-kondo/config.edn b/.clj-kondo/config.edn new file mode 100644 index 00000000..38ca8084 --- /dev/null +++ b/.clj-kondo/config.edn @@ -0,0 +1,4 @@ +{:cljc {:features [:cljs]} + :lint-as {applied-science.js-interop/defn clojure.core/defn + applied-science.js-interop/fn clojure.core/fn + applied-science.js-interop/let clojure.core/let}} diff --git a/.gitignore b/.gitignore index c576685d..b66f62a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,8 @@ .shadow-cljs .idea .calva -.clj-kondo +.cache .cpcache -.lsp public/js public/livedoc/js node_modules From 52308558296d7794f44ee32f93e06924c45a6983 Mon Sep 17 00:00:00 2001 From: Andrea Amantini Date: Tue, 31 Oct 2023 16:20:08 +0100 Subject: [PATCH 80/80] Prepare for NPM release --- package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package.json b/package.json index f5341193..6a7bc237 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,11 @@ { "name": "@nextjournal/clojure-mode", "files": ["dist"], + "version": "0.1.0-rc2", + "license": "EPL-2.0", + "repository": { + "type": "git", + "url": "https://github.com/nextjournal/clojure-mode" + }, "dependencies": { "@codemirror/autocomplete": "^6.0.2", "@codemirror/commands": "^6.0.0",