spacemacs/layers/+lang/haskell
2020-08-28 23:41:29 +02:00
..
img Use + instead of ! for layer categories 2015-09-11 00:13:51 -04:00
config.el [layers/+lang/haskell] Removed intero, ghc-mod and company-ghci backends, set dante as default backend. 2020-08-26 22:34:59 +02:00
funcs.el [layers/+lang/haskell] Removed intero, ghc-mod and company-ghci backends, set dante as default backend. 2020-08-26 22:34:59 +02:00
layers.el [core] Fix layer dependencies based on layer variables 2019-09-30 02:00:48 -04:00
packages.el [layers/+lang/haskell] Removed intero, ghc-mod and company-ghci backends, set dante as default backend. 2020-08-26 22:34:59 +02:00
README.org documentation formatting: Fri Aug 28 21:26:14 UTC 2020 2020-08-28 23:41:29 +02:00

Haskell layer

/TakeV/spacemacs/media/commit/050a6d197377098179683afc388f4de731fc6066/layers/+lang/haskell/img/haskell.png

Description

This layer adds support for the Haskell language.

Features:

This layer is under 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)

To install them, use the 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 only add the installation path of stack itself. Usually it's ~/.local/bin.

Then make sure that your $PATH contains the installation path for the 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).

Choosing a backend

First, ensure that you have auto-completion layer enabled.

To choose a haskell backend, set the haskell layer variable haskell-completion-backend:

  (haskell :variables haskell-completion-backend 'dante)

Supported values for haskell-completion-backend are dante and lsp.

If you haven't specified any value for haskell-completion-backend, dante will be used as default backend, unless the layer lsp is enabled, in which case lsp is used as default backend.

Backend can be chosen on a per project basis using directory local variables (files named .dir-locals.el at the root of a project). An example of .dir-locals.el to use the lsp backend:

  ;;; Directory Local Variables
  ;;; For more information see (info "(emacs) Directory Variables")

  ((haskell-mode (haskell-completion-backend . lsp)))

Note: you can easily add a directory local variable with SPC f v d.

dante

Dante is a fork of Intero mode which aims exclusively at providing a convenient frontend to GHCi.

It brings features like syntax checking, auto completion, hlint suggestions, automatic error fixing, info at point, definition and use sites.

dante works for cabal, nix, sytx, and stack users and requires no additional setup.

dante requires Emacs 25.

lsp

lsp requires an appropriate installation of hie, the official Haskell language server, to work properly. hie is best installed by building it locally as it requires that the same GHC version has been used to compile your code as has been used for hie.

To install it please refer to the official installation instructions here.

Enabling the lsp backend requires the lsp layer to be enabled, and provides access to all the additional lsp-mode key bindings. As such it is more of a full backend than just a completion backend.

Alternatively, you can use Haskell Language Server instead of hie (check their docs for installation details). Haskell Language Server is meant to completely replace hie but it is still in early stages of development.

Optional extras

The Haskell layer supports some extra features, which can be enabled through the 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 styles (structured-haskell-mode/#81). Emacs editing style users can easily enable it by adding structured-haskell-mode to the list of dotspacemacs-additional-packages in your .spacemacs file. For more installation instructions, please refer to the official documentation at the structured-haskell-mode page. In case you are a 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 lets you reformat your code. You need to install the executable with cabal install hindent or stack install hindent.

To enable it you have to toggle the variable haskell-enable-hindent.

See examples here.

  (setq-default dotspacemacs-configuration-layers
    '((haskell :variables haskell-enable-hindent t)))

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

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
i step into the next function
r refresh the debugger buffer
s go to next step to inspect bindings
S go to previous step to inspect the bindings
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 and switch to the REPL
SPC m s S show the REPL without switching to it
C-j switch to next history item
C-k switch to previous history item
C-l clear the REPL

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

These 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 library 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 i reformat imports from anywhere in the buffer
SPC m r r apply the HLint suggestion under the cursor

Only some of the HLint suggestions can be applied.

Syntax checking

At the moment there are three components, which can indicate errors and warnings in the code. Those components are:

  • dante (via flycheck)
  • hlint (via flycheck)
  • haskell-mode interactive

Since all of 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 if one isn't working. Only flycheck errors (from ghci and hlint) are displayed in the error list and can be navigated between, 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 of syntax checking, and it's also the most elaborate. You need to install the syntax-checking layer first, which will bring flycheck. Please read the layer's documentation on how to interact with flycheck.

Flycheck has different Haskell checkers: haskell-dante, haskell-ghc, haskell-stack-ghc and haskell-hlint. Normally it can detect the best one to use automatically, but if it doesn't work, then you can change it with 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.

HLint can be configured via .hlint.yaml.

Interactive haskell-mode

Finally, interactive haskell-mode (SPC m s b) also displays errors. These errors can be navigated to, 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 projects with flymake-compile. It doesn't highlight errors in the buffer, but it's more reliable. The error navigation is similar to interactive haskell-mode.

Troubleshooting

Flycheck can fail silently for miscellaneous reasons. See the 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, then 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-new-repl
  • cabal-dev
  • cabal-ghci
  • stack-ghci

The REPL is stuck

Make sure that there's a space between the REPL's λ> prompt and the cursor. When there is no space, then the REPL will behave as if it's stuck. Usually, when you enter normal state, the cursor moves backwards by one character, so there is no required space when you switch to insert mode. There is a possible workaround - just add the following snippet to your dotspacemacs/user-config function:

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

It makes the cursor stay in 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 the REPL in insert mode. This is done by placing the following snippet in your dotspacemacs/user-config function:

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

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 the 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 the normal flycheck checker, even if the checker fails. Check the Flycheck doesn't work section.

HLint fails with parse error

If HLint is not correctly configured (e.g. does not load some extensions that you are using in your project) it might fail while parsing the file.

Check HLint docs for more details.

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 haskell-mode. Check the Flycheck doesn't work section.

Flycheck doesn't work

You can use the flycheck-compile command to check what's wrong with flycheck. This will show you the exact command line that's used, and its output.

If you are using stack, check the Flycheck doesn't work with 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 that it uses haskell-stack-ghc. If it still doesn't work, then 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, which contains some generated files, is normally under .stack-work/install/<os>/Cabal-<version>/build.

However the version of the cabal library that's used by stack to generate the directory name is not the version of the cabal library that's installed by stack but rather the version of cabal that's 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 that's used by flycheck using flycheck-compile and compare it to the actual path in the .stack-work directory. If they are different, then you'll 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 directory of the file that's 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 wrap the stack command in order to run all subcommands from the project's root directory. You can do so with the following script:

  #!/bin/bash
  cd `stack path --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 work when haskell-mode is in interactive mode, i.e. has an interactive session associated with it. Load it using SPC m s b.