Skip to content

Commit 8fbc5f6

Browse files
committed
Support stdin input in the REPL
@hvr λ> do putStr "Enter your name: "; line <- getLine; putStr "Enter your age: "; line2 <- getLine; putStrLn ("Your name is: " ++ line ++ " and age " ++ line2 ++ "!") Enter your name: Chris Enter your age: 42 Your name is: Chris and age 42!
1 parent e827a17 commit 8fbc5f6

File tree

2 files changed

+57
-27
lines changed

2 files changed

+57
-27
lines changed

haskell-interactive-mode.el

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ interference with prompts that look like haskell expressions."
6565
nil
6666
"Mark used for the beginning of the prompt.")
6767

68+
(defvar haskell-interactive-mode-result-end
69+
nil
70+
"Mark used to figure out where the end of the current result
71+
output is. Used to distinguish betwen user input.")
72+
6873
(defvar haskell-interactive-mode-old-prompt-start
6974
nil
7075
"Mark used for the old beginning of the prompt.")
@@ -219,12 +224,27 @@ Key bindings:
219224
"Handle an inputted expression at the REPL."
220225
(when (haskell-interactive-at-prompt)
221226
(let ((expr (haskell-interactive-mode-input)))
222-
(when (not (string= "" (replace-regexp-in-string " " "" expr)))
223-
(setq haskell-interactive-mode-old-prompt-start
224-
(copy-marker haskell-interactive-mode-prompt-start))
225-
(set-marker haskell-interactive-mode-prompt-start (point-max))
226-
(haskell-interactive-mode-history-add expr)
227-
(haskell-interactive-mode-do-expr expr)))))
227+
(unless (string= "" (replace-regexp-in-string " " "" expr))
228+
(cond
229+
;; If already evaluating, then the user is trying to send
230+
;; input to the REPL during evaluation. Most likely in
231+
;; response to a getLine-like function.
232+
((and (haskell-process-evaluating-p (haskell-process))
233+
(= (line-end-position) (point-max)))
234+
(goto-char (point-max))
235+
(let ((process (haskell-process))
236+
(string (buffer-substring-no-properties
237+
haskell-interactive-mode-result-end
238+
(point))))
239+
(insert "\n")
240+
(haskell-process-set-sent-stdin process t)
241+
(haskell-process-send-string process string)))
242+
;; Otherwise we start a normal evaluation call.
243+
(t (setq haskell-interactive-mode-old-prompt-start
244+
(copy-marker haskell-interactive-mode-prompt-start))
245+
(set-marker haskell-interactive-mode-prompt-start (point-max))
246+
(haskell-interactive-mode-history-add expr)
247+
(haskell-interactive-mode-do-expr expr)))))))
228248

229249
(defun haskell-interactive-mode-do-expr (expr)
230250
(cond
@@ -246,21 +266,19 @@ Key bindings:
246266
:go (lambda (state)
247267
(insert "\n")
248268
(haskell-process-send-string (cadr state)
249-
(haskell-interactive-mode-multi-line (caddr state))))
269+
(haskell-interactive-mode-multi-line (caddr state)))
270+
(haskell-process-set-evaluating (cadr state) t))
250271
:live (lambda (state buffer)
251272
(unless (and (string-prefix-p ":q" (caddr state))
252273
(string-prefix-p (caddr state) ":quit"))
253274
(let* ((cursor (cadddr state))
254-
(next (replace-regexp-in-string
255-
haskell-process-prompt-regex
256-
""
257-
(substring buffer cursor))))
275+
(next (substring buffer cursor)))
258276
(haskell-interactive-mode-eval-result (car state) next)
259-
260277
(setf (cdddr state) (list (length buffer)))
261278
nil)))
262279
:complete
263280
(lambda (state response)
281+
(haskell-process-set-evaluating (cadr state) nil)
264282
(unless (haskell-interactive-mode-trigger-compile-error state response)
265283
(haskell-interactive-mode-expr-result state response)))))))
266284

@@ -324,12 +342,11 @@ Key bindings:
324342
(caddr state) response)))
325343
(cond
326344
(haskell-interactive-mode-eval-mode
327-
(haskell-interactive-mode-eval-as-mode (car state) response))
345+
(unless (haskell-process-sent-stdin-p (cadr state))
346+
(haskell-interactive-mode-eval-as-mode (car state) response)))
328347
((haskell-interactive-mode-line-is-query (elt state 2))
329348
(let ((haskell-interactive-mode-eval-mode 'haskell-mode))
330-
(haskell-interactive-mode-eval-as-mode (car state) response)))
331-
(haskell-interactive-mode-eval-pretty
332-
(haskell-interactive-mode-eval-pretty-result (car state) response))))
349+
(haskell-interactive-mode-eval-as-mode (car state) response)))))
333350
(haskell-interactive-mode-prompt (car state)))
334351

335352
(defun haskell-interactive-mode-cleanup-response (expr response)
@@ -482,7 +499,12 @@ SESSION, otherwise operate on the current buffer.
482499
'rear-nonsticky t
483500
'read-only t
484501
'prompt t
485-
'result t))))
502+
'result t))
503+
(let ((marker (set (make-local-variable 'haskell-interactive-mode-result-end)
504+
(make-marker))))
505+
(set-marker marker
506+
(point)
507+
(current-buffer)))))
486508

487509
(defun haskell-interactive-mode-eval-as-mode (session text)
488510
"Insert TEXT font-locked according to `haskell-interactive-mode-eval-mode'."
@@ -496,16 +518,6 @@ SESSION, otherwise operate on the current buffer.
496518
(when haskell-interactive-mode-collapse
497519
(haskell-collapse start (point)))))))
498520

499-
(defun haskell-interactive-mode-eval-pretty-result (session text)
500-
"Insert the result of an eval as a pretty printed Showable, if
501-
parseable, or otherwise just as-is."
502-
(with-current-buffer (haskell-session-interactive-buffer session)
503-
(let ((inhibit-read-only t))
504-
(delete-region haskell-interactive-mode-prompt-start (point))
505-
(goto-char (point-max))
506-
(haskell-show-parse-and-insert text)
507-
(insert "\n"))))
508-
509521
;;;###autoload
510522
(defun haskell-interactive-mode-echo (session message &optional mode)
511523
"Echo a read only piece of text before the prompt."

haskell-process.el

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,6 +1264,22 @@ Returns newly set VALUE."
12641264

12651265
;; Wrappers using haskell-process-{get,set}
12661266

1267+
(defun haskell-process-set-sent-stdin (p v)
1268+
"We've sent stdin, so let's not clear the output at the end."
1269+
(haskell-process-set p 'sent-stdin v))
1270+
1271+
(defun haskell-process-sent-stdin-p (p)
1272+
"Did we send any stdin to the process during evaluation?"
1273+
(haskell-process-get p 'sent-stdin))
1274+
1275+
(defun haskell-process-set-evaluating (p v)
1276+
"Set status of evaluating to be on/off."
1277+
(haskell-process-set p 'evaluating v))
1278+
1279+
(defun haskell-process-evaluating-p (p)
1280+
"Set status of evaluating to be on/off."
1281+
(haskell-process-get p 'evaluating))
1282+
12671283
(defun haskell-process-set-process (p v)
12681284
"Set the process's inferior process."
12691285
(haskell-process-set p 'inferior-process v))
@@ -1283,6 +1299,8 @@ Return nil if no current command."
12831299

12841300
(defun haskell-process-set-cmd (p v)
12851301
"Set the process's current command."
1302+
(haskell-process-set-evaluating p nil)
1303+
(haskell-process-set-sent-stdin p nil)
12861304
(haskell-process-set p 'current-command v))
12871305

12881306
(defun haskell-process-response (p)

0 commit comments

Comments
 (0)