2015-03-05 09:14:51 +00:00
|
|
|
---
|
|
|
|
title: IDEs and Linters
|
|
|
|
author: Kostiantyn Rybnikov <k-bx@k-bx.com>
|
|
|
|
description: Preparing your editor
|
|
|
|
first-written: 2015-03-05
|
|
|
|
last-updated: 2015-03-05
|
|
|
|
---
|
|
|
|
|
|
|
|
Incomplete. Need to add:
|
|
|
|
|
|
|
|
* Emacs:
|
|
|
|
* tags-search (hasktags)
|
|
|
|
* haskell-mode + hlint
|
|
|
|
* stylish-haskell
|
|
|
|
* Additional:
|
|
|
|
* multi-tags search
|
|
|
|
* projectile for projects
|
|
|
|
* Vim: pretty much everything
|
|
|
|
* fpcomplete IDE
|
|
|
|
* other IDEs not listed here
|
|
|
|
|
|
|
|
## Emacs
|
|
|
|
|
|
|
|
Emacs is one of most popular Haskell editors out there. If you are
|
|
|
|
able to use it, you can get a very nice development environment.
|
|
|
|
|
|
|
|
### Prerequisites
|
|
|
|
|
2015-03-05 15:48:07 +00:00
|
|
|
#### Cask / use-package
|
2015-03-05 09:14:51 +00:00
|
|
|
|
|
|
|
It's assumed you have modern package manager Cask installed. You can
|
|
|
|
install it by following the
|
|
|
|
[cask user guide](http://cask.readthedocs.org/en/latest/index.html). For
|
|
|
|
older Emacs versions (< 24), please figure out other method of
|
|
|
|
package-installation.
|
|
|
|
|
|
|
|
Make sure a `Cask` file in your `.emacs.d` directory has marmelade
|
|
|
|
repo, ensure it looks something like this:
|
|
|
|
|
2015-03-05 09:19:32 +00:00
|
|
|
```elisp
|
2015-03-05 09:14:51 +00:00
|
|
|
(source gnu)
|
|
|
|
(source melpa)
|
|
|
|
(source marmalade)
|
|
|
|
```
|
|
|
|
|
|
|
|
And check that your `~/.emacs` file has:
|
|
|
|
|
2015-03-05 09:19:32 +00:00
|
|
|
```elisp
|
2015-03-05 09:14:51 +00:00
|
|
|
(require 'cask "~/.cask/cask.el")
|
|
|
|
(cask-initialize)
|
|
|
|
```
|
|
|
|
|
2015-03-05 15:19:38 +00:00
|
|
|
After adding dependencies to your `Cask` file, run `cask install` in
|
|
|
|
that directory.
|
|
|
|
|
2015-03-05 15:48:07 +00:00
|
|
|
If instead of `Cask` you are using `use-package` to manage your
|
|
|
|
package, then make sure that you have this in your `init.el` file:
|
|
|
|
|
|
|
|
```elisp
|
|
|
|
(setq package-archives
|
|
|
|
'(("gnu" . "http://elpa.gnu.org/packages/")
|
|
|
|
("marmalade" . "http://marmalade-repo.org/packages/")
|
|
|
|
("melpa" . "http://melpa.milkbox.net/packages/")))
|
|
|
|
|
|
|
|
(package-initialize)
|
|
|
|
|
|
|
|
(require 'use-package)
|
|
|
|
```
|
|
|
|
|
|
|
|
Make sure that you install `use-package` from the package manager.
|
|
|
|
|
2015-03-05 09:14:51 +00:00
|
|
|
#### exec-path-from-shell
|
|
|
|
|
|
|
|
On MacOS X you will also need
|
|
|
|
[exec-path-from-shell](https://github.com/purcell/exec-path-from-shell)
|
|
|
|
in order to get your environment variables from your shell (bash or
|
|
|
|
zsh) into your emacs, so that it inherits your `$PATH` and sees proper
|
|
|
|
`~/.cabal/bin/cabal`, for example. To install, add following to your
|
|
|
|
`Cask` file:
|
|
|
|
|
2015-03-05 09:19:32 +00:00
|
|
|
```elisp
|
2015-03-05 09:14:51 +00:00
|
|
|
(depends-on "exec-path-from-shell")
|
|
|
|
```
|
|
|
|
|
|
|
|
and run `cask install` from `Cask`-file directory. Add following to your `~/.emacs`:
|
|
|
|
|
2015-03-05 09:19:32 +00:00
|
|
|
```elisp
|
2015-03-05 09:14:51 +00:00
|
|
|
(when (memq window-system '(mac ns))
|
|
|
|
(exec-path-from-shell-initialize))
|
|
|
|
```
|
|
|
|
|
|
|
|
### haskell-mode
|
|
|
|
|
|
|
|
First of all, you should use
|
|
|
|
[haskell-mode](https://github.com/haskell/haskell-mode) for editing
|
|
|
|
`.hs` and `.cabal` files. Add this line to your `Cask`:
|
|
|
|
|
2015-03-05 09:19:32 +00:00
|
|
|
```elisp
|
2015-03-05 09:14:51 +00:00
|
|
|
(depends-on "haskell-mode")
|
|
|
|
```
|
|
|
|
|
|
|
|
and run `cask install` in that file's directory. This should install a
|
|
|
|
fresh `haskell-mode` for you. Restart your emacs and you should be
|
|
|
|
ready to open any `.cabal` or `.hs` file for editing. You will see
|
|
|
|
syntax highlighted, you'll be able to run commands like `M-x
|
|
|
|
haskell-process-load-file`.
|
|
|
|
|
|
|
|
However, you can't yet use `haskell-mode` in full because you haven't
|
|
|
|
configured indentation mode and interaction. Go read
|
|
|
|
[haskell-mode tutorial on setting the indentation-mode you like](https://github.com/haskell/haskell-mode/wiki/Indentation)
|
|
|
|
and
|
|
|
|
[Haskell Interactive Mode Setup](https://github.com/haskell/haskell-mode/wiki/Haskell-Interactive-Mode-Setup)
|
|
|
|
pages, or just put something like this to your `.emacs` (if you
|
|
|
|
already have `custom-set-variables` in your `.emacs` -- extend it):
|
|
|
|
|
2015-03-05 09:19:32 +00:00
|
|
|
```elisp
|
2015-03-05 09:14:51 +00:00
|
|
|
(defun turn-on-subword-mode ()
|
|
|
|
(interactive)
|
|
|
|
(subword-mode 1))
|
|
|
|
(defun my-haskell-mode-hook ()
|
|
|
|
(define-key haskell-mode-map (kbd "C-c C-l") 'haskell-process-load-or-reload)
|
|
|
|
(define-key haskell-mode-map (kbd "C-`") 'haskell-interactive-bring)
|
|
|
|
(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 C-c") 'haskell-process-cabal-build)
|
|
|
|
(define-key haskell-mode-map (kbd "C-c C-k") 'haskell-interactive-mode-clear)
|
|
|
|
(define-key haskell-mode-map (kbd "C-c c") 'haskell-process-cabal)
|
|
|
|
(define-key haskell-mode-map (kbd "SPC") 'haskell-mode-contextual-space))
|
|
|
|
(custom-set-variables
|
|
|
|
'(haskell-mode-hook
|
|
|
|
(quote
|
2015-03-05 09:21:38 +00:00
|
|
|
(interactive-haskell-mode
|
|
|
|
turn-on-haskell-indent
|
|
|
|
turn-on-subword-mode
|
|
|
|
turn-on-haskell-decl-scan
|
|
|
|
my-haskell-mode-hook)))
|
2015-03-05 09:14:51 +00:00
|
|
|
'(haskell-process-type 'cabal-repl))
|
|
|
|
```
|
|
|
|
|
|
|
|
Now you're more or less ready, but this is just a beginning. Go ahead,
|
|
|
|
open some `.hs` file and press `C-h ? b`. You will see list of
|
|
|
|
bindings available. Search for `haskell-` to see all haskell-related
|
|
|
|
bindings. Also, run `M-x haskell-` and press `TAB` for list of
|
|
|
|
available commands starting with `haskell-`. There's plenty of them!
|
|
|
|
|
|
|
|
Press `C-c C-l` to open a `cabal repl` shell with current module
|
|
|
|
loaded. You can easily play with your code like this. Also, pressing
|
|
|
|
`C-c C-i` will inspect symbol under cursor and show you some info. Neat!
|
2015-03-05 15:18:21 +00:00
|
|
|
|
|
|
|
### ghc-mod
|
|
|
|
|
|
|
|
[Ghc-mod](http://www.mew.org/~kazu/proj/ghc-mod/en/) is a tool that
|
|
|
|
helps your editor become more close to an IDE. It lets you do things
|
|
|
|
like blazingly-fast error-reporting upon save, autocompletion and more.
|
|
|
|
|
|
|
|
First, install ghc-mod itself:
|
|
|
|
|
|
|
|
```
|
|
|
|
cabal install ghc-mod
|
|
|
|
```
|
|
|
|
|
|
|
|
Then, add this to your `Cask` file:
|
|
|
|
|
|
|
|
```elisp
|
|
|
|
(depends-on "ghc")
|
|
|
|
```
|
|
|
|
|
|
|
|
And this to your `~/.emacs`:
|
|
|
|
|
|
|
|
```
|
|
|
|
(autoload 'ghc-init "ghc" nil t)
|
|
|
|
(autoload 'ghc-debug "ghc" nil t)
|
|
|
|
```
|
|
|
|
|
|
|
|
and extend your `my-haskell-mode-hook` with call to `(ghc-init)` like
|
|
|
|
this:
|
|
|
|
|
|
|
|
```elisp
|
|
|
|
(defun my-haskell-mode-hook ()
|
|
|
|
(ghc-init)
|
|
|
|
; ... all previous contents
|
|
|
|
)
|
|
|
|
```
|
|
|
|
|
|
|
|
After this is done, relaunch your Emacs (or re-eval config)
|
|
|
|
and open some `.hs`-file. Make a mistake and save the file, mistake
|
|
|
|
should now become underlined with red, and pressing `M-S-?` while
|
|
|
|
keeping curstor on top of it will show the error, and `M-n` `M-p`
|
|
|
|
should navigate between next/prev errors.
|
|
|
|
|
|
|
|
Check out
|
|
|
|
[ghc-mod homepage](http://www.mew.org/~kazu/proj/ghc-mod/en/) and
|
|
|
|
other resources to know more.
|
|
|
|
|
|
|
|
### TAGS
|
|
|
|
|
|
|
|
In order to get a "goto by name" functionality you can use standard
|
|
|
|
[Emacs TAGS support](https://www.gnu.org/software/emacs/manual/html_node/emacs/Tags.html). Haskell
|
|
|
|
has a special program, called `hasktags`:
|
|
|
|
|
|
|
|
```
|
|
|
|
cabal install hasktags
|
|
|
|
```
|
|
|
|
|
|
|
|
In order to generate tags, you can use `haskell-mode`'s `M-x
|
|
|
|
haskell-process-generate-tags`, or you can manually run `hasktags -e.`
|
|
|
|
in your project's root.
|
|
|
|
|
|
|
|
`haskell-mode` replaces standard `M-.` tag-search with it's own,
|
|
|
|
trying to search via ghci first, and only then via standard TAGS
|
|
|
|
mechanism.
|