refine haskell completion backends

- add haskell-completion-backend variable that should be used to select
  desired completion backend
- add support for intero (based on @cydparser layer)
- remove ghci-ng support
- update readme file:
  - document haskell-completion-backend variable
  - remove installation notes for ghc-mod as they are not relevant
    anymore
  - remove ghci-ng section
  - overall readme file fixes and improvements
This commit is contained in:
d12frosted 2016-06-10 19:53:07 +03:00 committed by syl20bnr
parent 4d4e89641e
commit a8e569d3b2
3 changed files with 164 additions and 185 deletions

View file

@ -9,12 +9,11 @@
- [[#layer][Layer]]
- [[#dependencies][Dependencies]]
- [[#setup-path][Setup PATH]]
- [[#ghc-mod-support][ghc-mod support]]
- [[#stack-users][Stack users]]
- [[#completion-support][Completion support]]
- [[#company-ghci][=company-ghci=]]
- [[#intero][=intero=]]
- [[#ghc-mod][=ghc-mod=]]
- [[#optional-extras][Optional extras]]
- [[#ghci-ng-support][GHCi-ng support]]
- [[#stack-users][Stack users]]
- [[#ghc-mod-users][ghc-mod users]]
- [[#structured-haskell-mode][structured-haskell-mode]]
- [[#hindent][hindent]]
- [[#key-bindings][Key bindings]]
@ -22,15 +21,16 @@
- [[#debug][Debug]]
- [[#debug-buffer][Debug Buffer]]
- [[#repl][REPL]]
- [[#intero-repl][Intero REPL]]
- [[#cabal-commands][Cabal commands]]
- [[#cabal-files][Cabal files]]
- [[#refactor][Refactor]]
- [[#ghc-mod][Ghc-mod]]
- [[#ghc-mod-1][Ghc-mod]]
- [[#insert-template][Insert template]]
- [[#syntax-checking][Syntax checking]]
- [[#flycheck][Flycheck]]
- [[#hlint][HLint]]
- [[#ghc-mod][ghc-mod]]
- [[#ghc-mod-2][ghc-mod]]
- [[#interactive-haskell-mode][Interactive haskell-mode]]
- [[#flymake][Flymake]]
- [[#troublesshooting][Troublesshooting]]
@ -55,7 +55,7 @@ This layer adds support for the [[https://www.haskell.org/][Haskell]] language.
** Features:
- syntax highlighting for [[https://github.com/haskell/haskell-mode][haskell source]], [[https://github.com/haskell/haskell-mode][cabal files]], [[https://github.com/bgamari/cmm-mode][C-- source]],
- auto-completion with [[https://github.com/iquiw/company-ghc][company-ghc]].
- auto-completion with one of selected backends (=intero=, =ghci= or =ghc-mod=).
*This layer is in construction, it needs your contributions and bug reports.*
@ -67,17 +67,18 @@ file.
** Dependencies
This layer requires some [[https://www.haskell.org/cabal/][cabal]] packages:
- =apply-refact=
- =hlint=
- =stylish-haskell=
- =hasktags=
- =ghc-mod=
- =hoogle=
- =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):
#+BEGIN_SRC sh
$ cabal install apply-refact stylish-haskell hlint hasktags ghc-mod hoogle
$ cabal install apply-refact hlint stylish-haskell hasktags hoogle
#+END_SRC
** Setup PATH
@ -95,110 +96,42 @@ 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~).
** ghc-mod support
[[http://www.mew.org/~kazu/proj/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). Note that
=ghc-mod= support is enabled by default, so if you want to disable it, you must
do it explicitly in your =.spacemacs= file.
** 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=.
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((haskell :variables haskell-enable-ghc-mod-support nil)))
'((haskell :variables haskell-completion-backend 'intero)))
#+END_SRC
=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 [[https://github.com/kazu-yamamoto/ghc-mod/wiki#known-issues-related-to-stack][document]].
*** =company-ghci=
[[https://github.com/juiko/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=).
*** Stack users
From time to time =ghc-mod= is not available via latest Stackage LTS version. So
if you have problems with calling =stack install ghc-mod=, try to use =stack
install ghc-mod --resolver lts-3.1= (the last known LTS version that had
=ghc-mod=). But even if it doesn't work, don't panic, it's easy to install it
from sources.
*** =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.
#+BEGIN_SRC sh
# clone cabal-helper
$ git clone https://github.com/DanielG/cabal-helper.git
# cd into cloned repository
$ cd cabal-helper
# init stack, so cabal-helper can be installed using stack
$ stack init
# now install it
$ stack install
# go back where you was
$ cd ..
# and remove cabal-helper repository since you don't need it
$ rm -rf cabal-helper
# now clone ghc-mod
$ git clone https://github.com/kazu-yamamoto/ghc-mod.git
# and cd into it
$ cd ghc-mod
# again, let's init stack
$ stack init
# now install it
$ stack install
# go back
$ cd ..
# and remove ghc-mod since you don't need it
$ rm -rf ghc-mod
#+END_SRC
*** =ghc-mod=
[[http://www.mew.org/~kazu/proj/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 [[https://github.com/kazu-yamamoto/ghc-mod/wiki#known-issues-related-to-stack][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.
*** GHCi-ng support
[[https://github.com/chrisdone/ghci-ng][ghci-ng]] adds some nice features to =haskell-mode=, and is supported in Spacemacs
by a layer variable:
Follow the instructions to install [[https://github.com/chrisdone/ghci-ng][ghci-ng]] (remember to add =:set +c= in
=~/.ghci=), next set the layer variable:
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((haskell :variables haskell-enable-ghci-ng-support t)))
#+END_SRC
Once ghci-ng is enabled, two of the old keybindings are overriden with improved
versions from ghci-ng, and a new keybinding available:
| Key Binding | Description |
|-------------+---------------------------------------------------------------------------|
| ~SPC m h t~ | gets the type of the identifier under the cursor or for the active region |
| ~SPC m g g~ | go to definition |
| ~SPC m u~ | finds uses of identifier |
**** Stack users
=Stack= and =ghci-ng= doesn't play well with each other, so the general advice
is to avoid mixing them. But, if you want mix them anyway, you'll need to set
=haskell-process-type= explicitly:
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((haskell :variables haskell-process-type 'ghci)))
;; or
(setq-default dotspacemacs-configuration-layers
'((haskell :variables haskell-process-type cabal-repl)))
#+END_SRC
This is needed, because by default =haskell-process-type= is set to =auto= and
if you have =stack.yaml= file in the root of your project, =stack-ghci= will be
used as process type.
**** ghc-mod users
If you want to use ~SPC m h t~ from =ghc-mod= instead of =ghci-ng=, then you need to
add following line in your =dotspacemacs/user-config=:
#+BEGIN_SRC emacs-lisp
(spacemacs/set-leader-keys-for-major-mode 'haskell-mode
"ht" 'ghc-show-type)
#+END_SRC
This might be useful, because =ghc-mod= doesn't require active REPL in order to
get type of symbol.
*** structured-haskell-mode
Currently there is no support for [[https://github.com/chrisdone/structured-haskell-mode][structured-haskell-mode]], since it doesn't play
very well with non-emacs editing style ([[https://github.com/chrisdone/structured-haskell-mode/issues/81][structured-haskell-mode/#81]]). Emacs
@ -298,8 +231,19 @@ REPL commands are prefixed by ~SPC m s~:
| ~SPC m s s~ | show the REPL without switching to it |
| ~SPC m s S~ | show and switch to the REPL |
** Cabal commands
** 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 |
@ -349,7 +293,7 @@ ghc-mod commands are prefixed by ~SPC m m~:
| Key Binding | Description |
|-------------+-----------------------------------------|
| ~SPC m m t~ | insert template |
| ~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~) |

View file

@ -15,12 +15,12 @@
(spacemacs|defvar-company-backends haskell-mode)
(spacemacs|defvar-company-backends haskell-cabal-mode)
(spacemacs|defvar-company-backends intero-repl-mode)
(defvar haskell-enable-ghci-ng-support nil
"If non-nil ghci-ng support is enabled")
(defvar haskell-completion-backend 'ghci
"Completion backend used by company.
Available options are `ghci', `intero' and `ghc-mod'. Default is
`ghci'.")
(defvar haskell-enable-hindent-style nil
"Style to use for formatting with hindent; available are: fundamental johan-tibell chris-done gibiansky. If nil hindent is disabled.")
(defvar haskell-enable-ghc-mod-support t
"If non-nil ghc-mod support is enabled")

View file

@ -14,13 +14,21 @@
cmm-mode
company
(company-cabal :toggle (configuration-layer/package-usedp 'company))
(company-ghc :toggle (and (configuration-layer/package-usedp 'company)
haskell-enable-ghc-mod-support))
;; ghci completion backend
(company-ghci :toggle (and (configuration-layer/package-usedp 'company)
(not haskell-enable-ghc-mod-support)))
(eq haskell-completion-backend 'ghci)))
;; ghc-mod completion backend
(company-ghc :toggle (and (configuration-layer/package-usedp 'company)
(eq haskell-completion-backend 'ghc-mod)))
(ghc :toggle (eq haskell-completion-backend 'ghc-mod))
;; intero completion backend
(intero :toggle (eq haskell-completion-backend 'intero))
flycheck
(flycheck-haskell :toggle (configuration-layer/package-usedp 'flycheck))
ghc
haskell-mode
haskell-snippets
(helm-hoogle :toggle (configuration-layer/package-usedp 'helm))
@ -34,19 +42,9 @@
(defun haskell/post-init-company ()
(spacemacs|add-company-hook haskell-mode)
(spacemacs|add-company-hook haskell-cabal-mode))
(defun haskell/init-company-ghc ()
(use-package company-ghc
:defer t
:init (push '(company-ghc company-dabbrev-code company-yasnippet)
company-backends-haskell-mode)))
(defun haskell/init-company-ghci ()
(use-package company-ghc
:defer t
:init (push '(company-ghci company-dabbrev-code company-yasnippet)
company-backends-haskell-mode)))
(spacemacs|add-company-hook haskell-cabal-mode)
(when (eq haskell-completion-backend 'intero)
(spacemacs|add-company-hook intero-repl-mode)))
(defun haskell/init-company-cabal ()
(use-package company-cabal
@ -56,25 +54,21 @@
(push '(company-cabal)
company-backends-haskell-cabal-mode)))
(defun haskell/init-helm-hoogle ()
(use-package helm-hoogle
(defun haskell/init-company-ghci ()
(use-package company-ghci
:defer t
:init
(dolist (mode haskell-modes)
(spacemacs/set-leader-keys-for-major-mode mode "hf" 'helm-hoogle))))
:init (push '(company-ghci company-dabbrev-code company-yasnippet)
company-backends-haskell-mode)))
(defun haskell/post-init-flycheck ()
(spacemacs/add-flycheck-hook 'haskell-mode))
(defun haskell/init-flycheck-haskell ()
(use-package flycheck-haskell
:commands flycheck-haskell-configure
:init (add-hook 'flycheck-mode-hook 'flycheck-haskell-configure)))
(defun haskell/init-company-ghc ()
(use-package company-ghc
:defer t
:init (push '(company-ghc company-dabbrev-code company-yasnippet)
company-backends-haskell-mode)))
(defun haskell/init-ghc ()
(use-package ghc
:defer t
:if haskell-enable-ghc-mod-support
:after (haskell-mode)
:init (add-hook 'haskell-mode-hook 'ghc-init)
:config
(progn
@ -97,6 +91,82 @@
(set-face-attribute 'ghc-face-error nil :underline nil)
(set-face-attribute 'ghc-face-warn nil :underline nil)))))
(defun haskell/init-intero ()
(use-package intero
:after (haskell-mode)
:init
(progn
(push '(company-intero company-dabbrev-code company-yasnippet)
company-backends-haskell-mode)
(add-hook 'haskell-mode-hook #'intero-mode))
:config
(progn
(spacemacs|diminish intero-mode " λ" " \\")
(defun haskell-intero/insert-type ()
(interactive)
(intero-type-at :insert))
(defun haskell-intero/display-repl ()
(interactive)
(let ((buffer (intero-repl-buffer)))
(unless (get-buffer-window buffer 'visible)
(display-buffer (intero-repl-buffer)))))
(defun haskell-intero/pop-to-repl ()
(interactive)
(pop-to-buffer (intero-repl-buffer)))
(defun haskell-intero//preserve-focus (f)
(let ((buffer (current-buffer)))
(funcall f)
(pop-to-buffer buffer)))
(advice-add 'intero-repl-load
:around #'haskell-intero//preserve-focus)
(dolist (mode haskell-modes)
(spacemacs/set-leader-keys-for-major-mode mode
"gg" 'intero-goto-definition
"hi" 'intero-info
"ht" 'intero-type-at
"hT" 'haskell-intero/insert-type
"sb" 'intero-repl-load))
(dolist (mode (cons 'haskell-cabal-mode haskell-modes))
(spacemacs/set-leader-keys-for-major-mode mode
"sc" nil
"ss" 'haskell-intero/display-repl
"sS" 'haskell-intero/pop-to-repl))
(dolist (mode (append haskell-modes '(haskell-cabal-mode intero-repl-mode)))
(spacemacs/declare-prefix-for-mode mode "mi" "haskell/intero")
(spacemacs/set-leader-keys-for-major-mode mode
"ic" 'intero-cd
"id" 'intero-devel-reload
"ik" 'intero-destroy
"il" 'intero-list-buffers
"ir" 'intero-restart
"it" 'intero-targets))
(evil-define-key '(insert normal) intero-mode-map
(kbd "M-.") 'intero-goto-definition))))
(defun haskell/init-helm-hoogle ()
(use-package helm-hoogle
:defer t
:init
(dolist (mode haskell-modes)
(spacemacs/set-leader-keys-for-major-mode mode "hf" 'helm-hoogle))))
(defun haskell/post-init-flycheck ()
(spacemacs/add-flycheck-hook 'haskell-mode))
(defun haskell/init-flycheck-haskell ()
(use-package flycheck-haskell
:commands flycheck-haskell-configure
:init (add-hook 'flycheck-mode-hook 'flycheck-haskell-configure)))
(defun haskell/init-haskell-mode ()
(use-package haskell-mode
:defer t
@ -138,7 +208,7 @@
;; hooks
(add-hook 'haskell-mode-hook 'spacemacs/init-haskell-mode)
(unless haskell-enable-ghc-mod-support
(unless (eq haskell-completion-backend 'ghc-mod)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode))
;; prefixes
@ -154,9 +224,7 @@
;; key bindings
(defun spacemacs/haskell-process-do-type-on-prev-line ()
(interactive)
(if haskell-enable-ghci-ng-support
(haskell-mode-show-type-at 1)
(haskell-process-do-type 1)))
(haskell-process-do-type 1))
(dolist (mode haskell-modes)
(spacemacs/set-leader-keys-for-major-mode mode
@ -177,8 +245,8 @@
"hd" 'inferior-haskell-find-haddock
"hh" 'hoogle
"hH" 'haskell-hoogle-lookup-from-local
"hi" (lookup-key haskell-mode-map (kbd "C-c TAB"))
"ht" (lookup-key haskell-mode-map (kbd "C-c C-t"))
"hi" 'haskell-process-do-info
"ht" 'haskell-process-do-type
"hT" 'spacemacs/haskell-process-do-type-on-prev-line
"hy" 'hayoo
@ -240,40 +308,7 @@
(evil-define-key 'insert haskell-interactive-mode-map
(kbd "RET") 'haskell-interactive-mode-return)
(evil-define-key 'normal haskell-interactive-mode-map
(kbd "RET") 'haskell-interactive-mode-return)
;; interactive haskell mode
(unless (or haskell-enable-ghc-mod-support
haskell-enable-ghci-ng-support)
(dolist (mode haskell-modes)
(spacemacs/set-leader-keys-for-major-mode mode
"hi" 'haskell-process-do-info
"ht" 'haskell-process-do-type)))
;; GHCi-ng
(when haskell-enable-ghci-ng-support
;; haskell-process-type is set to auto, so setup ghci-ng for either case
;; if haskell-process-type == cabal-repl
(setq haskell-process-args-cabal-repl '("--ghc-option=-ferror-spans" "--with-ghc=ghci-ng"))
;; if haskell-process-type == GHCi
(setq haskell-process-path-ghci "ghci-ng")
;; fixes ghci-ng for stack projects
(setq haskell-process-wrapper-function
(lambda (args)
(append args (list "--with-ghc" "ghci-ng"))))
(dolist (mode haskell-modes)
(spacemacs/set-leader-keys-for-major-mode mode
;; function suggested in
;; https://github.com/chrisdone/ghci-ng#using-with-haskell-mode
"u" 'haskell-mode-find-uses
"ht" 'haskell-mode-show-type-at
"gg" 'haskell-mode-goto-loc))
;; Useful to have these keybindings for .cabal files, too.
(with-eval-after-load 'haskell-cabal-mode-map
(define-key haskell-cabal-mode-map
[?\C-c ?\C-z] 'haskell-interactive-switch))))
(kbd "RET") 'haskell-interactive-mode-return))
;; align rules for Haskell
(with-eval-after-load 'align