mirror of
https://gitlab.com/dwt1/dotfiles.git
synced 2026-04-22 19:10:24 +10:00
Moving to Doom Emacs!
This commit is contained in:
41
.emacs.d/modules/lang/haskell/+dante.el
Normal file
41
.emacs.d/modules/lang/haskell/+dante.el
Normal file
@@ -0,0 +1,41 @@
|
||||
;;; lang/haskell/+dante.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! +dante)
|
||||
|
||||
(use-package! dante
|
||||
:hook (haskell-mode-local-vars . dante-mode)
|
||||
:init
|
||||
(setq dante-load-flags '(;; defaults:
|
||||
"+c"
|
||||
"-Wwarn=missing-home-modules"
|
||||
"-fno-diagnostics-show-caret"
|
||||
;; necessary to make attrap-attrap useful:
|
||||
"-Wall"
|
||||
;; necessary to make company completion useful:
|
||||
"-fdefer-typed-holes"
|
||||
"-fdefer-type-errors"))
|
||||
:config
|
||||
(when (featurep! :tools flycheck)
|
||||
(flycheck-add-next-checker 'haskell-dante '(warning . haskell-hlint)))
|
||||
|
||||
(set-company-backend! 'dante-mode #'dante-company)
|
||||
|
||||
(defadvice! +haskell--restore-modified-state-a (orig-fn &rest args)
|
||||
"Marks the buffer as falsely modified.
|
||||
Dante quietly saves the current buffer (without triggering save hooks) before
|
||||
invoking flycheck, unexpectedly leaving the buffer in an unmodified state. This
|
||||
is annoying if we depend on save hooks to do work on the buffer (like
|
||||
reformatting)."
|
||||
:around #'dante-async-load-current-buffer
|
||||
(let ((modified-p (buffer-modified-p)))
|
||||
(apply orig-fn args)
|
||||
(if modified-p (set-buffer-modified-p t))))
|
||||
|
||||
(when (featurep 'evil)
|
||||
(add-hook 'dante-mode-hook #'evil-normalize-keymaps))
|
||||
(map! :map dante-mode-map
|
||||
:localleader
|
||||
"t" #'dante-type-at
|
||||
"i" #'dante-info
|
||||
"l" #'haskell-process-load-or-reload
|
||||
"e" #'dante-eval-block
|
||||
"a" #'attrap-attrap))
|
||||
30
.emacs.d/modules/lang/haskell/+intero.el
Normal file
30
.emacs.d/modules/lang/haskell/+intero.el
Normal file
@@ -0,0 +1,30 @@
|
||||
;;; lang/haskell/+intero.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! +intero)
|
||||
|
||||
(use-package! intero
|
||||
:commands intero-mode
|
||||
:init
|
||||
(add-hook! 'haskell-mode-local-vars-hook
|
||||
(defun +haskell-init-intero-h ()
|
||||
"Initializes `intero-mode' in haskell-mode, unless stack isn't installed.
|
||||
This is necessary because `intero-mode' doesn't do its own error checks."
|
||||
(when (derived-mode-p 'haskell-mode)
|
||||
(if (executable-find "stack")
|
||||
(intero-mode +1)
|
||||
(message "Couldn't find stack. Refusing to enable intero-mode.")))))
|
||||
:config
|
||||
(setq haskell-compile-cabal-build-command "stack build --fast")
|
||||
(set-lookup-handlers! 'intero-mode :definition #'intero-goto-definition)
|
||||
(set-company-backend! 'intero-mode 'intero-company)
|
||||
(when (featurep! :tools flycheck)
|
||||
(flycheck-add-next-checker 'intero '(warning . haskell-hlint)))
|
||||
|
||||
(when (featurep 'evil)
|
||||
(add-hook 'intero-mode-hook #'evil-normalize-keymaps))
|
||||
(map! :localleader
|
||||
:map intero-mode-map
|
||||
"t" #'intero-type-at
|
||||
"i" #'intero-info
|
||||
"l" #'intero-repl-load
|
||||
"e" #'intero-repl-eval-region
|
||||
"a" #'intero-apply-suggestions))
|
||||
10
.emacs.d/modules/lang/haskell/+lsp.el
Normal file
10
.emacs.d/modules/lang/haskell/+lsp.el
Normal file
@@ -0,0 +1,10 @@
|
||||
;;; lang/haskell/+lsp.el -*- lexical-binding: t; -*-
|
||||
|
||||
(use-package! lsp-haskell
|
||||
:after haskell-mode
|
||||
:init (add-hook 'haskell-mode-hook #'lsp!)
|
||||
:config
|
||||
(when IS-MAC
|
||||
(setq lsp-haskell-process-path-hie "hie-wrapper"))
|
||||
;; Does some strange indentation if it pastes in the snippet
|
||||
(setq-hook! 'haskell-mode-hook yas-indent-line 'fixed))
|
||||
168
.emacs.d/modules/lang/haskell/README.org
Normal file
168
.emacs.d/modules/lang/haskell/README.org
Normal file
@@ -0,0 +1,168 @@
|
||||
#+TITLE: lang/haskell
|
||||
#+DATE: January 16, 2017
|
||||
#+SINCE: v0.7
|
||||
#+STARTUP: inlineimages
|
||||
|
||||
* Table of Contents :TOC:
|
||||
- [[#description][Description]]
|
||||
- [[#external-resources][External resources]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#plugins][Plugins]]
|
||||
- [[#prerequisites][Prerequisites]]
|
||||
- [[#cabal][Cabal]]
|
||||
- [[#lsp][LSP]]
|
||||
- [[#stack][Stack]]
|
||||
- [[#haskell-packages][Haskell packages]]
|
||||
- [[#configuration][Configuration]]
|
||||
- [[#using-the-new-style-cabal-repl][Using the new-style cabal REPL]]
|
||||
- [[#troubleshooting][Troubleshooting]]
|
||||
|
||||
* Description
|
||||
This module adds [[https://www.haskell.org/][Haskell]] support, powered by either [[https://github.com/jyp/dante][dante]] (the default), LSP or
|
||||
[[https://haskell-lang.org/intero][intero]].
|
||||
|
||||
+ Code completion (~company-ghc~)
|
||||
+ Look up documentation (~hoogle~)
|
||||
+ eldoc support (~dante~)
|
||||
+ REPL (~ghci~)
|
||||
+ Syntax-checking (~flycheck~)
|
||||
+ Code navigation (~dante~)
|
||||
+ [[https://github.com/hlissner/doom-snippets/tree/master/haskell-mode][Snippets]]
|
||||
|
||||
** External resources
|
||||
Here are a few resources I've found indispensable in my Haskell adventures:
|
||||
|
||||
+ [[http://learnyouahaskell.com/][Learn you a haskell for great good]]
|
||||
+ [[http://haskellbook.com/][Haskell Programming from first principles]]
|
||||
+ [[https://github.com/krispo/awesome-haskell][Awesome Haskell]]: an extensive list of haskell resources
|
||||
+ [[https://docs.haskellstack.org/en/stable/README/][The Haskell Tool Stack docs]]
|
||||
|
||||
** Module Flags
|
||||
+ =+dante= Enables dante; a fork of intero aimed at lightweightedness. It
|
||||
doesn't depend on =stack=, supports both ~cabal~-only and ~stack~ projects,
|
||||
but lacks eldoc support.
|
||||
+ =+lsp= Enables lsp-haskell (this requires the ~:tools lsp~ to be enabled).
|
||||
+ =+intero= (Deprecated) Enables intero; a comprehensive, stack-based
|
||||
development environment for Haskell.
|
||||
|
||||
** Plugins
|
||||
+ [[https://github.com/haskell/haskell-mode][haskell-mode]]
|
||||
+ =+dante=
|
||||
+ [[https://github.com/jyp/dante][dante]]
|
||||
+ [[https://github.com/jyp/attrap][attrap]]
|
||||
+ =+lsp=
|
||||
+ [[https://github.com/emacs-lsp/lsp-haskell][lsp-haskell]]
|
||||
+ =+intero=
|
||||
+ [[https://github.com/chrisdone/intero][intero]]
|
||||
|
||||
* Prerequisites
|
||||
Depending on whether you use Intero, Dante or LSP, your dependencies will
|
||||
differ:
|
||||
|
||||
+ Dante users need =cabal=, =ghc= and =ghc-mod=
|
||||
+ LSP users need the =haskell-ide-engine= LSP server
|
||||
+ Intero and LSP users need =stack=
|
||||
+ All users will need the =hoogle= package
|
||||
|
||||
** Cabal
|
||||
To use Dante, you need =cabal= (the haskell package builder) and =ghci= (the
|
||||
compiler, syntax checker & repl):
|
||||
|
||||
*** MacOS
|
||||
#+BEGIN_SRC sh
|
||||
brew install cabal-install ghc
|
||||
#+END_SRC
|
||||
|
||||
*** Arch Linux
|
||||
#+BEGIN_SRC sh
|
||||
sudo pacman -S cabal-install ghc
|
||||
#+END_SRC
|
||||
|
||||
*** openSUSE
|
||||
#+BEGIN_SRC sh :dir /sudo::
|
||||
sudo zypper install cabal-install ghc
|
||||
#+END_SRC
|
||||
|
||||
** LSP
|
||||
You will need =stack= and =git= installed.
|
||||
|
||||
You will find a comprehensive [[https://github.com/haskell/haskell-ide-engine#installation][install guide for haskell-ide-engine on its
|
||||
project page]], but here's a TL;DR:
|
||||
|
||||
*** MacOS
|
||||
haskell-ide-engine must be build and installed manually on MacOS, e.g.
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
git clone https://github.com/haskell/haskell-ide-engine
|
||||
cd haskell-ide-engine
|
||||
make
|
||||
#+END_SRC
|
||||
|
||||
*** Arch Linux
|
||||
=haskell-ide-engine-git= is available on the AUR
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
yay -S haskell-ide-engine-git
|
||||
#+END_SRC
|
||||
|
||||
** Stack
|
||||
To use Intero or LSP, you need =stack=:
|
||||
|
||||
*** MacOS
|
||||
#+BEGIN_SRC sh
|
||||
brew install haskell-stack
|
||||
stack setup
|
||||
#+END_SRC
|
||||
*** Arch Linux
|
||||
#+BEGIN_SRC sh
|
||||
sudo pacman -S stack
|
||||
# Replace pacaur with your AUR package manager of choice
|
||||
pacaur -S ncurses5-compat-lib
|
||||
stack setup
|
||||
#+END_SRC
|
||||
|
||||
*** openSUSE
|
||||
#+BEGIN_SRC sh :dir /sudo::
|
||||
sudo zypper install stack
|
||||
stack setup
|
||||
#+END_SRC
|
||||
|
||||
** Haskell packages
|
||||
You'll need to install the following packages using ~stack~ or ~cabal~:
|
||||
|
||||
+ (Dante users) =ghc-mod=
|
||||
#+BEGIN_SRC sh
|
||||
stack install ghc-mod
|
||||
# or
|
||||
cabal install ghc-mod
|
||||
#+END_SRC
|
||||
+ =hoogle=
|
||||
#+BEGIN_SRC sh
|
||||
cabal update
|
||||
cabal install happy haskell-src-exts # ghc-mod/hoogle dependencies
|
||||
cabal ghc-mod hoogle
|
||||
# or
|
||||
stack install ghc-mod
|
||||
stack install hoogle
|
||||
#+END_SRC
|
||||
|
||||
And ensure the binaries for these packages are in your ~PATH~, e.g.
|
||||
|
||||
#+BEGIN_SRC sh
|
||||
# place this in your profile file, like ~/.bash_profile or ~/.zshenv
|
||||
export PATH="~/.local/bin:$PATH"
|
||||
#+END_SRC
|
||||
|
||||
* Configuration
|
||||
** Using the new-style cabal REPL
|
||||
=haskell-mode= will typically detect what REPL to run based on your project
|
||||
(e.g. stack, (old-style) cabal or ghc). If you want the new-style cabal REPL you
|
||||
must set ~haskell-process-type~ manually:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq haskell-process-type 'cabal-new-repl)
|
||||
#+END_SRC
|
||||
|
||||
* Troubleshooting
|
||||
+ Stack users: a ~dist/setup-config~ file in your project may cause [[https://github.com/DanielG/ghc-mod/wiki#known-issues-related-to-stack][ghc-mod to
|
||||
not work]].
|
||||
14
.emacs.d/modules/lang/haskell/autoload.el
Normal file
14
.emacs.d/modules/lang/haskell/autoload.el
Normal file
@@ -0,0 +1,14 @@
|
||||
;;; lang/haskell/autoload.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +haskell/open-repl (&optional arg)
|
||||
"Opens a Haskell REPL."
|
||||
(interactive "P")
|
||||
(if-let*
|
||||
((window
|
||||
(display-buffer
|
||||
(if (featurep! +intero)
|
||||
(intero-repl-buffer arg)
|
||||
(haskell-session-interactive-buffer (haskell-session))))))
|
||||
(window-buffer window)
|
||||
(error "Failed to display Haskell REPL")))
|
||||
41
.emacs.d/modules/lang/haskell/config.el
Normal file
41
.emacs.d/modules/lang/haskell/config.el
Normal file
@@ -0,0 +1,41 @@
|
||||
;;; lang/haskell/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
(after! projectile
|
||||
(add-to-list 'projectile-project-root-files "stack.yaml"))
|
||||
|
||||
;; TODO ghcide?
|
||||
(cond ((featurep! +intero) (load! "+intero")) ; DEPRECATED
|
||||
((featurep! +dante) (load! "+dante"))
|
||||
((featurep! +lsp) (load! "+lsp")))
|
||||
|
||||
|
||||
;;
|
||||
;; Common packages
|
||||
|
||||
(after! haskell-mode
|
||||
(setq haskell-process-suggest-remove-import-lines t ; warnings for redundant imports etc
|
||||
haskell-process-auto-import-loaded-modules t
|
||||
haskell-process-show-overlays (not (featurep! :tools flycheck))) ; redundant with flycheck
|
||||
|
||||
(set-lookup-handlers! 'haskell-mode
|
||||
:definition #'haskell-mode-jump-to-def-or-tag)
|
||||
(set-file-template! 'haskell-mode
|
||||
:trigger #'haskell-auto-insert-module-template
|
||||
:project t)
|
||||
(set-repl-handler!
|
||||
'(haskell-mode haskell-cabal-mode literate-haskell-mode)
|
||||
#'+haskell/open-repl :persist t)
|
||||
|
||||
(add-hook! 'haskell-mode-hook
|
||||
#'haskell-collapse-mode ; support folding haskell code blocks
|
||||
#'interactive-haskell-mode)
|
||||
|
||||
(add-to-list 'completion-ignored-extensions ".hi")
|
||||
|
||||
(map! :localleader
|
||||
:map haskell-mode-map
|
||||
;; this is set to use cabal for dante users and stack for intero users:
|
||||
"b" #'haskell-process-cabal-build
|
||||
"c" #'haskell-cabal-visit-file
|
||||
"h" #'haskell-hide-toggle
|
||||
"H" #'haskell-hide-toggle-all))
|
||||
18
.emacs.d/modules/lang/haskell/doctor.el
Normal file
18
.emacs.d/modules/lang/haskell/doctor.el
Normal file
@@ -0,0 +1,18 @@
|
||||
;; -*- lexical-binding: t; no-byte-compile: t; -*-
|
||||
;;; lang/haskell/doctor.el
|
||||
|
||||
(assert! (or (not (featurep! +lsp))
|
||||
(featurep! :tools lsp))
|
||||
"This module requires (:tools lsp)")
|
||||
|
||||
(when (featurep! +dante)
|
||||
(unless (executable-find "cabal")
|
||||
(warn! "Couldn't find cabal, haskell-mode may have issues")))
|
||||
|
||||
(when (featurep! +intero)
|
||||
(unless (executable-find "stack")
|
||||
(warn! "Couldn't find stack. Intero will not work")))
|
||||
|
||||
(when (or (featurep! +dante) (featurep! +intero))
|
||||
(unless (executable-find "hlint")
|
||||
(warn! "Couldn't find hlint. Flycheck may have issues in haskell-mode")))
|
||||
12
.emacs.d/modules/lang/haskell/packages.el
Normal file
12
.emacs.d/modules/lang/haskell/packages.el
Normal file
@@ -0,0 +1,12 @@
|
||||
;; -*- no-byte-compile: t; -*-
|
||||
;;; lang/haskell/packages.el
|
||||
|
||||
(package! haskell-mode)
|
||||
|
||||
(cond ((featurep! +dante)
|
||||
(package! dante)
|
||||
(package! attrap))
|
||||
((featurep! +lsp)
|
||||
(package! lsp-haskell))
|
||||
((featurep! +intero) ; DEPRECATED
|
||||
(package! intero)))
|
||||
Reference in New Issue
Block a user