Ian Kelling
Ian Kelling

Reputation: 10011

Function to evaluate haskell in ghci while editing source file using Emacs

I'm editing a haskell source file. I want to run my main function in my inferior-haskell buffer (already opened in a different frame) and continue editing my source file. To do this, I do

C-c C-l, change frame, main<ret>, change back to original frame

This seems quite inefficient. I'd like an emacs function/key that does it one shot.

Upvotes: 6

Views: 1191

Answers (2)

Miao ZhiCheng
Miao ZhiCheng

Reputation: 647

To use interactive-haskell-mode, I found a similar setting than the other answer:

(defun my-haskell-load-and-run ()
  "Loads and runs the current Haskell file main function."
  (interactive)
  (haskell-process-load-file)
  (haskell-interactive-mode-run-expr "main"))
(defun my-haskell-mode-hook ()
  (local-set-key (kbd "C-x C-r") 'my-haskell-load-and-run))
(add-hook 'haskell-mode-hook 'my-haskell-mode-hook)

But I have a small issue with it, it always jumps to the end of the source buffer... which can be annoying.

Upvotes: 1

Tikhon Jelvis
Tikhon Jelvis

Reputation: 68152

There is actually a function to do this already defined in inf-haskell.el: inferior-haskell-load-and-run. This loads your current file and runs :main.

You can bind it to a key in Haskell mode by adding a hook:

(defun my-haskell-mode-hook ()
  (local-set-key (kbd "C-x C-r") 'inferior-haskell-load-and-run))
(add-hook 'haskell-mode-hook 'my-haskell-mode-hook)

However, playing around with this for a bit, it seems to have an odd issue on my computer: sometimes, when it pops to the *haskell* buffer, it doesn't move the point to the end. I find this rather annoying. You can easily fix it by moving the point to the end yourself:

(defun my-haskell-load-and-run ()
  "Loads and runs the current Haskell file."
  (interactive)
  (inferior-haskell-load-and-run inferior-haskell-run-command)
  (sleep-for 0 100)
  (end-of-buffer))

I believe the sleep-for is necessary because the Haskell command is run asynchronously and takes a little bit of time to return. This whole thing is something of a hack, but it seems to work.

Also, you might want to customize exactly what the inferior-haskell-run-command is. By default, it's :main. However, for me, I think just main would be better because main is affected by :set args ... where :main isn't.

If you want to stay in your current Haskell buffer, you can just do this:

(defun my-haskell-load-and-run ()
  "Loads and runs the current Haskell file."
  (interactive)
  (let ((start-buffer (current-buffer)))
    (inferior-haskell-load-and-run inferior-haskell-run-command)
    (sleep-for 0 100)
    (end-of-buffer)
    (pop-to-buffer start-buffer)))

Upvotes: 7

Related Questions