Skip to content

Commit 328d051

Browse files
author
Sainadh Devireddy
committed
Shadow-cljs to separate command + refactor + Readme update
1 parent abfdc5b commit 328d051

File tree

3 files changed

+79
-28
lines changed

3 files changed

+79
-28
lines changed

Default.sublime-commands

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
"caption": "Clojure Sublimed: Connect",
44
"command": "clojure_sublimed_connect"
55
},
6+
{
7+
"caption": "Clojure Sublimed: Connect shadow-cljs",
8+
"command": "clojure_sublimed_connect_shadow_cljs"
9+
},
610
{
711
"caption": "Clojure Sublimed: Disconnect",
812
"command": "clojure_sublimed_disconnect"

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,18 @@ Differences from [Tutkain](https://tutkain.flowthing.me/):
107107

108108
Important! Make sure you switched your syntax to `Clojure (Sublimed)`.
109109

110+
For Clojure apps
111+
110112
1. Run nREPL server.
111113
2. Run `Clojure Sublimed: Connect` command.
112114

115+
For Shadow-cljs apps
116+
117+
1. Run `shadow-cljs watch app`. (This starts a HTTP server and an nREPL)
118+
2. If you are building a web-app, open the http-server url (from step 1) in the browser. This connects the shadow server to JS runtime.
119+
3. Run `Clojure Sublimed: Connect shadow-cljs` command from sublime's command palette.
120+
121+
113122
### Evaluating code from buffer
114123

115124
From here you have three options:

package.py

Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,25 @@ def format_time_taken(time_taken):
2222
else:
2323
return f"({'{:.2f}'.format(elapsed * 1000)} ms)"
2424

25+
26+
def get_middleware_opts(conn):
27+
"""Returns middleware options to send to nREPL as a dict.
28+
Currently only Clojure profile supports middleware.
29+
"""
30+
if conn and conn.profile == Profile.CLOJURE:
31+
return {
32+
"nrepl.middleware.caught/caught": f"{ns}.middleware/print-root-trace",
33+
"nrepl.middleware.print/print": f"{ns}.middleware/pprint",
34+
"nrepl.middleware.print/quota": 4096
35+
}
36+
return {}
37+
38+
2539
class Profile:
2640
CLOJURE = 'clojure'
2741
SHADOW_CLJS = 'shadow-cljs'
2842

43+
2944
class Eval:
3045
# class
3146
next_id: int = 10
@@ -371,10 +386,9 @@ def eval_msg(view, region, msg):
371386
progress_thread.wake()
372387
eval.msg = {k: v for k, v in msg.items() if v}
373388
eval.msg["id"] = eval.id
374-
eval.msg["nrepl.middleware.caught/caught"] = f"{ns}.middleware/print-root-trace"
375-
eval.msg["nrepl.middleware.print/print"] = f"{ns}.middleware/pprint"
376-
eval.msg["nrepl.middleware.print/quota"] = 4096
377389
eval.msg["session"] = conn.session
390+
eval.msg.update(get_middleware_opts(conn))
391+
378392
conn.add_eval(eval)
379393
conn.send(eval.msg)
380394
eval.update("pending", progress_thread.phase())
@@ -458,9 +472,8 @@ def run(self, code):
458472
eval.msg = {"op": "eval",
459473
"id": eval.id,
460474
"ns": ns,
461-
"code": code,
462-
"nrepl.middleware.caught/caught": f"{ns}.middleware/print-root-trace",
463-
"nrepl.middleware.print/quota": 300}
475+
"code": code}
476+
eval.msg.update(get_middleware_opts(conn))
464477
conn.add_eval(eval)
465478
conn.send(eval.msg)
466479
eval.update("pending", progress_thread.phase())
@@ -655,21 +668,30 @@ def read(self, n):
655668
self.pos = end
656669
return self.buffer[begin:end]
657670

671+
672+
def get_shadow_repl_init_cmd(build):
673+
"""Returns the command to initialise shadow-repl."""
674+
if build == "node-repl":
675+
return "(shadow.cljs.devtools.api/node-repl)"
676+
elif build == "browser-repl":
677+
return "(shadow.cljs.devtools.api/browser-repl)"
678+
else:
679+
return f"(shadow.cljs.devtools.api/repl {build})"
680+
681+
658682
def handle_connect(msg):
659683

660684
if conn.profile == Profile.SHADOW_CLJS:
661-
shadow_cljs_init = {
662-
":app": "(shadow.cljs.devtools.api/repl :app)",
663-
"node-repl": "(shadow.cljs.devtools.api/browser-repl)",
664-
"browser-repl": "(shadow.cljs.devtools.api/node-repl)"
665-
}
666685
if 1 == msg.get("id") and "new-session" in msg:
686+
# Once we have the connnection to shadow's nrepl, we will
687+
# tell shadow to watch the cljs build provided by the user.
667688
conn.session = msg["new-session"]
668689
conn.send({"op": "eval",
669690
"session": conn.session,
670-
"code": shadow_cljs_init[conn.cljs_build],
691+
"code": get_shadow_repl_init_cmd(conn.cljs_build),
671692
"id": 2})
672693
return True
694+
673695
elif 2 == msg.get("id") and msg.get("status") == ["done"]:
674696
conn.set_status(f"🌕 {conn.host}:{conn.port}")
675697
return True
@@ -730,7 +752,7 @@ def read_loop():
730752
pass
731753
conn.disconnect()
732754

733-
def connect(host, port, profile, cljs_build):
755+
def connect(host, port, profile=Profile.CLOJURE, cljs_build=None):
734756
conn.host = host
735757
conn.port = port
736758
conn.profile = profile
@@ -777,32 +799,48 @@ def validate(self, text):
777799
port = int(port)
778800
return 0 <= port and port <= 65536
779801

780-
class ClojureSublimedCljsBuildInputHandler(sublime_plugin.ListInputHandler):
781-
def list_items(self):
782-
return [':app', 'node-repl', 'browser-repl']
802+
class ClojureSublimedShadowCljsBuildInputHandler(sublime_plugin.TextInputHandler):
803+
def initial_text(self):
804+
return ':app'
805+
806+
def preview(self, text):
807+
return sublime.Html("""
808+
<html>
809+
<body>
810+
Provide the cljs build for shadow to watch.
811+
<br>
812+
Valid options are <b>node-repl</b>, <b>browser-repl</b> or the build defined in shadow-cljs.edn / project.clj
813+
For more info check <a href="https://shadow-cljs.github.io/docs/UsersGuide.html#_repl_2"> Shadow Documentation </a>
814+
</body>
815+
</html>
816+
""")
783817

784818
def next_input(self, args):
785819
return ClojureSublimedHostPortInputHandler()
786820

787-
class ClojureSublimedProfileInputHandler(sublime_plugin.ListInputHandler):
788-
def list_items(self):
789-
return [Profile.CLOJURE, Profile.SHADOW_CLJS]
790821

791-
def next_input(self, args):
792-
if args.get('clojure_sublimed_profile') == Profile.SHADOW_CLJS:
793-
return ClojureSublimedCljsBuildInputHandler()
794-
return ClojureSublimedHostPortInputHandler()
822+
class ClojureSublimedConnectShadowCljsCommand(sublime_plugin.ApplicationCommand):
795823

796-
class ClojureSublimedConnectCommand(sublime_plugin.ApplicationCommand):
824+
def run(self, clojure_sublimed_shadow_cljs_build, clojure_sublimed_host_port=''):
825+
host, port = clojure_sublimed_host_port.strip().split(':')
826+
port = int(port)
827+
connect(host, port, Profile.SHADOW_CLJS, clojure_sublimed_shadow_cljs_build)
797828

798-
def run(self, clojure_sublimed_profile, clojure_sublimed_cljs_build=None, clojure_sublimed_host_port=''):
829+
def input(self, args):
830+
if 'clojure_sublimed_shadow_cljs_build' not in args:
831+
return ClojureSublimedShadowCljsBuildInputHandler()
832+
833+
def is_enabled(self):
834+
return conn.socket == None
835+
836+
class ClojureSublimedConnectCommand(sublime_plugin.ApplicationCommand):
837+
def run(self, clojure_sublimed_host_port):
799838
host, port = clojure_sublimed_host_port.strip().split(':')
800839
port = int(port)
801-
connect(host, port, clojure_sublimed_profile, clojure_sublimed_cljs_build)
840+
connect(host, port)
802841

803842
def input(self, args):
804-
if 'clojure_sublimed_profile' not in args:
805-
return ClojureSublimedProfileInputHandler()
843+
return ClojureSublimedHostPortInputHandler()
806844

807845
def is_enabled(self):
808846
return conn.socket == None

0 commit comments

Comments
 (0)