Skip to content

Commit 5b45f5b

Browse files
committed
Overhaul inf-elixir-send-* buffer lookup
This is a relatively complex flow that I've wanted to revisit for some time. I will be uploading a diagram to the wiki that encapsulates most of the flow. Also introduces a new `inf-elixir-set-repl` command which allows the user to manually set what REPL they want the current buffer to send to. This choice is remembered until the buffer is killed or the command is run again.
1 parent acb948c commit 5b45f5b

File tree

1 file changed

+78
-10
lines changed

1 file changed

+78
-10
lines changed

inf-elixir.el

+78-10
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
(require 'comint)
3434
(require 'subr-x)
35+
(require 'map)
3536

3637

3738
;;; Customization
@@ -69,11 +70,25 @@ NOTE: Changing this variable will not affect running REPLs."
6970
:type 'string
7071
:group 'inf-elixir)
7172

73+
(defcustom inf-elixir-repl-buffer nil
74+
"Override for what REPL buffer code snippets should be sent to.
75+
76+
If this variable is set and the corresponding REPL buffer exists
77+
and has a living process, all `inf-elixir-send-*' commands will
78+
send to it. If this variable is unset (the default) or the
79+
indicated buffer is dead or has a dead process, a warning will be
80+
printed instead."
81+
:type 'buffer
82+
:group 'inf-elixir)
83+
7284

7385
;;; Mode definitions and configuration
7486
(defvar inf-elixir-project-buffers (make-hash-table :test 'equal)
7587
"A mapping of projects to buffers with running Elixir REPL subprocesses.")
7688

89+
(defvar inf-elixir-unaffiliated-buffers '()
90+
"A list of Elixir REPL buffers unaffiliated with any project.")
91+
7792
;;;###autoload
7893
(define-minor-mode inf-elixir-minor-mode
7994
"Minor mode for Elixir buffers that allows interacting with the REPL.")
@@ -154,18 +169,66 @@ Always returns a REPL buffer for DIR."
154169
(with-current-buffer
155170
(apply #'make-comint-in-buffer buf-name nil (car cmd) nil (cdr cmd))
156171
(inf-elixir-mode)
157-
(when dir (inf-elixir--set-project-buffer dir (current-buffer)))
172+
(if dir
173+
(inf-elixir--set-project-buffer dir (current-buffer))
174+
(add-to-list 'inf-elixir-unaffiliated-buffers (current-buffer)))
158175
(current-buffer)))))
159176

160-
(defun inf-elixir--send (command)
161-
"Send COMMAND to the REPL process in BUF."
162-
(let* ((proj-dir (inf-elixir--find-project-root))
163-
(proj-buf (inf-elixir--get-project-buffer proj-dir)))
164-
(if (process-live-p (get-buffer-process proj-buf))
165-
(with-current-buffer proj-buf
166-
(comint-add-to-input-history command)
167-
(comint-send-string proj-buf (concat command "\n")))
168-
(message (concat "No REPL running in " (inf-elixir--project-name proj-dir))))))
177+
(defun inf-elixir--send (cmd)
178+
"Determine where to send CMD and send it."
179+
(when-let ((buf (inf-elixir--determine-repl-buf)))
180+
(with-current-buffer buf
181+
(comint-add-to-input-history cmd)
182+
(comint-send-string buf (concat cmd "\n")))
183+
(pop-to-buffer buf)))
184+
185+
(defun inf-elixir--determine-repl-buf ()
186+
"Determines where to send a cmd when `inf-elixir-send-*' are used."
187+
(if inf-elixir-repl-buffer
188+
(if (process-live-p (get-buffer-process inf-elixir-repl-buffer))
189+
inf-elixir-repl-buffer
190+
(inf-elixir--prompt-repl-buffers "`inf-elixir-repl-buffer' is dead, please choose another REPL buffer: "))
191+
(if-let ((proj-dir (inf-elixir--find-project-root)))
192+
(inf-elixir--determine-project-repl-buf proj-dir)
193+
(inf-elixir--prompt-repl-buffers))))
194+
195+
(defun inf-elixir--determine-project-repl-buf (proj-dir)
196+
"Determines where to send a cmd when `inf-elixir-send-*' are used inside the PROJ-DIR Mix project."
197+
(if-let ((proj-buf (inf-elixir--get-project-buffer proj-dir)))
198+
(if (process-live-p (get-buffer-process proj-buf))
199+
proj-buf
200+
(if (y-or-n-p "A project REPL buffer exists, but the process is dead. Start a new one? ")
201+
(inf-elixir-project)
202+
(inf-elixir--prompt-repl-buffers)))
203+
(if (y-or-n-p "No REPL exists for this project yet. Start one? ")
204+
(inf-elixir-project)
205+
(inf-elixir--prompt-repl-buffers))))
206+
207+
(defun inf-elixir--prompt-repl-buffers (&optional prompt)
208+
"Prompt the user to select an inf-elixir REPL buffers or create an new one.
209+
210+
Returns the select buffer (as a buffer object).
211+
212+
If PROMPT is supplied, it is used as the prompt for a REPL buffer.
213+
214+
When the user selects a REPL, it is set as `inf-elixir-repl-buffer' locally in
215+
the buffer so that the choice is remembered for that buffer."
216+
;; Cleanup
217+
(setq inf-elixir-unaffiliated-buffers (seq-filter 'buffer-live-p inf-elixir-unaffiliated-buffers))
218+
(setq inf-elixir-project-buffers
219+
(map-into
220+
(map-filter (lambda (_dir buf) (buffer-live-p buf)) inf-elixir-project-buffers)
221+
'(hash-table :test equal)))
222+
;; Actual functionality
223+
(let* ((repl-buffers (append
224+
'("Create new")
225+
(mapcar (lambda (buf) `(,(buffer-name buf) . buf)) inf-elixir-unaffiliated-buffers)
226+
(mapcar (lambda (buf) `(,(buffer-name buf) . buf)) (hash-table-values inf-elixir-project-buffers))))
227+
(prompt (or prompt "Which REPL?"))
228+
(selected-buf (completing-read prompt repl-buffers (lambda (_) t) t)))
229+
(setq-local inf-elixir-repl-buffer (if (equal selected-buf "Create new")
230+
(inf-elixir)
231+
selected-buf))))
169232

170233

171234
;;; Public functions
@@ -222,6 +285,11 @@ be prompted for the REPL command. The default is provided by
222285
(inf-elixir-run-cmd default-directory cmd))
223286
(message "Could not find project root! Try `inf-elixir' instead.")))
224287

288+
(defun inf-elixir-set-repl ()
289+
"Select which REPL to use for this buffer."
290+
(interactive)
291+
(inf-elixir--prompt-repl-buffers))
292+
225293
(defun inf-elixir-send-line ()
226294
"Send the region to the REPL buffer and run it."
227295
(interactive)

0 commit comments

Comments
 (0)