From 9516d08a6a3f69f59bdda032c255e5535e46a217 Mon Sep 17 00:00:00 2001 From: Matthew Huebert Date: Wed, 14 Sep 2022 10:09:09 +0200 Subject: [PATCH 1/5] Add defs for extensions in clojure-mode api ns --- src/nextjournal/clojure_mode.cljs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/nextjournal/clojure_mode.cljs b/src/nextjournal/clojure_mode.cljs index f63ec476..be752014 100644 --- a/src/nextjournal/clojure_mode.cljs +++ b/src/nextjournal/clojure_mode.cljs @@ -12,6 +12,7 @@ [nextjournal.clojure-mode.node :as n] [nextjournal.clojure-mode.test-utils :as test-utils])) +(def format-props format/props) (def fold-node-props (let [coll-span (fn [^js tree] #js{:from (inc (n/start tree)) :to (dec (n/end tree))})] @@ -52,7 +53,7 @@ ([] (syntax parser)) ([^js parser] (.define LRLanguage - #js {:parser (.configure parser #js {:props #js [format/props + #js {:parser (.configure parser #js {:props #js [format-props (.add language/foldNodeProp fold-node-props) (highlight/styleTags style-tags)]})}))) @@ -60,13 +61,19 @@ (def ^js/Array builtin-keymap keymap/builtin) (def ^js/Array paredit-keymap keymap/paredit) +(def match-brackets match-brackets/extension) +(def close-brackets close-brackets/extension) +(def selection-history sel-history/extension) +(def format-changed-lines format/ext-format-changed-lines) +(def eval-region eval-region/extension) + (def default-extensions #js[(syntax lezer-clj/parser) - (close-brackets/extension) - (match-brackets/extension) - (sel-history/extension) - (format/ext-format-changed-lines) - (eval-region/extension {:modifier "Alt"})]) + (match-brackets) + (close-brackets) + (selection-history) + (format-changed-lines) + (eval-region {:modifier "Alt"})]) (def language-support "Eases embedding clojure mode into other languages (e.g. markdown). From 9a810262661fb4ce830f4fd2c5e260fedc73070f Mon Sep 17 00:00:00 2001 From: Matthew Huebert Date: Wed, 21 Sep 2022 16:06:08 +0200 Subject: [PATCH 2/5] add eval option to eval-region extension --- .../clojure_mode/extensions/eval_region.cljs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/nextjournal/clojure_mode/extensions/eval_region.cljs b/src/nextjournal/clojure_mode/extensions/eval_region.cljs index 64b7d77e..4d9d43a9 100644 --- a/src/nextjournal/clojure_mode/extensions/eval_region.cljs +++ b/src/nextjournal/clojure_mode/extensions/eval_region.cljs @@ -97,12 +97,18 @@ (u/guard #(j/get % :value))) (.. state -selection -main))) -(defn modifier-extension +(defn extension "Maintains modifier-state-field, containing a map of { true}, including Enter." - [modifier] + [{:keys [modifier + eval-string!] + :or {modifier "Alt"}}] (let [handle-enter (j/fn handle-enter [^:js {:as view :keys [state]}] (set-modifier-field! view (assoc (get-modifier-field state) "Enter" true)) - nil) + (when-let [source (and eval-string! + (-> (u/range-str state (current-range state)) + (u/guard (complement str/blank?))))] + (eval-string! source) + true)) handle-key-event (j/fn [^:js {:as event :keys [altKey shiftKey metaKey controlKey type]} ^:js {:as view :keys [state]}] (let [prev (get-modifier-field state) @@ -123,7 +129,9 @@ (dispatch (j/lit {:changes {:from from :to to :insert ""} :annotations (u/user-event-annotation "delete")}))) true))] - #js[modifier-field + #js[region-field + (.. EditorView -decorations (from region-field)) + modifier-field (.of keymap (j/lit [{:key (str modifier "-Enter") :shift handle-enter @@ -135,12 +143,6 @@ #js{:keydown handle-key-event :keyup handle-key-event})])) -(defn extension [{:keys [modifier] - :or {modifier "Alt"}}] - #js[(modifier-extension modifier) - region-field - (.. EditorView -decorations (from region-field))]) - (defn cursor-node-string [^js state] (u/guard (some->> (node-at-cursor state) (u/range-str state)) From 35fb41584e3e071b6f68f2e2185e2fd2bc6a0693 Mon Sep 17 00:00:00 2001 From: Matthew Huebert Date: Mon, 26 Sep 2022 13:45:47 +0200 Subject: [PATCH 3/5] - Support shift+enter for evaluating entire doc (maybe: do this in maria directly) --- .../clojure_mode/extensions/eval_region.cljs | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/nextjournal/clojure_mode/extensions/eval_region.cljs b/src/nextjournal/clojure_mode/extensions/eval_region.cljs index 4d9d43a9..67c63a8e 100644 --- a/src/nextjournal/clojure_mode/extensions/eval_region.cljs +++ b/src/nextjournal/clojure_mode/extensions/eval_region.cljs @@ -66,8 +66,11 @@ (defn single-mark [spec range] (.set Decoration #js[(mark spec range)])) -(defonce mark-spec (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.14);"}})) -(defonce mark-spec-highlight (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.35);"}})) + +;; TODO - parameterize mark colors +(defonce mark:none (j/lit {:attributes {:style {}}})) +(defonce mark:selected (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.14);"}})) +(defonce mark:evaluating (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.35);"}})) (defn cursor-range [^js state] (if (.. state -selection -main -empty) @@ -79,12 +82,14 @@ (j/lit {:create (constantly (.-none Decoration)) :update (j/fn [_value ^:js {:keys [state]}] - (let [{:strs [Alt Shift Enter]} (get-modifier-field state) - spec (if Enter mark-spec-highlight mark-spec)] - (if-some [range (when (or (n/embedded? state) (n/within-program? state)) - (cond (and Alt Shift) (top-level-node state) - Alt (or (u/guard (main-selection state) #(not (j/get % :empty))) - (cursor-range state))))] + (let [{:strs [Alt Shift Enter]} (get-modifier-field state)] + (if-some [[spec range] (when (or (n/embedded? state) (n/within-program? state)) + (cond (and Alt Shift) [mark:selected (top-level-node state)] + (and Enter Shift) [mark:selected (top-level-node state)] + Shift [mark:none (j/lit {:from 0 :to (.. state -doc -length)})] + Alt (when-let [range (or (u/guard (main-selection state) (complement (j/get :empty))) + (cursor-range state))] + [mark:selected range])))] (single-mark spec range) (.-none Decoration))))}))) @@ -100,14 +105,12 @@ (defn extension "Maintains modifier-state-field, containing a map of { true}, including Enter." [{:keys [modifier - eval-string!] + on-enter] :or {modifier "Alt"}}] (let [handle-enter (j/fn handle-enter [^:js {:as view :keys [state]}] - (set-modifier-field! view (assoc (get-modifier-field state) "Enter" true)) - (when-let [source (and eval-string! - (-> (u/range-str state (current-range state)) - (u/guard (complement str/blank?))))] - (eval-string! source) + (when on-enter + (set-modifier-field! view (assoc (get-modifier-field state) "Enter" true)) + (on-enter (u/range-str state (current-range state))) true)) handle-key-event (j/fn [^:js {:as event :keys [altKey shiftKey metaKey controlKey type]} ^:js {:as view :keys [state]}] @@ -136,6 +139,9 @@ (j/lit [{:key (str modifier "-Enter") :shift handle-enter :run handle-enter} + {:key "Enter" + :shift handle-enter + :run handle-enter} {:key (str modifier "-Backspace") :run handle-backspace :shift handle-backspace}])) From 2720bd140ac8625890d558b6748b09a17a7214e2 Mon Sep 17 00:00:00 2001 From: Matthew Huebert Date: Sun, 23 Oct 2022 21:41:07 +0200 Subject: [PATCH 4/5] eval-region: add current-str, adjust enter behaviour --- .../clojure_mode/extensions/eval_region.cljs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/nextjournal/clojure_mode/extensions/eval_region.cljs b/src/nextjournal/clojure_mode/extensions/eval_region.cljs index 67c63a8e..8b4437f1 100644 --- a/src/nextjournal/clojure_mode/extensions/eval_region.cljs +++ b/src/nextjournal/clojure_mode/extensions/eval_region.cljs @@ -68,7 +68,7 @@ ;; TODO - parameterize mark colors -(defonce mark:none (j/lit {:attributes {:style {}}})) +(defonce mark:none (j/lit {:attributes {:style "background-color: transparent;"}})) (defonce mark:selected (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.14);"}})) (defonce mark:evaluating (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.35);"}})) @@ -102,6 +102,9 @@ (u/guard #(j/get % :value))) (.. state -selection -main))) +(defn current-str [state] + (u/range-str state (current-range state))) + (defn extension "Maintains modifier-state-field, containing a map of { true}, including Enter." [{:keys [modifier @@ -109,9 +112,11 @@ :or {modifier "Alt"}}] (let [handle-enter (j/fn handle-enter [^:js {:as view :keys [state]}] (when on-enter - (set-modifier-field! view (assoc (get-modifier-field state) "Enter" true)) - (on-enter (u/range-str state (current-range state))) - true)) + (let [mods (get-modifier-field state)] + (set-modifier-field! view (assoc mods "Enter" true)) + (on-enter (u/range-str state (current-range state))) + (when (seq mods) + true)))) handle-key-event (j/fn [^:js {:as event :keys [altKey shiftKey metaKey controlKey type]} ^:js {:as view :keys [state]}] (let [prev (get-modifier-field state) From ce5a6751dd72af4809df6d49a68e5e71237334fd Mon Sep 17 00:00:00 2001 From: Matthew Huebert Date: Mon, 3 Jul 2023 06:03:41 -0600 Subject: [PATCH 5/5] manually merge main --- demo/src/nextjournal/clojure_mode/demo.cljs | 22 +++++++++-------- package.json | 2 +- shadow-cljs.edn | 8 ++----- src/deps.cljs | 2 +- src/nextjournal/clojure_mode.cljs | 21 +++++----------- .../clojure_mode/extensions/eval_region.cljs | 24 ++++++++++++------- src/nextjournal/clojure_mode/node.cljs | 2 +- yarn.lock | 14 +++++------ 8 files changed, 45 insertions(+), 50 deletions(-) diff --git a/demo/src/nextjournal/clojure_mode/demo.cljs b/demo/src/nextjournal/clojure_mode/demo.cljs index d21f3cd3..bc98462f 100644 --- a/demo/src/nextjournal/clojure_mode/demo.cljs +++ b/demo/src/nextjournal/clojure_mode/demo.cljs @@ -1,22 +1,23 @@ (ns nextjournal.clojure-mode.demo - (:require ["@codemirror/language" :refer [foldGutter syntaxHighlighting defaultHighlightStyle]] - ["@codemirror/commands" :refer [history historyKeymap]] + (:require ["@codemirror/commands" :refer [history historyKeymap]] + ["@codemirror/language" :refer [foldGutter syntaxHighlighting defaultHighlightStyle]] ["@codemirror/state" :refer [EditorState]] ["@codemirror/view" :as view :refer [EditorView]] - [nextjournal.clerk.sci-viewer :as sv] - [nextjournal.clerk.viewer :as v] + ["react" :as react] [applied-science.js-interop :as j] - [shadow.resource :as rc] [clojure.string :as str] + [nextjournal.clerk.sci-viewer :as sv] + [nextjournal.clerk.viewer :as v] [nextjournal.clojure-mode :as cm-clj] - [nextjournal.livedoc :as livedoc] [nextjournal.clojure-mode.demo.sci :as demo.sci] + [nextjournal.clojure-mode.extensions.eval-region :as eval-region] [nextjournal.clojure-mode.keymap :as keymap] [nextjournal.clojure-mode.live-grammar :as live-grammar] [nextjournal.clojure-mode.test-utils :as test-utils] - ["react" :as react] + [nextjournal.livedoc :as livedoc] [reagent.core :as r] - [reagent.dom :as rdom])) + [reagent.dom :as rdom] + [shadow.resource :as rc])) (def theme (.theme EditorView @@ -62,7 +63,8 @@ (j/obj :state (test-utils/make-state (cond-> #js [extensions] - eval? (.concat #js [(demo.sci/extension {:modifier "Alt" + eval? (.concat #js [(eval-region/extension {:modifier "Alt"}) + (demo.sci/extension {:modifier "Alt" :on-result (partial reset! last-result)})])) source) :parent el)))))] @@ -78,7 +80,7 @@ (react/isValidElement result) result 'else (sv/inspect-paginated result)))])] (finally - (j/call @!view :destroy)))) + (j/call @!view :destroy)))) ;; Markdown editors (defn markdown-editor [{:keys [doc extensions]}] diff --git a/package.json b/package.json index 3fb10dc5..1f5e12ae 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "@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", - "lezer-clojure": "1.0.0-rc.2", "markdown-it": "12.3.2", "markdown-it-block-image": "0.0.3", "markdown-it-sidenote": "gerwitz/markdown-it-sidenote#aa5de8ce3168b7d41cb33c3aed071a5f41ce0083", diff --git a/shadow-cljs.edn b/shadow-cljs.edn index 4ba041c9..dbe82195 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -18,12 +18,8 @@ :test {:compiler-options {:output-feature-set :es8} :target :browser-test :test-dir "public/test" - :ns-regexp "-tests$" - ;; sometimes I get weird $jscomp.inherits errors, which can be fixed - ;; by temporarily uncommenting the following forms in each build. - #_#_:js-options - {:resolve {"lezer-clojure" {:target :npm - :require "lezer-clojure/dist/index.cjs"}}}} + :ns-regexp "-tests$"} + :ci-test {:target :node-test :ns-regexp "-tests$" :output-dir "out" diff --git a/src/deps.cljs b/src/deps.cljs index da4a0865..125e9e07 100644 --- a/src/deps.cljs +++ b/src/deps.cljs @@ -11,5 +11,5 @@ "@lezer/generator" "^1.0.0" "@lezer/highlight" "^1.0.0" "@lezer/lr" "^1.0.0" - "lezer-clojure" "1.0.0-rc.2" + "@nextjournal/lezer-clojure" "1.0.0" "w3c-keyname" "^2.2.4"}} diff --git a/src/nextjournal/clojure_mode.cljs b/src/nextjournal/clojure_mode.cljs index be752014..f3ebf128 100644 --- a/src/nextjournal/clojure_mode.cljs +++ b/src/nextjournal/clojure_mode.cljs @@ -1,18 +1,16 @@ (ns nextjournal.clojure-mode (:require ["@lezer/highlight" :as highlight :refer [tags]] ["@codemirror/language" :as language :refer [LRLanguage LanguageSupport]] - ["lezer-clojure" :as lezer-clj] + ["@nextjournal/lezer-clojure" :as lezer-clj] [applied-science.js-interop :as j] [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] [nextjournal.clojure-mode.extensions.selection-history :as sel-history] - [nextjournal.clojure-mode.extensions.eval-region :as eval-region] [nextjournal.clojure-mode.keymap :as keymap] [nextjournal.clojure-mode.node :as n] [nextjournal.clojure-mode.test-utils :as test-utils])) -(def format-props format/props) (def fold-node-props (let [coll-span (fn [^js tree] #js{:from (inc (n/start tree)) :to (dec (n/end tree))})] @@ -53,7 +51,7 @@ ([] (syntax parser)) ([^js parser] (.define LRLanguage - #js {:parser (.configure parser #js {:props #js [format-props + #js {:parser (.configure parser #js {:props #js [format/props (.add language/foldNodeProp fold-node-props) (highlight/styleTags style-tags)]})}))) @@ -61,19 +59,12 @@ (def ^js/Array builtin-keymap keymap/builtin) (def ^js/Array paredit-keymap keymap/paredit) -(def match-brackets match-brackets/extension) -(def close-brackets close-brackets/extension) -(def selection-history sel-history/extension) -(def format-changed-lines format/ext-format-changed-lines) -(def eval-region eval-region/extension) - (def default-extensions #js[(syntax lezer-clj/parser) - (match-brackets) - (close-brackets) - (selection-history) - (format-changed-lines) - (eval-region {:modifier "Alt"})]) + (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). diff --git a/src/nextjournal/clojure_mode/extensions/eval_region.cljs b/src/nextjournal/clojure_mode/extensions/eval_region.cljs index 8b4437f1..427ba530 100644 --- a/src/nextjournal/clojure_mode/extensions/eval_region.cljs +++ b/src/nextjournal/clojure_mode/extensions/eval_region.cljs @@ -70,7 +70,6 @@ ;; TODO - parameterize mark colors (defonce mark:none (j/lit {:attributes {:style "background-color: transparent;"}})) (defonce mark:selected (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.14);"}})) -(defonce mark:evaluating (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.35);"}})) (defn cursor-range [^js state] (if (.. state -selection -main -empty) @@ -82,12 +81,12 @@ (j/lit {:create (constantly (.-none Decoration)) :update (j/fn [_value ^:js {:keys [state]}] - (let [{:strs [Alt Shift Enter]} (get-modifier-field state)] + (let [{:strs [RegionModifier Shift Enter]} (get-modifier-field state)] (if-some [[spec range] (when (or (n/embedded? state) (n/within-program? state)) - (cond (and Alt Shift) [mark:selected (top-level-node state)] + (cond (and RegionModifier Shift) [mark:selected (top-level-node state)] (and Enter Shift) [mark:selected (top-level-node state)] Shift [mark:none (j/lit {:from 0 :to (.. state -doc -length)})] - Alt (when-let [range (or (u/guard (main-selection state) (complement (j/get :empty))) + RegionModifier (when-let [range (or (u/guard (main-selection state) (complement (j/get :empty))) (cursor-range state))] [mark:selected range])))] (single-mark spec range) @@ -105,7 +104,7 @@ (defn current-str [state] (u/range-str state (current-range state))) -(defn extension +(defn modifier-extension "Maintains modifier-state-field, containing a map of { true}, including Enter." [{:keys [modifier on-enter] @@ -127,7 +126,10 @@ controlKey (assoc "Control" true) (and (= "keydown" type) (= "Enter" (keyName event))) - (assoc "Enter" true))] + (assoc "Enter" true)) + next (if (get next modifier) + (assoc next "RegionModifier" true) + next)] (when (not= prev next) (set-modifier-field! view next)) false)) @@ -137,9 +139,7 @@ (dispatch (j/lit {:changes {:from from :to to :insert ""} :annotations (u/user-event-annotation "delete")}))) true))] - #js[region-field - (.. EditorView -decorations (from region-field)) - modifier-field + #js[modifier-field (.of keymap (j/lit [{:key (str modifier "-Enter") :shift handle-enter @@ -154,6 +154,12 @@ #js{:keydown handle-key-event :keyup handle-key-event})])) +(defn extension [{:keys [modifier] + :or {modifier "Alt"}}] + #js[(modifier-extension modifier) + region-field + (.. EditorView -decorations (from region-field))]) + (defn cursor-node-string [^js state] (u/guard (some->> (node-at-cursor state) (u/range-str state)) diff --git a/src/nextjournal/clojure_mode/node.cljs b/src/nextjournal/clojure_mode/node.cljs index 8e24995f..1a9dfcda 100644 --- a/src/nextjournal/clojure_mode/node.cljs +++ b/src/nextjournal/clojure_mode/node.cljs @@ -3,7 +3,7 @@ (:require ["@lezer/common" :as lz-tree] ["@lezer/markdown" :as lezer-markdown] ["@codemirror/language" :as language] - ["lezer-clojure" :as lezer-clj] + ["@nextjournal/lezer-clojure" :as lezer-clj] [applied-science.js-interop :as j] [nextjournal.clojure-mode.util :as u] [nextjournal.clojure-mode.selections :as sel])) diff --git a/yarn.lock b/yarn.lock index 6349bb4b..a55b7a29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -195,6 +195,13 @@ "@lezer/common" "^1.0.0" "@lezer/highlight" "^1.0.0" +"@nextjournal/lezer-clojure@1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@nextjournal/lezer-clojure/-/lezer-clojure-1.0.0.tgz#0e7ff75f8d0fabed36d26b9f6b5f00d8a9f385e6" + integrity sha512-VZyuGu4zw5mkTOwQBTaGVNWmsOZAPw5ZRxu1/Knk/Xfs7EDBIogwIs5UXTYkuECX5ZQB8eOB+wKA2pc7VyqaZQ== + dependencies: + "@lezer/lr" "^1.0.0" + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -559,13 +566,6 @@ katex@^0.12.0: dependencies: commander "^2.19.0" -lezer-clojure@1.0.0-rc.2: - version "1.0.0-rc.2" - resolved "https://registry.yarnpkg.com/lezer-clojure/-/lezer-clojure-1.0.0-rc.2.tgz#cec59eafdd150bec9a5524214bc201b4ee117575" - integrity sha512-IdEwD9cq/PSTD3TBYHosqQQu4sKiBCdAcqucGimR0BwKRMnaPAjSgnj/JJ3ykmCwHf1pRHdVyr23gVaxYx2Tvg== - dependencies: - "@lezer/lr" "^1.0.0" - linkify-it@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e"