jyp/dante

399

stars

456

commits

Emacs Lisp

primary language

Mar 11, 2026

updated

README

# -*- eval: (flyspell-mode 1); -*-

* Dante: Emacs mode for Interactive Haskell

[[https://gitter.im/dante-mode/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge][https://badges.gitter.im/dante-mode/Lobby.svg]]
[[https://melpa.org/#/dante][https://melpa.org/packages/dante-badge.svg]]
[[https://stable.melpa.org/#/dante][https://stable.melpa.org/packages/dante-badge.svg]]

Dante provides a frontend to GHCi features: type-checking, execution,
completion and cross referencing. It integrates with standard Emacs
tooling as much as possible.

** Feature summary and cheat-sheet 

| Feature                  | Mode/Command            | Keybinding |
|--------------------------+-------------------------+------------|
| On the fly type checking | ~flymake-mode~          |            |
| Completion               | ~company-mode~          |            |
| Type in echo area        | ~eldoc-mode~            |            |
| Goto definition          | ~xref-find-definitions~ | M-.        |
| Find uses                | ~xref-find-references~  | M-?        |
| Remote operation         | (automatic with tramp)  |            |
| Error correction         | ~attrap-attrap~         |            |
|--------------------------+-------------------------+------------|
| Type of selection        | ~dante-type-at~         | C-c .      |
| Info at point            | ~dante-info~            | C-c ,      |
| REPLoid                  | ~dante-eval-block~      | C-c "      |
| Restart                  | ~dante-restart~         |            |
| Diagnosis                | ~dante-diagnose~        |            |

*** REPLoid

You can evaluate code by writing it in a comment of the form
~-- >>>~ and run ~dante-eval-block~.

Example:

#+BEGIN_SRC Haskell

example :: [String]
example = ["This is an example", "of", "interactive", "evaluation"]

-- >>> intercalate " " example

#+END_SRC
In the above file, if you invoke ~dante-eval-block~ on the line
containing "intercalate", you'll get:

#+BEGIN_SRC haskell
-- >>> intercalate " " example
-- "This is an example of interactive evaluation"
--
#+END_SRC

Several commands in the same block will be executed in at once, so you
can have local let statements.

#+BEGIN_SRC haskell
-- >>> let foo = "foo"
--
-- >>> foo ++ "bar"
-- "foobar"
---
#+END_SRC

Any GHCi command can be put in such a block, but note however that:

1. The GHCi state will not be maintained across several calls to
   ~dante-eval-block~. In fact, Dante liberally executes ~:r~ and
   ~:l~, and (re)sets various GHCi options.

2. It is not supported to load and/or unload modules in such blocks,
   or set unexpected options. This may work, or may mess with Dante
   internals.

So if your goal is run your webserver/database/etc. within GHCi, you
should not do it using dante.

*** Completion
Completion works only when the current file can be loaded by GHCi
(ie. is free of errors). So, this is not /very/ useful. To mitigate
the problem, Dante defers type-errors to runtime when loading.

*** Remote operation
When loading a remote ([[https://www.gnu.org/software/tramp/#Overview][Tramp]]) path, GHCi will be run on the remote host,
automatically.

However, if programs such as ~nix-shell~ are not found on the remote host, you
may need to adjust the tramp path. For example:
#+BEGIN_SRC elisp
(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
#+END_SRC
*** Error correction
Error correction is implemented in the sister package [[https://github.com/jyp/attrap][attrap]].

*** Using ~hlint~

Dante is a GHCi interaction mode. Therefore it does not provide any
support for hlint. However, you can use a third party support for
hlint in addition to Dante. In fact [[https://github.com/jyp/attrap][attrap]] even provides support for
interactive application of hints. See that package documentation for
configuration.

** Installation

Dante can be installed by any usual means. (Use-package is a pretty popular option)

** Configuration
*** Eldoc

Dante has builtin [[https://www.emacswiki.org/emacs/ElDoc][Eldoc]] support (showing info about the symbol at
point in the echo area when idle.) Unfortunately, at the time of
writing (Oct 2022), the standard Haskell mode uses the old eldoc API,
overriding Dante's Eldoc support. I recommend just disabling the
standard Haskell mode Eldoc support, which IMO isn't very helpful
anyway, like so:

#+begin_src elisp
  (add-hook 'haskell-mode-hook
            (defun my-fix-hs-eldoc ()
              (setq eldoc-documentation-strategy #'eldoc-documentation-default)))
#+end_src

*** Configuring the GHCi loading method
Configuration can be important to make sure that GHCi is properly
loaded by dante.  Even though Dante will do its best to figure out the
proper way to load GHCi for your project, it may still fail.  You can
guide Dante's behavior by customizing variables. Note in particular
that customization can be done on a per-file, per-package or
per-project basis by using [[https://www.gnu.org/software/emacs/manual/html_node/emacs/File-Variables.html#File-Variables][file-]] and [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html][directory-local]] variables (as
recommended above).

In fact typical way to configure GHCi command line is to a add a
~.dir-locals.el~ file to your project root which sets the loading
method. The loading method is a recipe to find out the root of the
project and the command line to use to start GHCi.

#+BEGIN_SRC elisp
((nil . ((dante-methods . (new-impure-nix)))))
#+END_SRC

Replace ~new-impure-nix~ with the proper value, which you can figure
out by ~M-x describe-variable <RET> dante-methods-alist~.

*** Configuring the Cabal target

For a multi-target project, it can be necessary to tell dante which
[[https://cabal.readthedocs.io/en/3.4/cabal-commands.html#cabal-v2-build][target]] to pass to the ~cabal repl~ or ~stack~ command. The best method
is to create another ~.dir-locals.el~ file in the top-level directory
of the sources of the target in question. For instance, if a ~sil-parser-test~
executable resides in ~stand-in-language/test/~, you can create the
following file in that directory:

#+begin_src elisp
((nil . ((dante-target . "sil:sil-parser-test"))))
#+end_src

When using ~stack~ and a test suite, the following configuration in
the test source directory will cause the ~--test~ flag to be passed
when loading the files there:

#+begin_src elisp
((nil . ((dante-target . "--test"))))
#+end_src

*** More control over the GHCi command line
For more direct control over the command line, you can set
~dante-repl-command-line~ directly. If Dante additionally fails to
find the project root using any of the ~dante-methods~, configure
~dante-project-root~ explicitly.  (Do it using ~dir-locals.el~.)

*** Example full configuration

#+BEGIN_SRC elisp
  (use-package dante
    :ensure t ; ask use-package to install the package
    :after haskell-mode
    :commands 'dante-mode
    :init
    ;; flycheck backend deprecated October 2022
    ;; (add-hook 'haskell-mode-hook 'flycheck-mode)

    (add-hook 'haskell-mode-hook 'flymake-mode)
    (remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake)
    (add-hook 'haskell-mode-hook 'dante-mode)
    (add-hook 'haskell-mode-hook
              (defun my-fix-hs-eldoc ()
                (setq eldoc-documentation-strategy #'eldoc-documentation-default)))
    :config
    (require 'flymake-flycheck)
    (defalias 'flymake-hlint
      (flymake-flycheck-diagnostic-function-for 'haskell-hlint))
    (add-to-list 'flymake-diagnostic-functions 'flymake-hlint)
    ;; flycheck backend deprecated October 2022
    ;; (flycheck-add-next-checker 'haskell-dante '(info . haskell-hlint)))
#+END_SRC

** Troubleshooting

If ~dante-type-at~ gives ~Couldn't guess that module name. Does it
exist?~ or ~xref-find-definitions~ gives ~No definitions found for:
"/tmp/danteTqJJvj.hs" ~, you may need to add your targets to
~.dir-locals.el~; see the Configuration section above.

Finally, Use ~M-x customize-group dante~ to read the documentation for
all customizable variables.

** In the "press"
- [[http://h2.jaguarpaw.co.uk/posts/how-i-use-dante/][How I use dante]]

Not written in Markdown, so it's shown here as plain text — view it formatted on GitHub.

Contributors

jyp

408 commits

purcell

9 commits

drvink

5 commits

sergv

4 commits

jyp/dante

399

stars

456

commits

Emacs Lisp

primary language

Mar 11, 2026

updated

README

# -*- eval: (flyspell-mode 1); -*-

* Dante: Emacs mode for Interactive Haskell

[[https://gitter.im/dante-mode/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge][https://badges.gitter.im/dante-mode/Lobby.svg]]
[[https://melpa.org/#/dante][https://melpa.org/packages/dante-badge.svg]]
[[https://stable.melpa.org/#/dante][https://stable.melpa.org/packages/dante-badge.svg]]

Dante provides a frontend to GHCi features: type-checking, execution,
completion and cross referencing. It integrates with standard Emacs
tooling as much as possible.

** Feature summary and cheat-sheet 

| Feature                  | Mode/Command            | Keybinding |
|--------------------------+-------------------------+------------|
| On the fly type checking | ~flymake-mode~          |            |
| Completion               | ~company-mode~          |            |
| Type in echo area        | ~eldoc-mode~            |            |
| Goto definition          | ~xref-find-definitions~ | M-.        |
| Find uses                | ~xref-find-references~  | M-?        |
| Remote operation         | (automatic with tramp)  |            |
| Error correction         | ~attrap-attrap~         |            |
|--------------------------+-------------------------+------------|
| Type of selection        | ~dante-type-at~         | C-c .      |
| Info at point            | ~dante-info~            | C-c ,      |
| REPLoid                  | ~dante-eval-block~      | C-c "      |
| Restart                  | ~dante-restart~         |            |
| Diagnosis                | ~dante-diagnose~        |            |

*** REPLoid

You can evaluate code by writing it in a comment of the form
~-- >>>~ and run ~dante-eval-block~.

Example:

#+BEGIN_SRC Haskell

example :: [String]
example = ["This is an example", "of", "interactive", "evaluation"]

-- >>> intercalate " " example

#+END_SRC
In the above file, if you invoke ~dante-eval-block~ on the line
containing "intercalate", you'll get:

#+BEGIN_SRC haskell
-- >>> intercalate " " example
-- "This is an example of interactive evaluation"
--
#+END_SRC

Several commands in the same block will be executed in at once, so you
can have local let statements.

#+BEGIN_SRC haskell
-- >>> let foo = "foo"
--
-- >>> foo ++ "bar"
-- "foobar"
---
#+END_SRC

Any GHCi command can be put in such a block, but note however that:

1. The GHCi state will not be maintained across several calls to
   ~dante-eval-block~. In fact, Dante liberally executes ~:r~ and
   ~:l~, and (re)sets various GHCi options.

2. It is not supported to load and/or unload modules in such blocks,
   or set unexpected options. This may work, or may mess with Dante
   internals.

So if your goal is run your webserver/database/etc. within GHCi, you
should not do it using dante.

*** Completion
Completion works only when the current file can be loaded by GHCi
(ie. is free of errors). So, this is not /very/ useful. To mitigate
the problem, Dante defers type-errors to runtime when loading.

*** Remote operation
When loading a remote ([[https://www.gnu.org/software/tramp/#Overview][Tramp]]) path, GHCi will be run on the remote host,
automatically.

However, if programs such as ~nix-shell~ are not found on the remote host, you
may need to adjust the tramp path. For example:
#+BEGIN_SRC elisp
(add-to-list 'tramp-remote-path 'tramp-own-remote-path)
#+END_SRC
*** Error correction
Error correction is implemented in the sister package [[https://github.com/jyp/attrap][attrap]].

*** Using ~hlint~

Dante is a GHCi interaction mode. Therefore it does not provide any
support for hlint. However, you can use a third party support for
hlint in addition to Dante. In fact [[https://github.com/jyp/attrap][attrap]] even provides support for
interactive application of hints. See that package documentation for
configuration.

** Installation

Dante can be installed by any usual means. (Use-package is a pretty popular option)

** Configuration
*** Eldoc

Dante has builtin [[https://www.emacswiki.org/emacs/ElDoc][Eldoc]] support (showing info about the symbol at
point in the echo area when idle.) Unfortunately, at the time of
writing (Oct 2022), the standard Haskell mode uses the old eldoc API,
overriding Dante's Eldoc support. I recommend just disabling the
standard Haskell mode Eldoc support, which IMO isn't very helpful
anyway, like so:

#+begin_src elisp
  (add-hook 'haskell-mode-hook
            (defun my-fix-hs-eldoc ()
              (setq eldoc-documentation-strategy #'eldoc-documentation-default)))
#+end_src

*** Configuring the GHCi loading method
Configuration can be important to make sure that GHCi is properly
loaded by dante.  Even though Dante will do its best to figure out the
proper way to load GHCi for your project, it may still fail.  You can
guide Dante's behavior by customizing variables. Note in particular
that customization can be done on a per-file, per-package or
per-project basis by using [[https://www.gnu.org/software/emacs/manual/html_node/emacs/File-Variables.html#File-Variables][file-]] and [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html][directory-local]] variables (as
recommended above).

In fact typical way to configure GHCi command line is to a add a
~.dir-locals.el~ file to your project root which sets the loading
method. The loading method is a recipe to find out the root of the
project and the command line to use to start GHCi.

#+BEGIN_SRC elisp
((nil . ((dante-methods . (new-impure-nix)))))
#+END_SRC

Replace ~new-impure-nix~ with the proper value, which you can figure
out by ~M-x describe-variable <RET> dante-methods-alist~.

*** Configuring the Cabal target

For a multi-target project, it can be necessary to tell dante which
[[https://cabal.readthedocs.io/en/3.4/cabal-commands.html#cabal-v2-build][target]] to pass to the ~cabal repl~ or ~stack~ command. The best method
is to create another ~.dir-locals.el~ file in the top-level directory
of the sources of the target in question. For instance, if a ~sil-parser-test~
executable resides in ~stand-in-language/test/~, you can create the
following file in that directory:

#+begin_src elisp
((nil . ((dante-target . "sil:sil-parser-test"))))
#+end_src

When using ~stack~ and a test suite, the following configuration in
the test source directory will cause the ~--test~ flag to be passed
when loading the files there:

#+begin_src elisp
((nil . ((dante-target . "--test"))))
#+end_src

*** More control over the GHCi command line
For more direct control over the command line, you can set
~dante-repl-command-line~ directly. If Dante additionally fails to
find the project root using any of the ~dante-methods~, configure
~dante-project-root~ explicitly.  (Do it using ~dir-locals.el~.)

*** Example full configuration

#+BEGIN_SRC elisp
  (use-package dante
    :ensure t ; ask use-package to install the package
    :after haskell-mode
    :commands 'dante-mode
    :init
    ;; flycheck backend deprecated October 2022
    ;; (add-hook 'haskell-mode-hook 'flycheck-mode)

    (add-hook 'haskell-mode-hook 'flymake-mode)
    (remove-hook 'flymake-diagnostic-functions 'flymake-proc-legacy-flymake)
    (add-hook 'haskell-mode-hook 'dante-mode)
    (add-hook 'haskell-mode-hook
              (defun my-fix-hs-eldoc ()
                (setq eldoc-documentation-strategy #'eldoc-documentation-default)))
    :config
    (require 'flymake-flycheck)
    (defalias 'flymake-hlint
      (flymake-flycheck-diagnostic-function-for 'haskell-hlint))
    (add-to-list 'flymake-diagnostic-functions 'flymake-hlint)
    ;; flycheck backend deprecated October 2022
    ;; (flycheck-add-next-checker 'haskell-dante '(info . haskell-hlint)))
#+END_SRC

** Troubleshooting

If ~dante-type-at~ gives ~Couldn't guess that module name. Does it
exist?~ or ~xref-find-definitions~ gives ~No definitions found for:
"/tmp/danteTqJJvj.hs" ~, you may need to add your targets to
~.dir-locals.el~; see the Configuration section above.

Finally, Use ~M-x customize-group dante~ to read the documentation for
all customizable variables.

** In the "press"
- [[http://h2.jaguarpaw.co.uk/posts/how-i-use-dante/][How I use dante]]

Not written in Markdown, so it's shown here as plain text — view it formatted on GitHub.

Contributors

jyp

408 commits

purcell

9 commits

drvink

5 commits

sergv

4 commits

Languages

Emacs Lisp

100.0%