Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I quickly and easily configure GHC integration for Emacs?

Tags:

emacs

haskell

ghc

In the past I've tried to get a more IDE like experience while developing Haskell in Emacs, but I've always stumbled on not quite working integration.

Is there a way to get basic GHC-powered features (e.g. look up type of identifier or instant compile using flymake) that just works*. By just works I mean integrates well with the rest of the ecosystem (e.g. haskell-mode, cabal)?

* Just works here basically means: only requires some basic configuration in init.el and perhaps installing some package from Hackage.

like image 899
tibbe Avatar asked Mar 10 '14 09:03

tibbe


2 Answers

For inline error checking, hdevtools is the best I've found. It's a background server running GHC in order to speed up analyzing programs.

It's actually very easy to install: you need one Haskell package:

cabal install hdevtools

and two Emacs packages, both through M-x list-packages: flycheck and flycheck-hdevtools.

Once it's installed, you just need to enable it with something like M-x global-flycheck-mode (which you can also put in your .emacs.) You can go to the next error with C-x `. You will probably also want to change the error and warning faces, which you can do with M-x customize-group flycheck-faces.

Unfortunately, the Emacs mode only does errors and warnings (including hlint); it does not expose retrieving the type of an identifier, which I believe hdevtools supports. It also sometimes gives me random parse errors when confronted with Unicode variable names or certain extensions; however, if I just ignore them, everything else works. I should probably file a bug report or something.

like image 149
Tikhon Jelvis Avatar answered Nov 16 '22 18:11

Tikhon Jelvis


Check out Tim's excellent setup:

http://tim.dysinger.net/posts/2014-02-18-haskell-with-emacs.html

UPDATE:

This is what I do:

(defmacro hcRequire (name &rest body)
  `(if (require ',name nil t)
       (progn ,@body)
     (warn (concat (format "%s" ',name) " NOT FOUND"))))

(hcRequire haskell-mode-autoloads
  (autoload 'ghc-init "ghc" nil t)
  (add-hook 'haskell-mode-hook (lambda () (ghc-init) (flymake-mode)))

  (add-hook 'haskell-mode-hook 'turn-on-haskell-doc-mode)
  (add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)
  (setq haskell-stylish-on-save t)
  (setq haskell-process-args-cabal-repl '("--ghc-option=-ferror-spans"
                                          "--with-ghc=ghci-ng"))
  (define-key haskell-mode-map (kbd "C-x C-d") nil)
  (define-key haskell-mode-map (kbd "C-c C-z") 'haskell-interactive-switch)
  (define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-file)
  (define-key haskell-mode-map (kbd "C-c C-b") 'haskell-interactive-switch)
  (define-key haskell-mode-map (kbd "C-c C-t") 'haskell-process-do-type)
  (define-key haskell-mode-map (kbd "C-c C-i") 'haskell-process-do-info)
  (define-key haskell-mode-map (kbd "C-c M-.") nil)
  (define-key haskell-mode-map (kbd "C-c C-d") nil)
  (define-key haskell-mode-map (kbd "C-c v c") 'haskell-cabal-visit-file)

  ;; Do this to get a variable in scope
  (auto-complete-mode)
  (defun hc-ac-haskell-candidates (prefix)
    (let ((cs (haskell-process-get-repl-completions (haskell-process) prefix)))
      (remove-if (lambda (c) (string= "" c)) cs)))
  (ac-define-source haskell
    '((candidates . (hc-ac-haskell-candidates ac-prefix))))
  (defun hc-haskell-hook ()
    (add-to-list 'ac-sources 'ac-source-haskell))
  (add-hook 'haskell-mode-hook 'hc-haskell-hook)

  ;; auto-complete-mode so can interact with inferior haskell and popup completion
  ;; I don't always want this.  Just turn on when needed.
  ;;(add-hook 'haskell-mode-hook (lambda () (auto-complete-mode 1)))
)

;; I'm not using this (YET)
;;(hcRequire shm
;;  (add-hook 'haskell-mode-hook 'structured-haskell-mode))
like image 7
haroldcarr Avatar answered Nov 16 '22 18:11

haroldcarr