flyspell-correct icon indicating copy to clipboard operation
flyspell-correct copied to clipboard

Distraction-free words correction with flyspell via selected interface.

:PROPERTIES: :ID: 17829216-93a9-4f5d-b297-a903ef9ad647 :END: #+begin_html

Banner

#+end_html
  • flyspell-correct :PROPERTIES: :ID: 11b3a67e-c4af-42fd-93d8-d04e8cd4f899 :END:

[[https://github.com/d12frosted/flyspell-correct/workflows/CI/badge.svg][file:https://github.com/d12frosted/flyspell-correct/workflows/CI/badge.svg]]

| =flyspell-correct= | [[http://melpa.org/#/flyspell-correct][file:http://melpa.org/packages/flyspell-correct-badge.svg]] | [[https://stable.melpa.org/#/flyspell-correct][file:https://stable.melpa.org/packages/flyspell-correct-badge.svg]] | | =flyspell-correct-ivy= | [[http://melpa.org/#/flyspell-correct-ivy][file:http://melpa.org/packages/flyspell-correct-ivy-badge.svg]] | [[https://stable.melpa.org/#/flyspell-correct-ivy][file:https://stable.melpa.org/packages/flyspell-correct-ivy-badge.svg]] | | =flyspell-correct-helm= | [[http://melpa.org/#/flyspell-correct-helm][file:http://melpa.org/packages/flyspell-correct-helm-badge.svg]] | [[https://stable.melpa.org/#/flyspell-correct-helm][file:https://stable.melpa.org/packages/flyspell-correct-helm-badge.svg]] | | =flyspell-correct-popup= | [[http://melpa.org/#/flyspell-correct-popup][file:http://melpa.org/packages/flyspell-correct-popup-badge.svg]] | [[https://stable.melpa.org/#/flyspell-correct-popup][file:https://stable.melpa.org/packages/flyspell-correct-popup-badge.svg]] | | =flyspell-correct-avy-menu= | [[http://melpa.org/#/flyspell-correct-popup][file:http://melpa.org/packages/flyspell-correct-avy-menu-badge.svg]] | [[https://stable.melpa.org/#/flyspell-correct-popup][file:https://stable.melpa.org/packages/flyspell-correct-avy-menu-badge.svg]] |

Correcting misspelled words with flyspell using favourite interface.

=flyspell-correct= provides several functions to start the correction process:

  • =flyspell-correct-wrapper= - by default jumps to the first misspelled word before the point and prompts for correction and gets you back. Calling it with =C-u= gives ability to correct [[multiple misspelled words][multiple misspelled words]] in one run. =C-u C-u= changes direction. =C-u C-u C-u= changes direction and enables multiple corrections.
  • =flyspell-correct-at-point= - to correct word at point.
  • =flyspell-correct-previous= to correct any visible word before the point.
  • =flyspell-correct-next= to correct any visible word after the point.

In most cases =flyspell-correct-wrapper= is the most convenient, so don't forget to bind it.

#+BEGIN_SRC emacs-lisp (define-key flyspell-mode-map (kbd "C-;") #'flyspell-correct-wrapper) #+END_SRC

Most interfaces also allow you to save the new word to your dictionary, accept this spelling in current buffer or for a whole session, or even skip this word (useful in a rapid flow).

=flyspell-correct= comes with default interface, which uses =completing-read=. If you use Ivy, Helm or Ido as completion system you probably want to replace the default interface with the specialized interface. All additional interfaces come in separate packages:

  • [[#flyspell-correct-ivy-interface][flyspell-correct-ivy]]
  • [[#flyspell-correct-avy-menu-interface][flyspell-correct-avy-menu]]
  • [[#flyspell-correct-helm-interface][flyspell-correct-helm]]
  • [[#flyspell-correct-popup-interface][flyspell-correct-popup]]

** Table of contents :TOC: :PROPERTIES: :ID: e04b1e8e-7d48-486e-a292-b550f34b33c2 :END:

  • [[#flyspell-correct][flyspell-correct]]
    • [[#rapid-mode][Rapid mode]]
    • [[#flyspell-correct-completing-read-interface][=flyspell-correct-completing-read= interface]]
    • [[#flyspell-correct-ivy-interface][=flyspell-correct-ivy= interface]]
    • [[#flyspell-correct-avy-menu-interface][=flyspell-correct-avy-menu= interface]]
    • [[#flyspell-correct-ido-interface][=flyspell-correct-ido= interface]]
    • [[#flyspell-correct-helm-interface][=flyspell-correct-helm= interface]]
    • [[#flyspell-correct-popup-interface][=flyspell-correct-popup= interface]]
  • [[#deprecations][Deprecations]]
    • [[#deprecations-in-v05][Deprecations in =v0.5=]]
  • [[#custom-interfaces][Custom interfaces]]
  • [[#highlighting][Highlighting]]
  • [[#auto-correction-mode][Auto correction mode]]
  • [[#reasoning][Reasoning]]
  • [[#screenshots][Screenshots]]
    • [[#ivy-interface][Ivy interface]]
    • [[#avy-menu-interface][Avy Menu interface]]
    • [[#popup-interface][Popup interface]]
    • [[#helm-interface][Helm interface]]
    • [[#ido-interface][Ido interface]]
    • [[#completing-read-interface][completing-read interface]]
  • [[#acknowledgements][Acknowledgements]]

** Rapid mode :PROPERTIES: :ID: 25719606-9996-4056-9049-18F73A609FF6 :END:

A so called 'rapid mode' means that you can correct multiple words in a single invocation of =flyspell-correct-wrapper= following current direction (usually, backwards). In order to enable it, one should call =flyspell-correct-wrapper= with universal argument - =C-u=. For example, =C-u C-;= will enable it.

** =flyspell-correct-completing-read= interface :PROPERTIES: :ID: 3aaedcac-ef83-441c-9dcc-24b567f8b400 :END:

In order to use =flyspell-correct-completing-read= interface you have to install =flyspell-correct= package in any preferred way and then add following snippet to relevant part of your =init.el= file.

#+BEGIN_SRC emacs-lisp (require 'flyspell-correct) (define-key flyspell-mode-map (kbd "C-;") 'flyspell-correct-wrapper) #+END_SRC

Or via =use-package=.

#+BEGIN_SRC emacs-lisp (use-package flyspell-correct :after flyspell :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))) #+END_SRC

If you do not want any binding, just replace =:bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))= with =:defer t= to use lazy loading.

In order to select the (s)ave, (a)ccept, sto(p) or s(k)ip actions, you can enter the shortcut key =@s=, =@a=, =@p= or =@k=. The actions will be automatically submitted. Furthermore suggestions can be quickly submitted by entering the numeric index in front of the suggestion. Besides the quick keys the usual ~completing-read~ interface is available, which may be enhanced and allow scrolling through candidates if you have a completion UI like [[https://github.com/oantolin/icomplete-vertical][Icomplete-vertical]], [[https://github.com/raxod502/selectrum][Selectrum]] or [[https://github.com/minad/vertico][Vertico]] installed.

** =flyspell-correct-ivy= interface :PROPERTIES: :ID: 5fc08aaa-02ac-48ac-9e7d-ca94e9abeb61 :END:

In order to use =flyspell-correct-ivy= interface you have to install =flyspell-correct-ivy= package in any preferred way and then add following snippet to relevant part of your =init.el= file.

#+BEGIN_SRC emacs-lisp (require 'flyspell-correct-ivy) (define-key flyspell-mode-map (kbd "C-;") 'flyspell-correct-wrapper) #+END_SRC

Or via =use-package=.

#+BEGIN_SRC emacs-lisp (use-package flyspell-correct :after flyspell :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)))

(use-package flyspell-correct-ivy :after flyspell-correct) #+END_SRC

If you do not want any binding, just replace =:bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))= with =:defer t= to use lazy loading.

Note that in order to access actions in =ivy= interface you need to press ~M-o~. More on =ivy= mini buffer key bindings you can read in [[http://oremacs.com/swiper/#key-bindings-for-single-selection-action-then-exit-minibuffer][official documentation]].

** =flyspell-correct-avy-menu= interface :PROPERTIES: :ID: 494754cd-9399-45ad-8c01-6fc616971911 :END:

In order to use =flyspell-correct-avy-menu= interface you have to install =flyspell-correct-avy-menu= package in any preferred way and then add following snippet to relevant part of your =init.el= file.

#+BEGIN_SRC emacs-lisp (require 'flyspell-correct-avy-menu) (define-key flyspell-mode-map (kbd "C-;") 'flyspell-correct-wrapper) #+END_SRC

Or via =use-package=.

#+BEGIN_SRC emacs-lisp (use-package flyspell-correct :after flyspell :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)))

(use-package flyspell-correct-avy-menu :after flyspell-correct) #+END_SRC

If you do not want any binding, just replace =:bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))= with =:defer t= to use lazy loading.

** =flyspell-correct-ido= interface :PROPERTIES: :ID: bd55cb14-df6c-485f-afd8-dabf390abe43 :END:

In order to use =flyspell-correct= interface you have to install =flyspell-correct-ido= package in any preferred way and then add following snippet to relevant part of your =init.el= file.

#+BEGIN_SRC emacs-lisp (require 'flyspell-correct) (require 'flyspell-correct-ido) (define-key flyspell-mode-map (kbd "C-;") 'flyspell-correct-wrapper) #+END_SRC

Or via =use-package=.

#+BEGIN_SRC emacs-lisp (use-package flyspell-correct :after flyspell :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)))

(use-package flyspell-correct-ido :after flyspell-correct) #+END_SRC

If you do not want any binding, just replace =:bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))= with =:defer t= to use lazy loading.

** =flyspell-correct-helm= interface :PROPERTIES: :ID: eb456982-b9a3-4c47-a6b9-9ff913d30951 :END:

In order to use =flyspell-correct-helm= interface you have to install =flyspell-correct-helm= package in any preferred way and then add following snippet to relevant part of your =init.el= file.

#+BEGIN_SRC emacs-lisp (require 'flyspell-correct-helm) (define-key flyspell-mode-map (kbd "C-;") 'flyspell-correct-wrapper) #+END_SRC

Or via =use-package=.

#+BEGIN_SRC emacs-lisp (use-package flyspell-correct :after flyspell :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)))

(use-package flyspell-correct-helm :after flyspell-correct) #+END_SRC

If you do not want any binding, just replace =:bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))= with =:defer t= to use lazy loading.

** =flyspell-correct-popup= interface :PROPERTIES: :ID: 6275479b-a569-4689-b51d-326aff000c1a :END:

In order to use =flyspell-correct-popup= interface you have to install =flyspell-correct-popup= package in any preferred way and then add following snippet to relevant part of your =init.el= file.

#+BEGIN_SRC emacs-lisp (require 'flyspell-correct-popup) (define-key flyspell-mode-map (kbd "C-;") 'flyspell-correct-wrapper) #+END_SRC

Or via =use-package=.

#+BEGIN_SRC emacs-lisp (use-package flyspell-correct :after flyspell :bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)))

(use-package flyspell-correct-popup :after flyspell-correct) #+END_SRC

If you do not want any binding, just replace =:bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper))= with =:defer t= to use lazy loading.

There are some cool usability suggestions by @alphapapa shared in [[https://github.com/d12frosted/flyspell-correct/issues/30][d12frosted/flyspell-correct#30]] that you might want to use. Enjoy!

  • Deprecations :PROPERTIES: :ID: aa3ca72d-cf45-4c9c-93cd-c3ef1fc2e1e2 :END: ** Deprecations in =v0.5= :PROPERTIES: :ID: 8c3332b9-555d-477c-9700-36c9f65dfbdd :END:

Unfortunately, the following functions are renamed.

  • =flyspell-correct-next-word-generic= -> =flyspell-correct-next=
  • =flyspell-correct-previous-word-generic= -> =flyspell-correct-previous=
  • =flyspell-correct-word-generic= -> =flyspell-correct-at-point=

Please make sure to update to new names.

  • Custom interfaces :PROPERTIES: :ID: 58868d20-024a-45b4-a919-f82329c6ee22 :END:

One can easily implement custom interface for =flyspell-correct=. It has to be a function accepting two arguments:

  • candidates for correction (list of strings)
  • misspelled word (string)

Result must be either a string (replacement word) or a cons of a command and a string (replacement word), where the command is one of the following:

  • skip - do nothing to misspelled word, in rapid mode used for jumping to the next (or previous) misspelled word
  • break - do nothing to misspelled word, break from rapid mode
  • stop - do nothing to misspelled word, break from rapid mode (if enabled) and leave the point at the misspelled word
  • save - replace misspelled word with replacement word and save it to the personal dictionary
  • session - replace misspelled word with replacement word and save it to the session dictionary (correction will be discarded upon quitting Emacs)
  • buffer - replace misspelled word with replacement word and save it to the buffer dictionary (added to the bottom of buffer)

Check any existing interface for reference.

  • Highlighting :PROPERTIES: :ID: 414a109d-8553-4d36-96ee-55c664810363 :END:

The word that is being currently corrected (e.g. you are selecting the correction for misspelled word) is highlighted with =flyspell-correct-highlight-face=. If you wish to disable extra highlighting, just set the value of =flyspell-correct-highlight= to =nil=.

#+begin_src emacs-lisp (setq flyspell-correct-highlight nil) #+end_src

  • Auto correction mode :PROPERTIES: :ID: 399a433a-d8db-4731-a62e-f829bf6dc544 :END:

/Take my advice and don't use this functionality unless you find =flyspell-correct-wrapper= function useless for your purposes. You can find more info in [[https://github.com/syl20bnr/spacemacs/issues/6209#issuecomment-274320376][this comment]].

This package also provides auto correction minor mode called =flyspell-correct-auto-mode=. When enabled it will automatically invoke =flyspell-correct-previous-word-generic= after certain delay configured by =flyspell-correct-auto-delay= when there is at least one incorrect word.

#+BEGIN_SRC (add-hook 'flyspell-mode-hook #'flyspell-correct-auto-mode) #+END_SRC

One can also configure interface specially for =flyspell-correct-previous-word-generic= called by =flyspell-correct-auto-mode= by setting value of =flyspell-correct-auto-mode-interface=.

  • Reasoning :PROPERTIES: :ID: 89d09c0e-562b-48ca-9ad0-85d9834eee6d :END:

There are already packages like =helm-flyspell= and =flyspell-popup=. So why would anyone create yet another similar package? The reason is simple - to support another interface or completion system. =flyspell-correct= started because =ivy= was missing similar to =helm-flyspell= package. But I didn't want to create a package just for =ivy=. The reasoning is simple - all those packages should have similar functionality but different interface. Adding something new to one of these packages ideally should be reflected in all others. So I decided to create generic package that works with any interfaces. It's not about one package containing all possible interfaces, but about a package giving you functionality with an interface of your choice.

And over the time, =flyspell-correct= got some killer features (like quick access to misspelled words from anywhere), rapid mode and some others.

  • Screenshots :PROPERTIES: :ID: 0ad131f7-f943-4e41-a78d-87068fdb04bd :END:

** Ivy interface :PROPERTIES: :ID: 4680e827-475a-4686-81d3-885fd1cf92f6 :END:

[[file:images/screenshot-ivy-1.png]]

[[file:images/screenshot-ivy-2.png]]

** Avy Menu interface :PROPERTIES: :ID: d9f7b9c4-b262-4ba4-bfc3-f3fe4e6db906 :END:

[[file:images/screenshot-avy-menu.png]]

** Popup interface :PROPERTIES: :ID: 0125c2f1-cc51-4405-8d8e-e077d443a9ff :END:

[[file:images/screenshot-popup.png]]

** Helm interface :PROPERTIES: :ID: 4a072429-6425-455e-af7a-ddb428b60d9c :END:

[[file:images/screenshot-helm.png]]

** Ido interface :PROPERTIES: :ID: 2cb846b9-f962-46fc-9648-e9a5a8970b21 :END:

[[file:images/screenshot-ido.png]]

** completing-read interface :PROPERTIES: :ID: c5283357-0209-409c-bd7b-053f17d4ced3 :END:

[[file:images/screenshot-completing-read.png]]

  • Acknowledgements :PROPERTIES: :ID: be7625b9-b782-4e5f-962c-bd181c3933a7 :END:

This package is available thanks to these people:

  • [[https://github.com/pronobis][Andrzej Pronobis]] for inspiration and [[https://github.com/pronobis/helm-flyspell][helm-flyspell]]
  • [[https://github.com/xuchunyang][xuchunyang]] for [[https://github.com/xuchunyang/flyspell-popup][flyspell-popup]]
  • [[https://github.com/abo-abo][Oleh Krehel]] for [[https://github.com/abo-abo/swiper][swiper]] and all the help

Additional thanks to all contributors:

  • [[https://github.com/gusbrs][gusbrs]]
  • [[https://github.com/Boruch-Baum][Boruch Baum]]
  • [[https://github.com/mrBliss][Thomas Winant]]
  • [[https://github.com/clemera][Clemens Radermacher]]
  • [[https://github.com/Ergus][Jimmy Aguilar Mena]]
  • [[https://github.com/vermiculus][Sean Allred]]
  • [[https://github.com/syohex][Syohei YOSHIDA]]
  • [[https://github.com/blue0513][Taiju Aoki]]
  • [[https://github.com/DamienCassou][Damien Cassou]]
  • [[https://github.com/hubisan][Daniel Hubmann]]
  • [[https://github.com/manuel-uberti][Manuel Uberti]]
  • [[https://github.com/jpkotta][Jonathan Kotta]]
  • [[https://github.com/tpadioleau][Thomas Padioleau]]
  • [[https://github.com/gusbrs][Gustavo Barros]]
  • [[https://github.com/minad][Daniel Mendler]]