-
-
Notifications
You must be signed in to change notification settings - Fork 68
/
highlight_hiccup.cljs
103 lines (76 loc) · 3.62 KB
/
highlight_hiccup.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
;; TODO: make this a standalone library
(ns day8.re-frame-10x.tools.highlight-hiccup
(:require [clojure.walk :as walk]
[rewrite-clj.zip :as rz]
[rewrite-clj.node.token :refer [SymbolNode TokenNode]]
[rewrite-clj.node.whitespace :refer [WhitespaceNode NewlineNode CommaNode]]
[rewrite-clj.node.keyword :refer [KeywordNode]]
[rewrite-clj.node.stringz :refer [StringNode]]
[rewrite-clj.node.seq :refer [SeqNode]]
[day8.re-frame-10x.styles :as styles]
[day8.re-frame-10x.inlined-deps.re-frame.v1v1v2.re-frame.core :as rf]
[day8.re-frame-10x.panels.event.subs :as event.subs]))
(def clj-core-macros #{'and 'binding 'case 'catch 'comment 'cond 'cond-> 'cond->> 'condp 'def
'defmacro 'defn 'defn- 'defmulti 'defmethod 'defonce 'defprotocol 'deftype
'do 'dotimes 'doseq 'dosync 'fn 'for 'future 'if 'if-let 'if-not 'import 'let
'letfn 'locking 'loop 'ns 'or 'proxy 'quote 'recur 'set! 'struct-map 'sync 'throw
'try 'when 'when-first 'when-let 'when-not 'when-some 'while})
(defn selected-style [{:keys [position]}]
(when @(rf/subscribe [::event.subs/highlighted? position])
(styles/clj-highlighted)))
(defmulti form type)
(defmethod form :default [node] [:span.clj-unknown {:data-node (type node)} (str (type node))])
(defmulti tf2 (comp type :value))
(defmethod tf2 (type true) [{:keys [string-value]}]
[:code.clj__boolean {:class (styles/clj-boolean)}
string-value])
(defmethod tf2 (type 0) [{:keys [string-value]}]
[:code.clj_number {:class (styles/clj-number)}
string-value])
(defmethod tf2 (type nil) [{:keys [string-value]}]
[:code.clj__nil {:class (styles/clj-nil)} string-value])
(defmethod tf2 :default [{:keys [string-value] :as node}]
[:span.clj__token (str (keys node)) string-value])
(defmethod form TokenNode [node]
[tf2 node])
(defmethod form (type []) [node] node)
(defmethod form CommaNode [node] [:span.clj__comma ","])
(defmulti seq-form :tag)
(defmethod seq-form :default [{:keys [tag]}]
[:code.clj__unknown tag])
(defmethod seq-form :list [node]
(into [:code.seq {:class [(styles/clj-seq)
(selected-style node)]}]
(concat [ "("] (:children node) [")"])))
(defmethod seq-form :vector [node]
(into [:code.clj__seq] (concat ["["] (:children node) ["]"])))
(defmethod seq-form :map [node]
(into [:code.clj__map {:class [(selected-style node)]}]
(concat ["{"] (:children node) ["}"])))
(defmethod form SeqNode [node]
(seq-form node))
(defmethod form SymbolNode [{:keys [value string-value] :as node}]
[:code.clj__symbol {:class [(if (clj-core-macros value)
(styles/clj-core-macro)
(styles/clj-symbol))
(selected-style node)]}
string-value])
(defmethod form WhitespaceNode [node]
[:code.clj__whitespace {:style {:white-space "pre"}}
(:whitespace node)])
(defmethod form NewlineNode [_] [:br])
(defmethod form KeywordNode [{:keys [k] :as node}]
[:code.clj__keyword {:class [(styles/clj-keyword)
(selected-style node)]}
(str k)])
(defmethod form StringNode [{:keys [lines]}]
[:code.clj__string {:class (styles/clj-string)}
\" (apply str lines) \"])
(defn str->hiccup [s]
(let [positional-ast
(-> s
(rz/of-string {:track-position? true})
(rz/postwalk #(rz/edit* % assoc
:position (rz/position %)))
rz/node)]
(walk/postwalk #(cond-> % (record? %) form) positional-ast)))