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.
188214This 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
296322Paragraphs are separated only by blank lines. Semicolons start comments.
297323If you accidentally suspend your process, use \\ [comint-continue-subjob]
298324to 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
@@ -521,11 +548,24 @@ The prefix argument SWITCH-TO-REPL controls whether to switch to REPL after the
521548; ;; Command strings
522549; ;; ===============
523550
524- (defcustom inf-clojure-var-doc-command
551+ (defcustom inf-clojure-var-doc-form
525552 " (clojure.repl/doc %s)\n "
526553 " Command to query inferior Clojure for a var's documentation."
527554 :type 'string )
528555
556+ (defcustom inf-clojure-var-doc-form-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."
@@ -541,11 +581,24 @@ The prefix argument SWITCH-TO-REPL controls whether to switch to REPL after the
541581 " Command to query inferior Clojure for a function's arglist."
542582 :type 'string )
543583
544- (defcustom inf-clojure-completion-command
584+ (defcustom inf-clojure-completion-form
545585 " (complete.core/completions \" %s\" )\n "
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'.
683736With 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