88; ; URL: http://github.com/clojure-emacs/inf-clojure
99; ; Keywords: processes, comint, clojure
1010; ; Version: 3.2.1
11- ; ; Package-Requires: ((emacs "25.1 ") (clojure-mode "5.11"))
11+ ; ; Package-Requires: ((emacs "26.2 ") (clojure-mode "5.11"))
1212
1313; ; This file is not part of GNU Emacs.
1414
7474(defvar inf-clojure-startup-forms '((lein . " lein repl" )
7575 (boot . " boot repl" )
7676 (clojure . " clojure" )
77- (cljs . " clojure -m cljs.main -r" )
77+ (cljs . " clojure -M - m cljs.main -r" )
7878 (lein-clr . " lein clr repl" )
7979 (planck . " planck -d" )
8080 (babashka . " bb" )
140140 (set-ns . " (clojure.core/in-ns '%s)" )
141141 (macroexpand . " (clojure.core/macroexpand '%s)" )
142142 (macroexpand-1 . " (clojure.core/macroexpand-1 '%s)" )))
143+ (node-babashka . ((load . " (clojure.core/load-file \" %s\" )" )
144+ (doc . " (clojure.repl/doc %s)" )
145+ (source . " (clojure.repl/source %s)" )
146+ (arglists .
147+ " (try (-> '%s clojure.core/resolve clojure.core/meta :arglists)
148+ (catch Throwable e nil))" )
149+ (apropos . " (doseq [var (sort (clojure.repl/apropos \" %s\" ))] (println (str var)))" )
150+ (ns-vars . " (clojure.repl/dir %s)" )
151+ (set-ns . " (clojure.core/in-ns '%s)" )
152+ (macroexpand . " (clojure.core/macroexpand '%s)" )
153+ (macroexpand-1 . " (clojure.core/macroexpand-1 '%s)" )))
143154 (clojure . ((load . " (clojure.core/load-file \" %s\" )" )
144155 (doc . " (clojure.repl/doc %s)" )
145156 (source . " (clojure.repl/source %s)" )
@@ -641,33 +652,34 @@ Customization: Entry to this mode runs the hooks on `comint-mode-hook' and
641652
642653You can send text to the inferior Clojure process from other buffers containing
643654Clojure source.
644- `inf-clojure-switch-to-repl' switches the current buffer to the Clojure process buffer.
655+ `inf-clojure-switch-to-repl' switches the current buffer to the Clojure
656+ process buffer.
645657 `inf-clojure-eval-defun' sends the current defun to the Clojure process.
646658 `inf-clojure-eval-region' sends the current region to the Clojure process.
647659
648660 Prefixing the inf-clojure-eval/defun/region commands with
649- a \\ [universal-argument] causes a switch to the Clojure process buffer after sending
650- the text.
661+ a \\ [universal-argument] causes a switch to the Clojure process buffer after
662+ sending the text.
651663
652664Commands:\\ <inf-clojure-mode-map>
653- \\ [comint-send-input] after the end of the process' output sends the text from the
654- end of process to point.
655- \\ [comint-send-input] before the end of the process' output copies the sexp ending at point
656- to the end of the process' output, and sends it.
657- \\ [comint-copy-old-input] copies the sexp ending at point to the end of the process' output,
658- allowing you to edit it before sending it.
659- If `comint-use-prompt-regexp' is nil (the default), \\ [comint-insert-input] on old input
660- copies the entire old input to the end of the process' output, allowing
661- you to edit it before sending it. When not used on old input, or if
662- `comint-use-prompt-regexp' is non-nil, \\ [comint-insert-input] behaves according to
663- its global binding.
665+ \\ [comint-send-input] after the end of the process' output sends the text from
666+ the end of process to point.
667+ \\ [comint-send-input] before the end of the process' output copies the sexp
668+ ending at point to the end of the process' output, and sends it.
669+ \\ [comint-copy-old-input] copies the sexp ending at point to the end of the
670+ process' output, allowing you to edit it before sending it.
671+ If `comint-use-prompt-regexp' is nil (the default), \\ [comint-insert-input] on
672+ old input copies the entire old input to the end of the process' output,
673+ allowing you to edit it before sending it. When not used on old input, or if
674+ `comint-use-prompt-regexp' is non-nil, \\ [comint-insert-input] behaves
675+ according to its global binding.
664676\\ [backward-delete-char-untabify] converts tabs to spaces as it moves back.
665677\\ [clojure-indent-line] indents for Clojure; with argument, shifts rest
666678 of expression rigidly with the current line.
667- \\ [indent-sexp] does \\ [clojure-indent-line] on each line starting within following expression.
668- Paragraphs are separated only by blank lines. Semicolons start comments .
669- If you accidentally suspend your process, use \\ [comint-continue-subjob]
670- to continue it."
679+ \\ [indent-sexp] does \\ [clojure-indent-line] on each line starting within
680+ following expression. Paragraphs are separated only by blank lines.
681+ Semicolons start comments. If you accidentally suspend your process,
682+ use \\ [comint-continue-subjob] to continue it."
671683 (setq comint-input-sender 'inf-clojure--send-string )
672684 (setq comint-prompt-regexp inf-clojure-comint-prompt-regexp)
673685 (setq mode-line-process '(" :%s" ))
@@ -807,9 +819,11 @@ process buffer for a list of commands.)"
807819 nil
808820 'confirm-after-completion ))))
809821 (let* ((project-dir (clojure-project-dir))
810- (process-buffer-name (if project-dir
811- (format " inf-clojure %s " (inf-clojure--project-name project-dir))
812- " inf-clojure" ))
822+ (process-buffer-name (or
823+ inf-clojure-custom-repl-name
824+ (if project-dir
825+ (format " inf-clojure %s " (inf-clojure--project-name project-dir))
826+ " inf-clojure" )))
813827 ; ; comint adds the asterisks to both sides
814828 (repl-buffer-name (format " *%s * " process-buffer-name)))
815829 ; ; Create a new comint buffer if needed
@@ -819,10 +833,11 @@ process buffer for a list of commands.)"
819833 (cmdlist (if (consp cmd)
820834 (list cmd)
821835 (split-string-and-unquote cmd)))
822- (repl-type (or (unless prefix-arg
836+ (repl-type (or inf-clojure-socket-repl-type
837+ (unless prefix-arg
823838 inf-clojure-custom-repl-type)
824- (car (rassoc cmd inf-clojure-startup-forms))
825- (inf-clojure--prompt-repl-type))))
839+ (car (rassoc cmd inf-clojure-startup-forms))
840+ (inf-clojure--prompt-repl-type))))
826841 (message " Starting Clojure REPL via `%s' ... " cmd)
827842 (with-current-buffer (apply #'make-comint
828843 process-buffer-name (car cmdlist) nil (cdr cmdlist))
@@ -843,6 +858,117 @@ HOST is the host the process is running on, PORT is where it's listening."
843858 (interactive " shost: \n nport: " )
844859 (inf-clojure (cons host port)))
845860
861+ (defvar-local inf-clojure-socket-callback nil
862+ " Used to transfer state between the socket process buffer & REPL buffer." )
863+
864+ (defvar-local inf-clojure-socket-buffer nil
865+ " Used to kill the associated socket buffer when it's REPL buffer is killed." )
866+
867+ (defun inf-clojure-socket-filter (process output )
868+ " A filter that gets triggered each time the socket receives new OUTPUT.
869+ This function prints out the output received but also
870+ watches for a prompt using the `inf-clojure-prompt' regexp, once
871+ this happens a callback is triggered if available. The callback
872+ is intended to be used to trigger a `inf-clojure-connect' once we
873+ can determine that a socket REPL is ready to receive a
874+ connection.
875+
876+ PROCESS is the process object that is being filtered.
877+
878+ OUTPUT is the latest data received from the process"
879+ (let ((server-buffer (process-buffer process)))
880+ (when (buffer-live-p server-buffer)
881+ (with-current-buffer server-buffer
882+ (insert output)))
883+ (let ((prompt-displayed (string-match inf-clojure-prompt output)))
884+ (when prompt-displayed
885+ (message (format " Socket REPL startup detected for %s " (process-name process)))
886+ (with-current-buffer server-buffer
887+ (when inf-clojure-socket-callback
888+ (funcall inf-clojure-socket-callback)))))))
889+
890+ (defun inf-clojure-socket-repl-sentinel (process event )
891+ " Ensures socket REPL are cleaned up when the REPL buffer is closed.
892+
893+ PROCESS is the process object that is connected to a socket REPL.
894+
895+ EVENT is the event that triggered this function to be called."
896+ (when (not (process-live-p process))
897+ (let ((repl-buffer (process-buffer process)))
898+ (with-current-buffer repl-buffer
899+ (when inf-clojure-socket-buffer
900+ (kill-buffer inf-clojure-socket-buffer))))))
901+
902+ (defvar inf-clojure-socket-repl-startup-forms
903+ '((lein . " JVM_OPTS='-Dclojure.server.repl={:port %d :accept clojure.core.server/repl}' lein repl" )
904+ (boot . " export BOOT_JVM_OPTIONS='-Dclojure.server.repl=\" {:port %d :accept clojure.core.server/repl}\" ' boot repl" )
905+ (clojure . " clojure -J-Dclojure.server.repl=\" {:port %d :accept clojure.core.server/repl}\" " )
906+ (cljs . " clojure -J-Dclojure.server.repl=\" {:port %d :accept cljs.server.browser/repl}\" " )
907+ (lein-clr . " JVM_OPTS='-Dclojure.server.repl={:port %d :accept clojure.core.server/repl}' lein clr repl" )
908+ (planck . " planck -n %d" )
909+ (babashka . " bb socket-repl %d" )))
910+
911+ (defcustom inf-clojure-socket-repl-port
912+ nil
913+ " Port to be used when creating a socket REPL via `inf-clojure-socket-repl' .
914+ If left as nil a random port will be selected between 5500-6000."
915+ :type '(choice integer (const nil ))
916+ :package-version '(inf-clojure . " 3.3" ))
917+
918+ ;;;### autoload
919+ (defun inf-clojure-socket-repl (cmd )
920+ " Start a socket REPL server and connect to it via `inf-clojure' .
921+ CMD is the command line used to start the socket REPL, if this
922+ isn't provided you will be prompted to select from the defaults
923+ provided in `inf-clojure-socket-repl-startup-forms' or
924+ `inf-clojure-custom-startup' if this is defined."
925+ (interactive (list (or (unless current-prefix-arg
926+ inf-clojure-custom-startup)
927+ (completing-read " Select Clojure socket REPL startup command: "
928+ (mapcar #'cdr inf-clojure-socket-repl-startup-forms)
929+ nil
930+ 'confirm-after-completion ))))
931+ (let* ((host " localhost" )
932+ (port (or inf-clojure-socket-repl-port (+ 5500 (random 500 ))))
933+ (project-dir (clojure-project-dir))
934+ (repl-type (or (unless prefix-arg
935+ inf-clojure-custom-repl-type)
936+ (car (rassoc cmd inf-clojure-socket-repl-startup-forms))
937+ (inf-clojure--prompt-repl-type)))
938+ (project-name (inf-clojure--project-name (or project-dir " standalone" )))
939+ (socket-process-name (format " *%s -%s -socket-server* " project-name repl-type))
940+ (socket-buffer-name (format " *%s -%s -socket* " project-name repl-type))
941+ (socket-buffer (get-buffer-create socket-buffer-name))
942+ (repl-buffer-name (format " %s -%s -repl" project-name repl-type))
943+ (socket-form (or cmd
944+ (cdr (assoc repl-type inf-clojure-socket-repl-startup-forms))
945+ inf-clojure-custom-startup))
946+ (socket-cmd (format socket-form port))
947+ (sock (let ((default-directory (or project-dir default-directory)))
948+ (start-file-process-shell-command
949+ socket-process-name socket-buffer
950+ socket-cmd))))
951+ (with-current-buffer socket-buffer
952+ (setq-local
953+ inf-clojure-socket-callback
954+ (lambda ()
955+ (let ((with-process-repl-buffer-name (concat " *" repl-buffer-name " *" )))
956+ (setq inf-clojure-socket-repl-type
957+ repl-type
958+ inf-clojure-custom-repl-name
959+ repl-buffer-name
960+ repl-buffer
961+ (get-buffer-create with-process-repl-buffer-name))
962+ (inf-clojure-connect host port)
963+ (with-current-buffer with-process-repl-buffer-name
964+ (setq inf-clojure-socket-buffer socket-buffer))
965+ (set-process-sentinel
966+ (get-buffer-process (get-buffer with-process-repl-buffer-name))
967+ #'inf-clojure-socket-repl-sentinel )))))
968+ (set-process-filter sock #'inf-clojure-socket-filter )
969+ (message " Starting %s socket REPL server at %s :%d with %s " repl-type host port socket-cmd)))
970+
971+
846972(defun inf-clojure--forms-without-newlines (str )
847973 " Remove newlines between toplevel forms.
848974STR is a string of contents to be evaluated. When sending
0 commit comments