minad / jinx

🪄 Enchanted Spell Checker
GNU General Public License v3.0
436 stars 23 forks source link

+title: jinx.el - Enchanted Spell Checker

+author: Daniel Mendler

+language: en

+export_file_name: jinx.texi

+texinfo_dir_category: Emacs misc features

+texinfo_dir_title: Jinx: (jinx).

+texinfo_dir_desc: Enchanted Spell Checker

+html: GNU Emacs

+html: GNU ELPA

+html: GNU-devel ELPA

+html: MELPA

+html: MELPA Stable

Jinx is a fast just-in-time spell-checker for Emacs. Jinx highlights misspelled words in the text of the visible portion of the buffer. For efficiency, Jinx highlights misspellings lazily, recognizes window boundaries and text folding, if any. For example, when unfolding or scrolling, only the newly visible part of the text is checked if it has not been checked before. Each misspelling can be corrected from a list of dictionary words presented as a completion menu.

Installing Jinx is straight-forward and configuring should not need much intervention. Jinx can be used completely on its own, but can also safely co-exist with Emacs's built-in spell-checker Ispell.

Jinx's high performance and low resource usage comes from directly calling the widely-used API of the [[https://rrthomas.github.io/enchant/][Enchant library]]. Jinx automatically compiles =jinx-mod.c= and loads the dynamic module at startup. By binding directly to the native Enchant API, Jinx avoids the slower backend process communication with Aspell. Enchant is widely used by other text editors and supports [[https://nuspell.github.io/][Nuspell]], [[http://hunspell.github.io/][Hunspell]], [[http://aspell.net/][Aspell]] and a few language-specific backends.

Jinx supports spell-checking multiple languages in the same buffer. See the =jinx-languages= variable to customize for multiple languages. Jinx can flexibly ignore misspellings via faces (=jinx-exclude-faces= and =jinx-include-faces=), regular expressions (=jinx-exclude-regexps=), and programmable predicates. Jinx comes preconfigured for the most important Emacs major modes. Modes like Java, Ruby or Rust are listed in =jinx-camel-modes=. For these modes composite words in =camelCase= and =PascalCase= are accepted.

+html:

Jinx can be installed from GNU ELPA or MELPA directly with =package-install=.

Most importantly your Emacs must be compiled with dynamic module support. Jinx requires =libenchant=, which is needed to compile the native module at install time. If =pkgconf= or =pkg-config= is available, Jinx will use it to locate =libenchant= during installation. Depending on your BSD or Linux distribution you have to install different packages:

On Windows the installation of the native module may require manual intervention.

Jinx has two modes: the command, =global-jinx-mode= activates globally; and the command, =jinx-mode=, for activating for specific modes.

+begin_src emacs-lisp

;; Alternative 1: Enable Jinx globally (add-hook 'emacs-startup-hook #'global-jinx-mode)

;; Alternative 2: Enable Jinx per mode (dolist (hook '(text-mode-hook prog-mode-hook conf-mode-hook)) (add-hook hook #'jinx-mode))

+end_src

The commands =jinx-correct= and =jinx-languages= are marked as autoloads. Invoking =jinx-correct= corrects the misspellings. Binding =jinx-correct= to =M-$= takes over that key from the default assignment to =ispell-word=. Since Jinx is independent of the Ispell package, =M-$= can be re-used.

+begin_src emacs-lisp

(keymap-global-set "M-$" #'jinx-correct) (keymap-global-set "C-M-$" #'jinx-languages)

+end_src

A sample configuration with the popular =use-package= macro is shown here:

+begin_src emacs-lisp

(use-package jinx :hook (emacs-startup . global-jinx-mode) :bind (("M-$" . jinx-correct) ("C-M-$" . jinx-languages)))

+end_src

See also the [[https://github.com/minad/jinx/wiki][Jinx Wiki]] for additional configuration tips. The wiki documents configurations to save misspellings as global abbreviations and support for Ispell =LocalWords=.

The easiest way to correct a misspelling is to right click on the word, underlined with a wavy line. Then a context menu will open where you can select from suggestions.

If you prefer to use the keyboard, invoke the command =jinx-correct=. The recommended binding is =M-$=, see the configuration section. Suggested corrections will be displayed as a completion menu. You can press the displayed digit keys to quickly select a suggestion. Furthermore the menu offers options to save the word temporarily for the current session, in the personal dictionary or in the file-local variables.

You can enter arbitrary input at the correction prompt in order to make the correction or to store a modified word in the personal dictionary. For example if you typed =alotriomorpc=, the prompt offers you the option =@alotriomorpc= which would add this word to your personal dictionary upon selection. You can then correct the option to =@allotriomorphic= and add it to the dictionary.

While inside the =jinx-correct= prompt, the keys =M-n= and =M-p= are bound to =jinx-next= and =jinx-previous= respectively and allow you to move the next and previous misspelled word.

The completion menu is compatible with all popular completion UIs: Vertico, Mct, Icomplete, Ivy, Helm and the default completions buffer. In case you use Vertico I suggest that you tweak the completion display via =vertico-multiform-mode= for the completion category =jinx=. You can for example use the grid display such that more suggestions fit on the screen and enable annotations.

+begin_src emacs-lisp

(add-to-list 'vertico-multiform-categories '(jinx grid (vertico-grid-annotate . 20))) (vertico-multiform-mode 1)

+end_src

When correcting a word with =jinx-correct=, the movement commands =jinx-next= and =jinx-previous= are available on the keys =M-n= and =M-p= to navigate to the next and previous misspelling respectively. The movement commands work from within the minibuffer during =jinx-correct= and also globally outside the minibuffer context.

While the commands are not bound globally by default, they are available as =M-n= and =M-p= if point is placed on top of a misspelled word overlay. If you want you can add them and other commands to the =jinx-mode-map=, such that they are always available independent of point placement. If =repeat-mode= from Emacs 28 is enabled, the movement can be repeated with the keys =n= and =p=.

Enchant uses different backends for different languages. The backends are ordered as specified in the personal configuration file =~/.config/enchant/enchant.ordering= and the system-wide configuration file =/usr/share/enchant-2/enchant.ordering=. Enchant uses Hunspell as default backend for most languages barring a few exceptions. For English Enchant prefers Aspell and for Finnish and Turkish special backends called Voikko and Zemberek are used.

Depending on the backend the personal dictionary will be taken from different locations, e.g., =~/.aspell.LANG.pws= or =~/.config/enchant/LANG.dic=. It is possible to symlink different personal dictionaries such that they are shared by different spell checkers. See the [[https://rrthomas.github.io/enchant/lib/enchant.html][Enchant manual]] for details.

There exist multiple alternative spell-checking packages for Emacs, most famously the builtin ispell.el and flyspell.el packages. The main advantages of Jinx are its automatic checking of the visible text, its sharp focus on performance and the ability to easily use multiple dictionaries at once. The following three alternative packages come closest to the behavior of Jinx.

Since this package is part of [[https://elpa.gnu.org/packages/jinx.html][GNU ELPA]] contributions require a copyright assignment to the FSF.