Skip to content

Commit 31657f5

Browse files
mkmhuebertphilippamarkovics
authored andcommitted
eval-at-point for ClojureScript
* Command/Ctrl to temporarily select form at cursor * tweak how temp-selections behave around symbols and edges * paste should insert, not replace, temporary selections * cleanup * support backspace with temp selection * fix paste insertion * .gitignore * use keymap for paste-insert * initial setup of eval with sci and temp-selections * eval top-level * Option + Enter for eval-at-point/run selection * Adjust keybindings for demo * Alt-Shift-Enter to eval top level * temp-toplevel * bring back eval-cell * keep temp selection after grow/shrink, left/right moves cursor before/after toplevel * re-use sci context across invocations * top-level tempselection supports backspace * render multiple, smaller cells * formatting of demo cells * temp-selections as decorations * cleanup * Upgrade sci to 0.2.0 * Change temp cm selectin color to a lighter blue Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Matthew Huebert <[email protected]> Co-authored-by: Philipp Markovics <[email protected]>
1 parent ee81e77 commit 31657f5

File tree

16 files changed

+396
-133
lines changed

16 files changed

+396
-133
lines changed

.github/workflows/clojure.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
run: yarn
5555

5656
- name: Shadow-cljs
57-
run: yarn shadow-cljs release app
57+
run: yarn build
5858

5959
- name: Deploy 🚀
6060
uses: JamesIves/[email protected]

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
public/js
44
node_modules
55
public/test
6+
*.iml

deps.edn

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22
"src/test"]
33
:deps {applied-science/js-interop {:mvn/version "0.2.5"}
44
org.clojure/clojurescript {:mvn/version "1.10.773"}
5-
thheller/shadow-cljs {:mvn/version "2.11.1"}}}
5+
thheller/shadow-cljs {:mvn/version "2.11.1"}}
6+
:aliases
7+
{:demo {:extra-deps {borkdude/sci {:mvn/version "0.2.0"}
8+
reagent/reagent {:mvn/version "0.9.1"}}
9+
:extra-paths ["src/demo"]}}}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"w3c-keyname": "^2.2.4"
1414
},
1515
"scripts": {
16-
"watch": "shadow-cljs watch app test"
16+
"watch": "shadow-cljs -A:demo watch demo test",
17+
"build": "shadow-cljs -A:demo release demo"
1718
}
1819
}

public/index.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
</head>
1414
<body>
1515
<div class="landing-page">
16-
<div class="hero">
17-
<div class="lp-block">
16+
<div class="hero pb-4">
17+
<div>
1818
<h1>Clojure/Script mode for <a href="https://codemirror.net/6/">codemirror.next</a></h1>
1919
<p>
2020
Enable a decent Clojure/Script editor experience in the browser.
@@ -32,9 +32,9 @@ <h1>Clojure/Script mode for <a href="https://codemirror.net/6/">codemirror.next<
3232
</div>
3333
</div>
3434
</div>
35-
<div class="bg-alt pb-12 px-6">
35+
<div class="bg-alt pb-12 px-6 pt-3">
3636
<div class="max-w-4xl mx-auto">
37-
<div id="editor" class="mt-4 rounded-lg border mb-0 text-sm monospace overflow-auto relative shadow-lg bg-white" style="max-height: 500px; top: -2.5rem;"></div>
37+
<div id="editor"></div>
3838
</div>
3939
<div class="max-w-4xl mx-auto">
4040
<div id="docs" class="border-t-0 overflow-auto text-md p-0 m-0 mt-4 sans-serif"></div>

shadow-cljs.edn

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
:dev-http {8002 "public"
33
8001 "public/test"}
44
:nrepl {:port 9000}
5-
:builds {:app {:compiler-options {:output-feature-set :es8}
6-
:target :browser
7-
:output-dir "public/js"
8-
:asset-path "js"
9-
:modules {:main {:init-fn codemirror-next.clojure.demo/render}}}
5+
:builds {:demo {:compiler-options {:output-feature-set :es8}
6+
:target :browser
7+
:output-dir "public/js"
8+
:asset-path "js"
9+
:modules {:main {:init-fn codemirror-next.clojure.demo/render}}}
1010
:test {:compiler-options {:output-feature-set :es8}
1111
:target :browser-test
1212
:test-dir "public/test"

src/main/codemirror_next/clojure/demo.cljs renamed to src/demo/codemirror_next/clojure/demo.cljs

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
[applied-science.js-interop :as j]
1313
[clojure.string :as str]
1414
[codemirror-next.clojure :as cm-clj]
15+
[codemirror-next.clojure.demo.sci :as sci]
1516
[codemirror-next.clojure.extensions.close-brackets :as close-brackets]
1617
[codemirror-next.clojure.extensions.formatting :as format]
1718
[codemirror-next.clojure.extensions.selection-history :as sel-history]
@@ -20,20 +21,25 @@
2021
[codemirror-next.clojure.node :as n]
2122
[codemirror-next.clojure.selections :as sel]
2223
[codemirror-next.test-utils :as test-utils]
23-
[shadow.resource :as rc])
24-
(:require-macros [codemirror-next.build :as build]))
24+
[reagent.core :as r]
25+
[reagent.dom :as rdom]
26+
[shadow.resource :as rc]))
2527

2628
(def theme
2729
(.theme EditorView
28-
(j/lit {:$content {:white-space "pre-wrap"}
30+
(j/lit {:$content {:white-space "pre-wrap"
31+
:padding "10px 0"}
2932
:$$focused {:outline "none"}
3033
:$line {:padding "0 9px"
3134
:line-height "1.6"
3235
:font-size "16px"
3336
:font-family "var(--code-font)"}
3437
:$matchingBracket {:border-bottom "1px solid var(--teal-color)"
3538
:color "inherit"}
36-
;; only show cursor when focused
39+
:$gutters {:background "transparent"
40+
:border "none"}
41+
:$gutterElement {:margin-left "5px"}
42+
;; only show cursor when focused
3743
:$cursor {:visibility "hidden"}
3844
"$$focused $cursor" {:visibility "visible"}})))
3945

@@ -42,7 +48,7 @@
4248
(history)
4349
highlight/defaultHighlightStyle
4450
(view/drawSelection)
45-
(lineNumbers)
51+
;(lineNumbers)
4652
(fold/foldGutter)
4753
(.. EditorState -allowMultipleSelections (of true))
4854
(if false
@@ -53,45 +59,39 @@
5359
(view/keymap cm-clj/complete-keymap)
5460
(view/keymap historyKeymap)])
5561

56-
(defn sample-text []
57-
(str "(defn lezer-clojure
58-
\"This is a showcase for `lezer-clojure`, a grammar for Clojure/Script to enable a decent editor experience in the browser.\"
59-
{:added \"0.1\"}
60-
[demo]
61-
nil ;; nil
62-
(+ 1 1.0 1/5 1E3 042 +042 -042) ;; numbers
63-
:hi :hi/ho ::ho :*+!-_? :abc:def:ghi ;; keywords
64-
true false ;; booleans
65-
:hello #_ :ignored ;; ignore next form
66-
#\"[A-Z]\" ;; regex
67-
^{:meta/data 'is-data} 'too
68-
(if (test? <demo>)
69-
(inc demo)|
70-
(dec demo)))
71-
#
72-
[ ]
73-
#\"a\""
74-
\newline
75-
"a b(c|)d e"
76-
)
62+
(defn editor [source]
63+
(r/with-let [!view (atom nil)
64+
last-result (r/atom (sci/eval-string source))
65+
mount! (fn [el]
66+
(when el
67+
(reset! !view (new EditorView
68+
(j/obj :state
69+
(test-utils/make-state
70+
#js[extensions
71+
(sci/extension {:modifier "Alt"
72+
:on-result (partial reset! last-result)})] source)
73+
:parent el)))))]
74+
[:div
75+
[:div {:class "mt-4 rounded-md border mb-0 text-sm monospace overflow-auto relative shadow-md bg-white"
76+
:ref mount!}]
77+
[:div.mt-3.mv-4.pl-6 {:style {:white-space "pre-wrap" :font-family "monospace"}}
78+
(prn-str @last-result)]]
79+
(finally
80+
(j/call @!view :destroy))))
7781

78-
)
79-
80-
(defonce prev-views (atom []))
81-
82-
(defn mount-editor! [dom-selector initial-value]
83-
(let [state (test-utils/make-state extensions initial-value)]
84-
(->> (j/obj :state state :parent (js/document.querySelector dom-selector))
85-
(new EditorView)
86-
(swap! prev-views conj))))
82+
(defn samples []
83+
(into [:<>]
84+
(for [source ["(rand-nth (range 1000))"
85+
"(defn greeting [first-name] \n (str \"Hello, \" first-name))"
86+
"(greeting \"fido\")"]]
87+
[editor source])))
8788

8889
(defn tag [tag & s]
8990
(let [[opts s] (if (map? (first s)) [(first s) (rest s)] [nil s])]
9091
(str "<" (name tag) (reduce-kv #(str %1 " " (name %2) "=" "'" %3 "'") "" opts) ">" (apply str s) "</" (name tag) ">")))
9192

9293
(defn ^:dev/after-load render []
93-
(doseq [v @prev-views] (j/call v :destroy))
94-
(mount-editor! "#editor" (sample-text))
94+
(rdom/render [samples] (js/document.getElementById "editor"))
9595
(j/assoc! (js/document.getElementById "docs")
9696
:innerHTML
9797
(tag :div
@@ -112,15 +112,11 @@
112112
(tag :td {:class "px-3 py-1 align-top monospace text-sm"}
113113
(str "Shift-" key))
114114
(tag :td {:class "px-3 py-1 align-top"} ""))))) ""))
115-
"</table>")))
116-
#_(j/assoc! (js/document.getElementById "readme")
117-
:innerHTML
118-
(tag :pre {:class "mt-4"} (build/slurp "README.md")))
119-
(.focus (last @prev-views)))
115+
"</table>"))))
120116

121117

122118
(comment
123-
(let [s "#(a )"
124-
state (test-utils/make-state default-extensions s)
125-
tree (n/tree state)]
126-
))
119+
(let [s "#(a )"
120+
state (test-utils/make-state default-extensions s)
121+
tree (n/tree state)]
122+
))
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
(ns codemirror-next.clojure.demo.sci
2+
(:require ["@codemirror/next/view" :as view]
3+
[applied-science.js-interop :as j]
4+
[sci.core :as sci]
5+
[codemirror-next.clojure.node :as n]
6+
[codemirror-next.clojure.extensions.temp-selection :as temp-selection]
7+
[codemirror-next.clojure.util :as u]))
8+
9+
(defonce context (sci/init {}))
10+
11+
(defn eval-string [source]
12+
(try (sci/eval-string* context source)
13+
(catch js/Error e
14+
(str e))))
15+
16+
(j/defn eval-current-range [on-result ^:js {:as view :keys [state]}]
17+
(some->> (temp-selection/current-string state)
18+
(eval-string)
19+
(on-result))
20+
true)
21+
22+
(j/defn eval-cell [on-result ^:js {:as view :keys [state]}]
23+
(-> (str "(do " (.-doc state) " )")
24+
(eval-string)
25+
(on-result))
26+
true)
27+
28+
(defn extension [{:keys [modifier
29+
on-result]}]
30+
(view/keymap
31+
(j/lit
32+
[{:key "Mod-Enter"
33+
:run (partial eval-cell on-result)}
34+
{:key (str modifier "-Enter")
35+
:shift (partial eval-current-range on-result)
36+
:run (partial eval-current-range on-result)}])))

src/main/codemirror_next/build.clj

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/main/codemirror_next/clojure.cljs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
[codemirror-next.clojure.extensions.match-brackets :as match-brackets]
1313
[codemirror-next.clojure.extensions.formatting :as format]
1414
[codemirror-next.clojure.extensions.selection-history :as sel-history]
15+
[codemirror-next.clojure.extensions.temp-selection :as temp-selection]
1516
[codemirror-next.clojure.keymap :as keymap]
1617
[codemirror-next.clojure.node :as n]
1718
[codemirror-next.clojure.selections :as sel]
@@ -77,7 +78,8 @@
7778
(match-brackets/extension)
7879
(sel-history/extension)
7980
(format/ext-format-changed-lines)
80-
(.-lineWrapping EditorView)])
81+
(.-lineWrapping EditorView)
82+
(temp-selection/as-decoration {:modifier "Alt"})])
8183

8284
(comment
8385

0 commit comments

Comments
 (0)