Skip to content

Commit d831b52

Browse files
committed
finished implementing remote jack-in support, using ssh tunnels by default
1 parent 250c147 commit d831b52

File tree

1 file changed

+93
-44
lines changed

1 file changed

+93
-44
lines changed

clojure-mode.el

Lines changed: 93 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -949,15 +949,57 @@ returned."
949949
;; Pipe to $SHELL to work around mackosecks GUI Emacs $PATH issues.
950950
(defcustom clojure-swank-command
951951
(if (or (locate-file "lein" exec-path) (locate-file "lein.bat" exec-path))
952-
"lein jack-in %s %s"
953-
"echo \"lein jack-in %s %s\" | $SHELL -l")
952+
"lein jack-in %s"
953+
"echo \"lein jack-in %s\" | $SHELL -l")
954954
"The command used to start swank via clojure-jack-in.
955955
For remote swank it is lein must be in your PATH and the remote
956956
proc is launched via sh rather than bash, so it might be necessary
957-
to specific the full path to it. The arguments are port, hostname."
957+
to specific the full path to it. The argument is the port to connect on.
958+
Localhost is assumed."
958959
:type 'string
959960
:group 'clojure-mode)
960961

962+
(defcustom clojure-generate-remote-swank-command-function
963+
'clojure-generate-remote-swank-command-ssh-tunnel
964+
"A function that is called to determine the swank command that
965+
`clojure-jack-in` will execute and the hostname/port that slime
966+
should connect to for remote projects that are opened via tramp.
967+
968+
The arguments are dir, hostname, and port. The return value should be an `alist` of the form
969+
(:cmd \"command string\" :hostname \"hostname\" :port 1234)"
970+
:type 'function
971+
:group 'clojure-mode)
972+
973+
(defun clojure-generate-local-swank-command-default (dir hostname port)
974+
(if (not (string-equal "localhost" hostname))
975+
(error (concat
976+
"If you need to jack-in to remote projects/jvms over tramp, "
977+
"you need to define a custom `clojure-generate-swank-command-function`"))
978+
(list :cmd (format clojure-swank-command port)
979+
:hostname hostname
980+
:port port)))
981+
982+
(defun clojure-generate-remote-swank-command-ssh-tunnel (dir hostname port)
983+
(destructuring-bind (_method user host localname)
984+
(append (tramp-dissect-file-name dir) nil)
985+
(list :cmd (format-spec
986+
"ssh -L %p:localhost:%p -l '%u' '%h' 'cd \'%d\'; lein jack-in \'%p\''"
987+
`((?p . ,port)
988+
(?h . ,host)
989+
(?u . ,(or user (getenv "USER")))
990+
(?d . ,localname)))
991+
:hostname "localhost"
992+
:port port)))
993+
994+
(defun clojure-generate-swank-cmd (dir hostname port)
995+
(if (file-remote-p dir)
996+
(if (functionp clojure-generate-remote-swank-command-function)
997+
(funcall clojure-generate-remote-swank-command-function dir hostname port)
998+
(error (concat
999+
"If you need to jack-in to remote projects/jvms over tramp "
1000+
"you need to define a custom `clojure-generate-remote-swank-command-function`")))
1001+
(clojure-generate-local-swank-command-default dir hostname port)))
1002+
9611003
(defun clojure-jack-in-sentinel (process event)
9621004
(let ((debug-on-error t))
9631005
(error "Could not start swank server: %s"
@@ -985,54 +1027,63 @@ to specific the full path to it. The arguments are port, hostname."
9851027
(set-process-query-on-exit-flag process nil))
9861028
(kill-buffer swank-buffer-name))))
9871029

988-
(defun clojure-generate-swank-connection-name (dir hostname port)
1030+
(defun clojure-generate-swank-connection-name (dir hostname)
9891031
"swank")
9901032

991-
(defun clojure-jack-in-start-process (swank-connection-name swank-buffer-name hostname port)
992-
;; the buffer has to be created before the proc:
1033+
(defun clojure-jack-in-start-process (swank-connection-name swank-buffer-name dir hostname)
1034+
;; The buffer has to be created before the proc if
1035+
;; `start-file-process-shell-command` is used. It doesn't hurt to do
1036+
;; it now even if `start-process-shell-command` is used:
9931037
(get-buffer-create swank-buffer-name)
9941038

995-
(let ((swank-cmd (format clojure-swank-command port hostname)))
996-
(lexical-let* ((proc (start-file-process-shell-command
997-
swank-connection-name
998-
swank-buffer-name
999-
swank-cmd))
1000-
(hostname hostname)
1001-
(port port)
1002-
(connect-callback (lambda () (slime-connect hostname port))))
1003-
(set-process-sentinel proc 'clojure-jack-in-sentinel)
1004-
(set-process-query-on-exit-flag proc nil)
1005-
(set-process-filter proc
1006-
(lambda (process output)
1007-
(with-current-buffer (process-buffer process)
1008-
(insert output))
1009-
(when (string-match "proceed to jack in" output)
1010-
(clojure-eval-bootstrap-region process)
1011-
(with-current-buffer
1012-
;; this block is an attempt to avoid
1013-
;; creating duplicate repl windows
1014-
(or
1015-
(get-buffer "*slime-repl clojure*")
1016-
(get-buffer "*slime-repl nil*")
1017-
(current-buffer))
1018-
(funcall connect-callback)
1019-
(when (string-match "slime-repl" (buffer-name))
1020-
(goto-char (point-max))))
1021-
(set-process-sentinel process nil)
1022-
(set-process-filter process nil)))))))
1039+
(let ((port (- 65535 (mod (caddr (current-time)) 4096))))
1040+
(destructuring-bind (&key cmd hostname port)
1041+
(clojure-generate-swank-cmd dir hostname port)
1042+
(lexical-let* ((proc (start-process-shell-command
1043+
;; this command runs locally
1044+
;; `start-file-process-shell-command` would
1045+
;; run remote for tramp buffers
1046+
swank-connection-name
1047+
swank-buffer-name
1048+
cmd))
1049+
(dir dir)
1050+
(hostname hostname)
1051+
(port port)
1052+
(connect-callback (lambda () (slime-connect hostname port))))
1053+
(set-process-sentinel proc 'clojure-jack-in-sentinel)
1054+
(set-process-query-on-exit-flag proc nil)
1055+
(set-process-filter proc
1056+
(lambda (process output)
1057+
(with-current-buffer (process-buffer process)
1058+
(insert output))
1059+
(when (string-match "proceed to jack in" output)
1060+
(clojure-eval-bootstrap-region process)
1061+
(with-current-buffer
1062+
;; this block is an attempt to avoid
1063+
;; creating duplicate repl windows
1064+
(or
1065+
(get-buffer "*slime-repl clojure*")
1066+
(get-buffer "*slime-repl nil*")
1067+
(current-buffer))
1068+
(funcall connect-callback)
1069+
(when (string-match "slime-repl" (buffer-name))
1070+
;; this is most likely an old repl
1071+
;; buffer that existed prior to the
1072+
;; jack-in call.
1073+
(setq default-directory dir)
1074+
(goto-char (point-max))))
1075+
(set-process-sentinel process nil)
1076+
(set-process-filter process nil))))))))
10231077

10241078
;;;###autoload
10251079
(defun clojure-jack-in ()
10261080
(interactive)
10271081
(setq slime-net-coding-system 'utf-8-unix)
1028-
(let* ((port (- 65535 (mod (caddr (current-time)) 4096)))
1029-
(dir default-directory)
1082+
(let* ((dir default-directory)
10301083
(hostname (if (file-remote-p default-directory)
1031-
tramp-current-host
1032-
"localhost"))
1033-
(swank-connection-name
1034-
(clojure-generate-swank-connection-name dir hostname port))
1035-
(swank-buffer-name (format "*%s*" swank-connection-name)))
1084+
tramp-current-host "localhost"))
1085+
(connection-name (clojure-generate-swank-connection-name dir hostname))
1086+
(swank-buffer-name (format "*%s*" connection-name)))
10361087

10371088
(when (and (functionp 'slime-disconnect)
10381089
(slime-current-connection)
@@ -1041,9 +1092,7 @@ to specific the full path to it. The arguments are port, hostname."
10411092
)
10421093
(slime-disconnect))
10431094
(clojure-kill-swank-buffer swank-buffer-name)
1044-
(clojure-jack-in-start-process swank-connection-name
1045-
swank-buffer-name
1046-
hostname port))
1095+
(clojure-jack-in-start-process connection-name swank-buffer-name dir hostname))
10471096
(message "Starting swank server..."))
10481097

10491098
(defun clojure-find-ns ()

0 commit comments

Comments
 (0)