This repository has been archived on 2024-10-22. You can view files and clone it, but cannot push or open issues or pull requests.
spacemacs/layers/+lang/haskell
syl20bnr 89dc1af9a6 Remove spacemacs/add-to-local-vars-hook and use (format ...)
It is better to directly hook function using the conventional hook
functions.

Replace usage of (concat ...) by a (format ...) from which is more
readable.
2016-06-26 14:04:13 -04:00
..
img
config.el refine haskell completion backends 2016-06-23 00:47:23 -04:00
funcs.el conditionally enable haskell completion backend 2016-06-26 13:51:11 -04:00
packages.el Remove spacemacs/add-to-local-vars-hook and use (format ...) 2016-06-26 14:04:13 -04:00
README.org haskell: align tables in documentation 2016-06-23 00:50:03 -04:00

Haskell layer

/TakeV/spacemacs/media/commit/237d1143d125809f11dbea753f5ca1c69adc9719/layers/+lang/haskell/img/haskell.png

Description

This layer adds support for the Haskell language.

Features:

This layer is in construction, it needs your contributions and bug reports.

Install

Layer

To use this configuration layer, add it to your ~/.spacemacs. You will need to add haskell to the existing dotspacemacs-configuration-layers list in this file.

Dependencies

This layer requires some cabal packages:

  • apply-refact (required by hlint-refactor)
  • hlint (required by hlint-refactor)
  • stylish-haskell (optional for haskell-mode)
  • hasktags (optional)
  • hoogle (optional for haskell-mode and helm-hoogle)
  • ghc-mod (optional for completion)
  • intero (optional for completion)

To install them, use following command (or the stack equivalent):

$ cabal install apply-refact hlint stylish-haskell hasktags hoogle

Setup PATH

First of all make sure that your $PATH contains the installation path for Haskell tools like ghc, ghci etc. It depends on how you have installed ghc, but you can always check it by running which ghc in your terminal. Stack users should add only the installation path of stack itself. Usually it's ~/.local/bin.

Then make sure that your $PATH contains the installation path for cabal packages. If you are using cabal it should be ~/.cabal/bin or ~/Library/Haskell/bin (for 'Haskell for Mac' users). If you are using stack then it should be ~/.local/bin.

For information about setting up $PATH, check out the corresponding section in the FAQ (SPC h SPC $PATH RET).

Completion support

This layer provides several completion backends - intero, ghci and ghc-mod. By default ghci (company-ghci) is used as it requires no dependencies and works both with stack and pure cabal projects. In order to manually set completion backend set value of haskell-completion-backend.

(setq-default dotspacemacs-configuration-layers
  '((haskell :variables haskell-completion-backend 'intero)))

company-ghci

company-ghci communicates directly with ghci in order to provide completion. In order to use it you have to call haskell-process-load-or-reload (SPC s b).

intero

Intero works only for stack users. You can manually install intero executable by calling stack install intero, but this step is optional as Intero installs itself.

ghc-mod

ghc-mod enhances haskell-mode with for example code completion, templates, case-splitting and much more. In order to use it you need to install the executable with cabal install ghc-mod (or stack equivalent).

Stack users also should make sure that dist/setup-config doesn't exist in the project root. As it will confuse ghc-mod. For more troubleshooting, checkout this document.

Also note that ghc-mod works only with GHC version that was used to build ghc-mod. You can check which version was used by calling ghc-mod --version.

Optional extras

The Haskell layer supports some extra features that can be enabled through layer variables.

structured-haskell-mode

Currently there is no support for structured-haskell-mode, since it doesn't play very well with non-emacs editing style (structured-haskell-mode/#81). Emacs editing style users might easily enable it by adding structured-haskell-mode to list of dotspacemacs-additional-packages in your .spacemacs file. For more installation instructions, please refer to the official documentation at structured-haskell-mode page. In case you are non-emacs editing style user and still want to use structured-haskell-mode - use it at your own risk.

Any contributions that will help to solve issues with structured-haskell-mode are warmly welcome!

hindent

hindent is an extensible Haskell pretty printer, which let's you reformat your code. You need to install the executable with cabal install hindent or stack install hindent

To enable it you have to set the variable haskell-enable-hindent-style to a supported style. The available styles are:

  • fundamental
  • johan-tibell
  • chris-done
  • gibiansky

See examples here.

(setq-default dotspacemacs-configuration-layers
  '((haskell :variables haskell-enable-hindent-style "johan-tibell")))

Key bindings

All Haskell specific bindings are prefixed with the major-mode leader SPC m.

Top-level commands are prefixed by SPC m:

Key Binding Description
SPC m g g go to definition or tag
SPC m g i cycle the Haskell import lines or return to point (with prefix arg)
SPC m f format buffer using haskell-stylish
SPC m F format declaration using hindent (if enabled)

Documentation

Documentation commands are prefixed by SPC m h

Key Binding Description
SPC m h d find or generate Haddock documentation for the identifier under the cursor
SPC m h f do a helm-hoogle lookup
SPC m h h do a Hoogle lookup
SPC m h H do a local Hoogle lookup
SPC m h i gets information for the identifier under the cursor
SPC m h t gets the type of the identifier under the cursor
SPC m h y do a Hayoo lookup

Debug

Debug commands are prefixed by SPC m d:

Key Binding Description
SPC m d a abandon current process
SPC m d b insert breakpoint at function
SPC m d B delete breakpoint
SPC m d c continue current process
SPC m d d start debug process, needs to be run first
SPC m d n next breakpoint
SPC m d N previous breakpoint
SPC m d p previous breakpoint
SPC m d r refresh process buffer
SPC m d s step into the next function
SPC m d t trace the expression

Debug Buffer

Key Binding Description
RET select object at the point
a abandon current computation
b break on function
c continue the current computation
d delete object at the point
n go to next step to inspect bindings
N or p go to previous step to inspect the bindings
r refresh the debugger buffer
s step into the next function
t trace the expression

REPL

REPL commands are prefixed by SPC m s:

Key Binding Description
SPC m s b load or reload the current buffer into the REPL
SPC m s c clear the REPL
SPC m s s show the REPL without switching to it
SPC m s S show and switch to the REPL

Intero REPL

Intero REPL commands are prefixed by SPC m i:

Key Binding Description
SPC m i c change directory in the backend process
SPC m i d reload the module DevelMain and then run DevelMain.update
SPC m i k stop the current worker process and kill its associated
SPC m i l list hidden process buffers created by intero
SPC m i r restart the process with the same configuration as before
SPC m i t set the targets to use for stack ghci

Cabal commands

Cabal commands are prefixed by SPC m c:

Key Binding Description
SPC m c a cabal actions
SPC m c b build the current cabal project, i.e. invoke cabal build
SPC m c c compile the current project, i.e. invoke ghc
SPC m c v visit the cabal file

Cabal files

This commands are available in a cabal file.

Key Binding Description
SPC m d add a dependency to the project
SPC m b go to benchmark section
SPC m e go to executable section
SPC m t go to test-suite section
SPC m m go to exposed modules
SPC m l go to libary section
SPC m n go to next subsection
SPC m p go to previous subsection
SPC m s c clear the REPL
SPC m s s show the REPL without switching to it
SPC m s S show and switch to the REPL
SPC m N go to next section
SPC m P go to previous section
SPC m f find or create source-file under the cursor

Refactor

Refactor commands are prefixed by SPC m r:

Key Binding Description
SPC m r b apply all HLint suggestions in the current buffer
SPC m r r apply the HLint suggestion under the cursor

Only some of the HLint suggestions can be applied.

Ghc-mod

These commands are only available when ghc-mod is enabled.

For more info, see http://www.mew.org/~kazu/proj/ghc-mod/en/emacs.html

ghc-mod commands are prefixed by SPC m m:

Key Binding Description
SPC t insert template
SPC m m u insert template with holes
SPC m m a select one of possible cases (ghc-auto)
SPC m m f replace a hole (ghc-refine)
SPC m m e expand template haskell
SPC m m n go to next type hole
SPC m m p go to previous type hole
SPC m m > make indent deeper
SPC m m < make indent shallower

Insert template

SPC m m t inserts a template. What this means is that in the beginning of a buffer, module Foo where is inserted. On a function without signature, the inferred type is inserted. On a symbol foo without definition, foo = undefined is inserted or a proper module is imported. SPC m m u inserts a hole in this case. On a variable, the case is split. When checking with hlint, original code is replaced with hlint's suggestion if possible.

Syntax checking

At the moment there are four components which can check the syntax and indicates somehow error and warnings in the code. Those components are

  • flycheck
  • hlint (via flycheck)
  • ghc-mod
  • haskell-mode interactive

As all these components can be active at the same time, it can be tricky to know which component is displaying which message, especially when they disagree or one is not working. Only flycheck errors (ghc and hlint) are displayed in the error list and can be navigated using the standard spacemacs key bindings (under SPC e) even though errors from other modes might highlight the actual buffer.

Flycheck

This is the standard spacemacs way to do syntax checking and the most elaborate. You need the syntax-checking layer to enable this. Please the documentation for that layer on how to interact with flycheck.

Flycheck has different Haskell checkers: haskell-ghc, haskell-stackghc and haskell-hlint. Normally it can automatically detect the best one to use, but if it doesn't work, you can change it using SPC e s.

HLint

HLint is a linter for Haskell. It doesn't detect errors (as long as it can parse the file) but bad coding style and code smell. The HLint checker is called after the flycheck GHC checker.

ghc-mod

Ghc-mod, when enabled, also does syntax checking. It doesn't highlight errors but instead displays an exclamation point in the fringe. You can navigate between errors using ghc-goto-next-error (M-n) and ghc-goto-prev-error (M-p).

Interactive haskell-mode

Finally, interactive haskell-mode (SPC m s b) also displays errors. These errors can be navigated from the interactive buffer (by clicking on the error) or using haskell-goto-next-error (M-n) and haskell-goto-prev-error (M-p).

Flymake

An alternative to syntax checking is to build your project using flymake-compile. It doesn't highlight error in the buffer but is more reliable. The error navigation is similar to interactive haskell-mode.

Troublesshooting

Flycheck and ghc-mod can fail silently for miscellaneous reasons. See the /TakeV/spacemacs/src/commit/237d1143d125809f11dbea753f5ca1c69adc9719/layers/+lang/haskell/FAQ for troubleshooting.

FAQ

The REPL doesn't work

Usually haskell-mode is great at figuring out which interactive process to bring up. But if you are experiencing problems with it you can help haskell-mode by setting haskell-process-type as in following code:

(setq-default dotspacemacs-configuration-layers
  '((haskell :variables haskell-process-type 'stack-ghci)))

Available options are:

  • ghci
  • cabal-repl
  • cabal-dev
  • cabal-ghci
  • stack-ghci

The REPL is stuck

Make sure that when you are typing anything in REPL there is a space between what you type and λ>. When there is no space - REPL will behave as it's stuck. Usually, when you enter normal state, cursor is moved back, so there is no required space when you switch to insert mode. There is possible workaround - just add following snippet to your dotspacemacs/user-config function:

(when (configuration-layer/package-usedp 'haskell)
  (add-hook 'haskell-interactive-mode-hook
            (lambda ()
              (setq-local evil-move-cursor-back nil))))

It will make cursor stay at the right place in the REPL buffer when you enter normal state. Which in most cases helps you to avoid the problem with 'stuck' REPL.

Also, some users might want to start REPL in insert mode. For this to happen you could place following snippet in your dotspacemacs/user-config function:

(when (configuration-layer/package-usedp 'haskell)
    (defadvice haskell-interactive-switch (after spacemacs/haskell-interactive-switch-advice activate)
      (when (eq dotspacemacs-editing-style 'vim)
        (call-interactively 'evil-insert))))

I am using stack and ghc-mod, but ghc-mod doesn't work

Make sure that dist directory doesn't exist in your project root. So if it exists, just remove it and try again.

ghc-mod doesn't work

First of all - make sure that the version of ghc matches the version of ghc that was used to build ghc-mod. To get the latter call ghc-mod --version in terminal. If they don't match you have to rebuild ghc-mod.

Stack provides ability to use different ghc versions across different projects. In case you are using this feature you have to rebuild ghc-mod quite often. If you use ghc-mod only for completion and don't want to rebuild ghc-mod every time you switch project you'd better disable ghc-mod support, so company-ghci will be used for completion.

The second thing to do if it's still not working - call ghc-mod debug in the root of project you are currently working on. Make sure that it shows no errors. If there are errors you can't solve - it's better to report them upstream.

Indentation doesn't reset when pressing return after an empty line

This is the intended behavior in haskell-indentation-mode. If you want to reset indentation when pressing return after an empty line, add the following snippet into your dotspacemacs/user-config function.

(defun haskell-indentation-advice ()
  (when (and (< 1 (line-number-at-pos))
             (save-excursion
               (forward-line -1)
               (string= "" (s-trim (buffer-substring (line-beginning-position) (line-end-position))))))
    (delete-region (line-beginning-position) (point))))

(advice-add 'haskell-indentation-newline-and-indent
            :after 'haskell-indentation-advice)

Flycheck displays HLInt warnings but not errors

The HLint checker is called after normal flycheck checker even if the checker fails. Check the /TakeV/spacemacs/src/commit/237d1143d125809f11dbea753f5ca1c69adc9719/layers/+lang/haskell/Flycheck%20doesn't%20work section.

I can see highlighted errors but they don't appear in the error list

The error list is only set by flycheck. You are probably seeing errors highlighted by either ghc-mode or haskell-mode. Check the /TakeV/spacemacs/src/commit/237d1143d125809f11dbea753f5ca1c69adc9719/layers/+lang/haskell/Flycheck%20doesn't%20work section.

Flycheck doesn't work

You can check what is wrong with flycheck with the flycheck-compile command. This will show you the exact command line used and its output.

If you are using stack, check the /TakeV/spacemacs/src/commit/237d1143d125809f11dbea753f5ca1c69adc9719/layers/+lang/haskell/Flycheck%20doesn't%20work%20with%20=stack= section.

Flycheck doesn't work with stack

First check that flycheck uses the correct checker and all the paths are properly configured using flycheck-verify-setup (SPC e v). You can force the checker with flycheck-select-checker (SPC e s) to ensure it uses haskell-stack-ghc. If it still doesn't work, it could be one of the following problems:

  • The stack build directory is wrong
  • The project root is not set properly

The stack build directory is wrong

The path to the build directory containing some generated files is normally under .stack-work/install/<os>/Cabal-<version>/build.

However, the version of the cabal library used by stack to generate the directory name is not the version of the cabal library installed by stack, but the version of cabal associated to the GHC version. This error can happen after upgrading cabal or cabal-install. To check if this is the problem, compare the path name of the build path used by flycheck using flycheck-compile and compare it to to the actual path in the .stack-work directory. If they are different you need to reinstall ghc using the command stack setup --upgrade-cabal.

The Project root directory is not set properly

Flycheck launches the GHC command not from the project root directory but from the the directory of the file being checked. This is normally not a problem as all the paths are set properly, however it could be a problem if some template Haskell functions use relative paths (e.g. in Yesod scaffolded projects).

Until it's fixed in flycheck the workaround is to the wrap the stack command to run all subcommands from the project root directory. You can do so with the following script:

#!/bin/bash
cd `stack --project-root`
stack $*

Make sure you set flycheck-haskell-stack-ghc-executable to this script.

haskell-mode commands don't work

Some (most of) the haskell-mode commands only works when haskell-mode is in interactive mode, i.e. as a interactive session associated to it. Load it using SPC m s b.

ghc-mod and haskell-mode commands overlap. How do I know which command belongs to what?

ghc-mod commands are prefixed with ghc-, haskell-mode ones are prefixed with haskell-.

Some commands start with ghc- and some with haskell-. What does that mean?

Commands starting with ghc- are ghc-mod commands. Commands starting with haskell- are haskell-mode commands.