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 f63ec476..f3ebf128 100644 --- a/src/nextjournal/clojure_mode.cljs +++ b/src/nextjournal/clojure_mode.cljs @@ -1,13 +1,12 @@ (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])) @@ -65,8 +64,7 @@ (close-brackets/extension) (match-brackets/extension) (sel-history/extension) - (format/ext-format-changed-lines) - (eval-region/extension {:modifier "Alt"})]) + (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 64b7d77e..427ba530 100644 --- a/src/nextjournal/clojure_mode/extensions/eval_region.cljs +++ b/src/nextjournal/clojure_mode/extensions/eval_region.cljs @@ -66,8 +66,10 @@ (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 "background-color: transparent;"}})) +(defonce mark:selected (j/lit {:attributes {:style "background-color: rgba(0, 243, 255, 0.14);"}})) (defn cursor-range [^js state] (if (.. state -selection -main -empty) @@ -79,12 +81,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 [RegionModifier Shift Enter]} (get-modifier-field state)] + (if-some [[spec range] (when (or (n/embedded? state) (n/within-program? 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)})] + RegionModifier (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))))}))) @@ -97,12 +101,21 @@ (u/guard #(j/get % :value))) (.. state -selection -main))) +(defn current-str [state] + (u/range-str state (current-range state))) + (defn modifier-extension "Maintains modifier-state-field, containing a map of { true}, including Enter." - [modifier] + [{:keys [modifier + 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)) - nil) + (when on-enter + (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) @@ -113,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)) @@ -128,6 +144,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}])) 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"