Skip to content

Commit 3b4d27b

Browse files
committed
Support REPL types and Lumo
This patch adds the `inf-clojure-repl-type` defcustom in order to support different kind of configurations based on the selected type. The default is `'clojure`, and the other supported one is `'lumo`.
1 parent d04c36c commit 3b4d27b

File tree

1 file changed

+95
-9
lines changed

1 file changed

+95
-9
lines changed

inf-clojure.el

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
(require 'thingatpt)
4545
(require 'ansi-color)
4646
(require 'cl-lib)
47+
(require 'subr-x)
4748

4849

4950
(defgroup inf-clojure nil
@@ -148,6 +149,7 @@ The following commands are available:
148149
149150
\\{inf-clojure-minor-mode-map}"
150151
:lighter "" :keymap inf-clojure-minor-mode-map
152+
(setq comint-input-sender 'inf-clojure--send-string)
151153
(inf-clojure-eldoc-setup)
152154
(make-local-variable 'completion-at-point-functions)
153155
(add-to-list 'completion-at-point-functions
@@ -183,6 +185,30 @@ often connecting to a remote REPL process."
183185
:type '(choice (string)
184186
(cons string integer)))
185187

188+
(defvar-local inf-clojure-repl-type nil
189+
"Symbol to define your REPL type.
190+
Its root binding is nil and it can be further customized using
191+
either `setq-local` or an entry in `.dir-locals.el`." )
192+
193+
(defun inf-clojure--detect-type (proc)
194+
"Identifies the current REPL type for PROC."
195+
(cond
196+
((inf-clojure--lumo-p proc) 'lumo)
197+
(t 'clojure)))
198+
199+
(defun inf-clojure--set-repl-type (proc)
200+
"Set the REPL type if has not already been set."
201+
(when (not inf-clojure-repl-type)
202+
(setq inf-clojure-repl-type (inf-clojure--detect-type proc))))
203+
204+
(defun inf-clojure--send-string (proc string)
205+
"A custom `comint-input-sender` / `comint-send-string`.
206+
Perform the required side effects on every send for PROC and
207+
STRING (for example set the buffer local REPL type). It should
208+
be used instead of `comint-send-string`."
209+
(inf-clojure--set-repl-type proc)
210+
(comint-simple-send proc string))
211+
186212
(defcustom inf-clojure-load-command "(clojure.core/load-file \"%s\")\n"
187213
"Format-string for building a Clojure expression to load a file.
188214
This format string should use `%s' to substitute a file name
@@ -296,6 +322,7 @@ If `comint-use-prompt-regexp' is nil (the default), \\[comint-insert-input] on o
296322
Paragraphs are separated only by blank lines. Semicolons start comments.
297323
If you accidentally suspend your process, use \\[comint-continue-subjob]
298324
to continue it."
325+
(setq comint-input-sender 'inf-clojure--send-string)
299326
(setq comint-prompt-regexp inf-clojure-comint-prompt-regexp)
300327
(setq mode-line-process '(":%s"))
301328
(clojure-mode-variables)
@@ -408,12 +435,12 @@ Prefix argument AND-GO means switch to the Clojure buffer afterwards."
408435
(let ((str (replace-regexp-in-string
409436
"[\n]*\\'" "\n"
410437
(buffer-substring-no-properties start end))))
411-
(comint-send-string (inf-clojure-proc) str))
438+
(inf-clojure--send-string (inf-clojure-proc) str))
412439
(if and-go (inf-clojure-switch-to-repl t)))
413440

414441
(defun inf-clojure-eval-string (code)
415442
"Send the string CODE to the inferior Clojure process to be executed."
416-
(comint-send-string (inf-clojure-proc) (concat code "\n")))
443+
(inf-clojure--send-string (inf-clojure-proc) (concat code "\n")))
417444

418445
(defun inf-clojure-eval-defun (&optional and-go)
419446
"Send the current defun to the inferior Clojure process.
@@ -504,8 +531,8 @@ The prefix argument SWITCH-TO-REPL controls whether to switch to REPL after the
504531
(comint-check-source file-name) ; Check to see if buffer needs saved.
505532
(setq inf-clojure-prev-l/c-dir/file (cons (file-name-directory file-name)
506533
(file-name-nondirectory file-name)))
507-
(comint-send-string (inf-clojure-proc)
508-
(format inf-clojure-load-command file-name))
534+
(inf-clojure--send-string (inf-clojure-proc)
535+
(format inf-clojure-load-command file-name))
509536
(when switch-to-repl
510537
(inf-clojure-switch-to-repl t))))
511538

@@ -526,6 +553,19 @@ The prefix argument SWITCH-TO-REPL controls whether to switch to REPL after the
526553
"Command to query inferior Clojure for a var's documentation."
527554
:type 'string)
528555

556+
(defcustom inf-clojure-var-doc-command-lumo
557+
"(lumo.repl/doc %s)\n"
558+
"Lumo command to query inferior Clojure for a var's documentation."
559+
:type 'string)
560+
561+
(defun inf-clojure-var-doc-form ()
562+
"Return the form to query inferior Clojure for a var's documentation.
563+
If you are using REPL types, it will pickup the most approapriate
564+
`inf-clojure-var-doc-form` variant."
565+
(pcase inf-clojure-repl-type
566+
(lumo inf-clojure-var-doc-form-lumo)
567+
(_ inf-clojure-var-doc-form)))
568+
529569
(defcustom inf-clojure-var-source-command
530570
"(clojure.repl/source %s)\n"
531571
"Command to query inferior Clojure for a var's source."
@@ -546,6 +586,19 @@ The prefix argument SWITCH-TO-REPL controls whether to switch to REPL after the
546586
"Command to query inferior Clojure for completion candidates."
547587
:type 'string)
548588

589+
(defcustom inf-clojure-completion-form-lumo
590+
"(doall (map str (lumo.repl/get-completions \"%s\")))\n"
591+
"Lumo form to query inferior Clojure for completion candidates."
592+
:type 'string)
593+
594+
(defun inf-clojure-completion-form ()
595+
"Return the form to query inferior Clojure for a var's documentation.
596+
If you are using REPL types, it will pickup the most approapriate
597+
`inf-clojure-completion-form` variant."
598+
(pcase inf-clojure-repl-type
599+
(lumo inf-clojure-completion-form-lumo)
600+
(_ inf-clojure-completion-form)))
601+
549602
(defcustom inf-clojure-ns-vars-command
550603
"(clojure.repl/dir %s)\n"
551604
"Command to show the public vars in a namespace."
@@ -618,9 +671,9 @@ The value is nil if it can't find one."
618671

619672
(defun inf-clojure-show-var-documentation (var)
620673
"Send a command to the inferior Clojure to give documentation for VAR.
621-
See variable `inf-clojure-var-doc-command'."
674+
See function `inf-clojure-var-doc-form'."
622675
(interactive (inf-clojure-symprompt "Var doc" (inf-clojure-var-at-pt)))
623-
(comint-proc-query (inf-clojure-proc) (format inf-clojure-var-doc-command var)))
676+
(comint-proc-query (inf-clojure-proc) (format (inf-clojure-var-doc-form) var)))
624677

625678
(defun inf-clojure-show-var-source (var)
626679
"Send a command to the inferior Clojure to give source for VAR.
@@ -683,7 +736,7 @@ See variable `inf-clojure-macroexpand-command'.
683736
With a prefix arg MACRO-1 uses `inf-clojure-macroexpand-1-command'."
684737
(interactive "P")
685738
(let ((last-sexp (buffer-substring-no-properties (save-excursion (backward-sexp) (point)) (point))))
686-
(comint-send-string
739+
(inf-clojure--send-string
687740
(inf-clojure-proc)
688741
(format (if macro-1
689742
inf-clojure-macroexpand-1-command
@@ -710,7 +763,7 @@ See variable `inf-clojure-buffer'."
710763
(unwind-protect
711764
(let ((completion-snippet
712765
(format
713-
inf-clojure-completion-command (substring-no-properties expr))))
766+
(inf-clojure-completion-form) (substring-no-properties expr))))
714767
(process-send-string proc completion-snippet)
715768
(while (and (not (string-match inf-clojure-prompt kept))
716769
(accept-process-output proc 2)))
@@ -876,6 +929,39 @@ to suppress the usage of the target buffer discovery logic."
876929
(inf-clojure (inf-clojure-cmd (inf-clojure-project-type)))
877930
(rename-buffer target-buffer-name)))
878931

879-
(provide 'inf-clojure)
932+
(defun inf-clojure--response-match-p (form match-p proc)
933+
"Return MATCH-P on the result of sending FORM to PROC.
934+
Note that this function will add a \n to the end of the string
935+
for evaluation, therefore FORM should not include it."
936+
(let* ((kept "")
937+
(is-matching nil)
938+
(prev-filter (process-filter proc)))
939+
(set-process-filter proc (lambda (_ string) (setq kept (concat kept string))))
940+
(unwind-protect
941+
;; use the real comind-send-string in order to avoid stack overflows
942+
(comint-send-string proc (concat form "\n"))
943+
;; yey, loads of procedural code again
944+
(while (and (not is-matching)
945+
(not (string-match inf-clojure-prompt kept))
946+
(accept-process-output proc 2))
947+
(setq is-matching (funcall match-p kept)))
948+
(set-process-filter proc prev-filter))
949+
is-matching))
950+
951+
;;;; Lumo
952+
;;;; ====
953+
954+
(defcustom inf-clojure--lumo-repl-form
955+
"(js/global.hasOwnProperty \"$$LUMO_GLOBALS\")"
956+
"Form to invoke in order to verify that we launched a Lumo REPL."
957+
:type 'string)
958+
959+
(defalias 'inf-clojure--lumo-p
960+
(apply-partially 'inf-clojure--response-match-p
961+
inf-clojure--lumo-repl-form
962+
(lambda (string)
963+
(string-match-p (concat inf-clojure--lumo-repl-form "\\Ca*true\\Ca*") string)))
964+
"Ascertain that PROC is a Lumo REPL.")
880965

966+
(provide 'inf-clojure)
881967
;;; inf-clojure.el ends here

0 commit comments

Comments
 (0)