Moving to Doom Emacs!

This commit is contained in:
Derek Taylor
2019-12-16 20:21:19 -06:00
parent d9f2f456f1
commit d4b4c33550
683 changed files with 51877 additions and 100 deletions

View 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))

View 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))

View 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))

View 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]].

View 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")))

View 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))

View 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")))

View 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)))