#+TITLE: Spell Checking layer

#+TAGS: checker|layer

* Table of Contents                     :TOC_5_gh:noexport:
- [[#description][Description]]
  - [[#features][Features:]]
- [[#install][Install]]
  - [[#layer][Layer]]
  - [[#spell-checker-configuration][Spell Checker Configuration]]
  - [[#disabling-by-default][Disabling by default]]
  - [[#enabling-auto-dictionary-mode][Enabling auto-dictionary-mode]]
  - [[#enabling-multi-dictionary-support-with-hunspell][Enabling multi-dictionary support with hunspell]]
  - [[#enable-auto-completion-popup][Enable auto-completion popup]]
- [[#key-bindings][Key bindings]]
  - [[#spell-checking-transient-state][Spell Checking Transient-state]]
- [[#known-issues][Known issues]]

* Description
This layer provides spell checking capabilities to Spacemacs.

** Features:
- Buffer-wide spell checking via external command (ispell, hunspell, aspell) run through [[http://www-sop.inria.fr/members/Manuel.Serrano/flyspell/flyspell.html][Flyspell]].
- Spell as you type
- Optional correction popups, controlled by =enable-flyspell-auto-completion= variable.
- [[https://github.com/nschum/auto-dictionary-mode][Auto dictionary mode]] for some languages.

* Install
** Layer
To use this configuration layer, add it to your =~/.spacemacs=. You will need to
add =spell-checking= to the existing =dotspacemacs-configuration-layers= list in this
file.

** Spell Checker Configuration
The built-in Emacs variable that controls which external spell-checking program
is used is =ispell-program-name=, which can be set in your
=dotspacemacs/user-init= function if you do not like the default. It will give
priority to =aspell= if it is installed on your system. Another important
variable to be aware of is =ispell-dictionary= which will control the default
dictionary used by =ispell-program-name= (instead of using this variable you can
also use the key binding ~SPC S d~).

** Disabling by default
By default, =spell-checking= is enabled in all available major modes and may be
toggled off with ~SPC t S~. You can default this to off by setting the variable
=spell-checking-enable-by-default= to =nil=:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
    '((spell-checking :variables spell-checking-enable-by-default nil)))
#+END_SRC

** Enabling auto-dictionary-mode
=auto-dictionary-mode= tries to detect the current language from the buffer
content, and activate the corresponding dictionary. You can enable it by setting
the variable =spell-checking-enable-auto-dictionary= to something other than
=nil=:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
    '((spell-checking :variables spell-checking-enable-auto-dictionary t)))
#+END_SRC

Some people encountered bugs with =auto-dictionary-mode=, especially in *daemon
mode* where new =emacsclient= open directly freezed. If so, no other workaround
have been found yet than disabling =auto-dictionary-mode= completely.

Not all languages are supported by =auto-dictionary-mode=. The supported
languages are listed in the =adict-language-list= variable, that can be checked
with =spacemacs/describe-variable=. For convenience, here is the list of
currently supported language:

| Language          |
|-------------------|
| catalan           |
| classical greek   |
| danish            |
| english           |
| esperanto         |
| french            |
| german            |
| hindi             |
| hungarian         |
| modern greek      |
| norwegian bokmål  |
| norwegian nynorsk |
| portuguese        |
| romanian          |
| slovak            |
| slovene           |
| spanish           |
| swedish           |

** Enabling multi-dictionary support with hunspell
If your language is not supported by auto-dictionary feature or you author
multi-lingual documents you might be compelled to use hunspell's multi-dictionary
mode. For example to enable it for pl_PL and en_GB dictionaries you could put
following code in your dotspacemacs/user-config section in your configuration
file:

#+BEGIN_SRC emacs-lisp
  (with-eval-after-load "ispell"
      (setq ispell-program-name "hunspell")
      ;; ispell-set-spellchecker-params has to be called
      ;; before ispell-hunspell-add-multi-dic will work
      (ispell-set-spellchecker-params)
      (ispell-hunspell-add-multi-dic "pl_PL,en_GB")
      (setq ispell-dictionary "pl_PL,en_GB"))
#+END_SRC

One caveat is you need quite modern ispell.el for above to work. It's been
tested with version coming from Emacs 25.2 repository.

** Enable auto-completion popup
To enable auto-completion popup when the point is idle on a misspelled word
set the layer variable =enable-flyspell-auto-completion= to t:

#+BEGIN_SRC emacs-lisp
  (setq-default dotspacemacs-configuration-layers
    '((spell-checking :variables enable-flyspell-auto-completion t)))
#+END_SRC

* Key bindings

| Key binding     | Description                            |
|-----------------+----------------------------------------|
| ~SPC S a b~     | Add word to dict (buffer)              |
| ~SPC S a g~     | Add word to dict (global)              |
| ~SPC S a s~     | Add word to dict (session)             |
| ~SPC S b~       | Flyspell whole buffer                  |
| ~SPC S r~       | Flyspell region                        |
| ~SPC S c~       | Flyspell correct word before point     |
| ~SPC S s~       | Flyspell correct word at point         |
| ~SPC u SPC S c~ | Flyspell correct all errors one by one |
| ~SPC S d~       | Change dictionary                      |
| ~SPC S n~       | Flyspell goto next error               |
| ~SPC t S~       | Toggle flyspell                        |

** Spell Checking Transient-state

| Key binding | Description                                      |
|-------------+--------------------------------------------------|
| ~SPC S . b~ | Rerun spell check for the whole buffer           |
| ~SPC S . r~ | Rerun spell check for the selected region        |
| ~SPC S . d~ | Change dictionary                                |
| ~SPC S . n~ | Go to next spelling error                        |
| ~SPC S . c~ | Correct word before point                        |
| ~SPC S . s~ | Correct word at point                            |
| ~SPC S . t~ | Toggle spell check                               |
| ~SPC S . q~ | Quit transient state                             |
| ~SPC S . Q~ | Quit transient state and disable =flyspell-mode= |
| ~SPC S . B~ | Add word to dict (buffer)                        |
| ~SPC S . G~ | Add word to dict (global)                        |
| ~SPC S . S~ | Add word to dict (session)                       |

* Known issues
Vim-empty-lines layer seems incompatible with spell-checking inside org-mode. If
you experience "Args out of range" error message when invoking ~SPC S c~ inside
org-mode buffer then check if you don't have vim-empty-lines layer enabled and
disable it.
