-
-
Notifications
You must be signed in to change notification settings - Fork 21
/
cs_conn_shadow_cljs.py
105 lines (91 loc) · 3.93 KB
/
cs_conn_shadow_cljs.py
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
104
105
import os, re, sublime, sublime_plugin
from . import cs_common, cs_conn, cs_conn_nrepl_raw, cs_eval
class ConnectionShadowCljs(cs_conn_nrepl_raw.ConnectionNreplRaw):
"""
Shadow CLJS connnection. Requires an additional argument: build
"""
def __init__(self, addr, build):
super().__init__(addr)
self.build = build
def handle_connect(self, msg):
if 1 == msg.get('id') and 'new-session' in msg:
self.session = msg['new-session']
self.set_status(2, 'Upgrading REPL')
if self.build == 'node-repl':
code = '(shadow.cljs.devtools.api/node-repl)'
elif self.build == 'browser-repl':
code = '(shadow.cljs.devtools.api/browser-repl)'
else:
code = f'(shadow.cljs.devtools.api/repl {self.build})'
self.send({'id': 2,
'session': self.session,
'op': 'eval',
'code': code})
return True
elif 2 == msg.get('id') and msg.get('status') == ['done']:
self.set_status(4, self.get_addr())
return True
def handle_value(self, msg):
if 'value' in msg and (id := msg.get('id')):
eval = cs_eval.by_id(id)
value = msg.get('value')
if eval and eval.status == 'exception' and ('nil' == value or value.startswith(':repl/')):
pass
else:
cs_eval.on_success(id, msg.get('value'))
return True
def handle_err(self, msg):
if 'err' in msg and (id := msg.get('id')):
eval = cs_eval.by_id(id)
trace = msg['err']
error = re.sub(r'\s*------+\s*', '', trace)
if eval and eval.status == 'exception':
trace = eval.trace + '\n' + trace
error = eval.value + '\n' + error
cs_eval.on_exception(id, error, trace = trace)
return True
def load_file_impl(self, id, file, path):
msg = {'id': id,
'session': self.session,
'op': 'load-file',
'file': file,
'file-name': os.path.basename(path) if path else "NO_SOURCE_FILE.cljc"}
if path:
msg['file-path'] = path
self.send(msg)
def load_file(self, view):
if view.file_name():
super().load_file(view)
else:
self.eval(view, [sublime.Region(0, view.size())])
class BuildInputHandler(sublime_plugin.TextInputHandler):
def initial_text(self):
return ':app'
def preview(self, text):
return sublime.Html("""
<html>
<body>
Provide the cljs build for shadow to watch.
<br>
Valid options are <b>node-repl</b>, <b>browser-repl</b> or the build defined in shadow-cljs.edn / project.clj
For more info check <a href="https://shadow-cljs.github.io/docs/UsersGuide.html#_repl_2"> Shadow Documentation </a>
</body>
</html>
""")
class ClojureSublimedConnectShadowCljsCommand(sublime_plugin.WindowCommand):
def run(self, address, build, timeout = 0):
state = cs_common.get_state(self.window)
state.last_conn = ('clojure_sublimed_connect_shadow_cljs', {'address': address, 'build': build})
ConnectionShadowCljs(address, build).try_connect(timeout = timeout)
def input(self, args):
if 'address' in args and 'build' in args:
pass
elif 'address' in args:
return BuildInputHandler()
elif 'build' in args:
return cs_conn.AddressInputHandler(port_files = ['.nrepl-port', '.shadow-cljs/nrepl.port'])
else:
return cs_conn.AddressInputHandler(port_files = ['.nrepl-port', '.shadow-cljs/nrepl.port'], next_input = BuildInputHandler())
def is_enabled(self):
state = cs_common.get_state(self.window)
return state.conn is None