Skip to content

Commit

Permalink
Add multi-line support in REPL
Browse files Browse the repository at this point in the history
@hvr might be of interest.
  • Loading branch information
chrisdone committed Mar 9, 2014
1 parent 5a3a996 commit 9b43204
Showing 1 changed file with 96 additions and 23 deletions.
119 changes: 96 additions & 23 deletions haskell-interactive-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,17 @@ Key bindings:
(setq next-error-function 'haskell-interactive-next-error-function)
(setq completion-at-point-functions '(haskell-interactive-mode-completion-at-point-function))

(haskell-interactive-mode-prompt))

(haskell-interactive-mode-prompt)
(set (make-local-variable 'comment-start) "-- ")
(set (make-local-variable 'font-lock-defaults)
'(haskell-font-lock-choose-keywords
nil nil ((?\' . "w") (?_ . "w")) nil
(font-lock-syntactic-keywords
. haskell-font-lock-choose-syntactic-keywords)
(font-lock-syntactic-face-function
. haskell-syntactic-face-function)
;; Get help from font-lock-syntactic-keywords.
(parse-sexp-lookup-properties . t))))

(defface haskell-interactive-face-prompt
'((t :inherit 'font-lock-function-name-face))
Expand All @@ -142,7 +151,8 @@ Key bindings:
(defun haskell-interactive-mode-newline-indent ()
"Make newline and indent."
(interactive)
(insert "\n" (make-string (length haskell-interactive-prompt) ? )))
(newline)
(indent-according-to-mode))

;;;###autoload
(defun haskell-interactive-bring ()
Expand All @@ -168,9 +178,11 @@ Key bindings:
(defun haskell-interactive-mode-return ()
"Handle the return key."
(interactive)
(if (haskell-interactive-at-compile-message)
(next-error-internal)
(haskell-interactive-handle-line)))
(cond
((haskell-interactive-at-compile-message)
(next-error-internal))
(t
(haskell-interactive-handle-expr))))

(defun haskell-interactive-mode-space (n)
"Handle the space key."
Expand All @@ -187,26 +199,28 @@ Key bindings:
(>= (point)
haskell-interactive-mode-prompt-start))

(defun haskell-interactive-handle-line ()
(defun haskell-interactive-handle-expr ()
"Handle an inputted expression at the REPL."
(when (haskell-interactive-at-prompt)
(let ((expr (haskell-interactive-mode-input)))
(when (not (string= "" (replace-regexp-in-string " " "" expr)))
(set-marker haskell-interactive-mode-prompt-start (point-max))
(haskell-interactive-mode-history-add expr)
(haskell-interactive-mode-run-line expr)))))
(haskell-interactive-mode-run-expr expr)))))

(defun haskell-interactive-mode-run-line (line)
"Run the given line."
(defun haskell-interactive-mode-run-expr (expr)
"Run the given expression."
(let ((session (haskell-session))
(process (haskell-process)))
(process (haskell-process))
(lines (length (split-string expr "\n"))))
(goto-char (point-max))
(haskell-process-queue-command
process
(make-haskell-command
:state (list session process line 0)
:state (list session process expr 0)
:go (lambda (state)
(haskell-process-send-string (cadr state)
(caddr state)))
(haskell-interactive-mode-multi-line (caddr state))))
:live (lambda (state buffer)
(unless (and (string-prefix-p ":q" (caddr state))
(string-prefix-p (caddr state) ":quit"))
Expand All @@ -217,19 +231,74 @@ Key bindings:
(substring buffer cursor))))
(when (= 0 cursor) (insert "\n"))
(haskell-interactive-mode-eval-result (car state) next)

(setf (cdddr state) (list (length buffer)))
nil)))
:complete (lambda (state response)
(cond
(haskell-interactive-mode-eval-mode
(haskell-interactive-mode-eval-as-mode (car state) response))
((haskell-interactive-mode-line-is-query (elt state 2))
(let ((haskell-interactive-mode-eval-mode 'haskell-mode))
(haskell-interactive-mode-eval-as-mode (car state) response)))
(haskell-interactive-mode-eval-pretty
(haskell-interactive-mode-eval-pretty-result (car state) response)))
(let ((response (haskell-interactive-mode-cleanup-response
(caddr state) response)))
(cond
(haskell-interactive-mode-eval-mode
(haskell-interactive-mode-eval-as-mode (car state) response))
((haskell-interactive-mode-line-is-query (elt state 2))
(let ((haskell-interactive-mode-eval-mode 'haskell-mode))
(haskell-interactive-mode-eval-as-mode (car state) response)))
(haskell-interactive-mode-eval-pretty
(haskell-interactive-mode-eval-pretty-result (car state) response))))
(haskell-interactive-mode-prompt (car state)))))))

(defun haskell-interactive-mode-cleanup-response (expr response)
"Ignore the mess that GHCi outputs on multi-line input."
(if (not (string-match "\n" expr))
response
(let ((i 0)
(out "")
(lines (length (split-string expr "\n"))))
(loop for part in (split-string response "| ")
do (setq out
(concat out
(if (> i lines)
(concat (if (or (= i 0) (= i (1+ lines))) "" "| ") part)
"")))
do (setq i (1+ i)))
out)))

(defun haskell-interactive-mode-multi-line (expr)
"If a multi-line expression has been entered, then reformat it to be:
:{
do the
multi-liner
expr
:}
"
(if (not (string-match "\n" expr))
expr
(let* ((i 0)
(lines (split-string expr "\n"))
(len (length lines))
(indent (make-string (length haskell-interactive-prompt)
? )))
(mapconcat 'identity
(loop for line in lines
collect (cond ((= i 0)
(concat ":{" "\n" line))
((= i (1- len))
(concat (haskell-interactive-trim line) "\n" ":}"))
(t
(haskell-interactive-trim line)))
do (setq i (1+ i)))
"\n"))))

(defun haskell-interactive-trim (line)
"Trim indentation off of lines in the REPL."
(if (and (string-match "^[ ]+" line)
(> (length line)
(length haskell-interactive-prompt)))
(substring line
(length haskell-interactive-prompt))
line))

(defun haskell-interactive-mode-line-is-query (line)
"Is LINE actually a :t/:k/:i?"
(and (string-match "^:[itk] " line)
Expand Down Expand Up @@ -277,7 +346,7 @@ Key bindings:
(let ((inhibit-read-only t))
(set-text-properties (point-min) (point-max) nil))
(delete-region (point-min) (point-max))
(mapc 'delete-overlay (overlays-in (point-min) (point-max)))
(remove-overlays)
(haskell-interactive-mode-prompt session)
(haskell-session-set session 'next-error-region nil)
(haskell-session-set session 'next-error-locus nil))))
Expand Down Expand Up @@ -313,7 +382,11 @@ SESSION, otherwise operate on the current buffer.
(make-marker))))
(set-marker marker
(point)
(current-buffer)))))
(current-buffer))
(when nil
(let ((o (make-overlay (point) (point-max) nil nil t)))
(overlay-put o 'line-prefix (make-string (length haskell-interactive-prompt)
? )))))))

(defun haskell-interactive-mode-eval-result (session text)
"Insert the result of an eval as plain text."
Expand Down

0 comments on commit 9b43204

Please sign in to comment.