FlySpell

“Flyspell enables on-the-fly spell checking in Emacs by the means of a minor mode. It is called Flyspell. This facility is hardly intrusive. It requires no help. Flyspell highlights incorrect words as soon as they are completed or as soon as the TextCursor hits a new word.”

Flyspell can be found at http://www-sop.inria.fr/mimosa/Manuel.Serrano/flyspell/flyspell.html

It is also part of Emacs. See also FlyspellWithoutColors.

See FlyspellXmlLang to switch to the appropriate language indicated in the XML document and see FlyspellBabel to switch language as indicated by LaTeX Babel commands.

flyspell in other modes

Here is an example to enable it for text-mode, and disable it for log-edit-mode and change-log-mode. These two are derived from text-mode, and thus enabling flyspell-mode for text-mode also enables it for these two. An alternative solution would be the writing of a flyspell-mode-predicate such that symbols are ignored by flyspell.

    (dolist (hook '(text-mode-hook))
      (add-hook hook (lambda () (flyspell-mode 1))))
    (dolist (hook '(change-log-mode-hook log-edit-mode-hook))
      (add-hook hook (lambda () (flyspell-mode -1))))

The idiom used above makes it very easy to enable and disable flyspell for the various major-modes out there: Just add the relevant hook to the list where the other hooks already are.

Enable flyspell for comments in source code

Programmers can use flyspell-prog-mode to enable spell checking only within comments of source code.

Flyspell comes with a mode to check comments and strings in programming modes. Just type M-x flyspell-prog-mode or add it to your mode hooks

  (add-hook 'c++-mode-hook
          (lambda ()
            (flyspell-prog-mode)
            ; ...
          ))

- ruediger -

Performance

I highly suggest setting ‘flyspell-issue-message-flag’ to nil, as printing messages for every word (when checking the entire buffer) causes an enormous slowdown. – nschum

Avoid false positives

I recently started using flyspell and am enjoying its features. Is there a way to disable flyspell for certain regexps? For instance, I would like to disable flyspell when typing a url. Otherwise, when entering a url such as http://www.emacswiki.org/cgi-bin/emacs/FlySpell, www, emacswiki, cgi and FlySpell are highlighted as errors. Any advice would be greatly appreciated. – MattLundin

There is only one way, using flyspell-generic-check-word-predicate which should be a function. In such a function you can use thing at point.

However it is a bit difficult to manage this as this variable may be only one function. I have submitted a patch to Emacs devel to take care of this.

Thanks for pointing me to the flyspell-generic-check-word-predicate variable. – MattLundin

I am interested in a working solution to ignore spellchecking URLs and email addresses. The answer at http://superuser.com/a/345461/40407 seems to be relevant to making a solution with flyspell-generic-check-word-predicate, though not specificly for URLs and email addresses. MattLundin, did you come up with something?

Change dictionaries

As I often need to switch between English and German I use this function:

      (defun fd-switch-dictionary()
      (interactive)
      (let* ((dic ispell-current-dictionary)
    	 (change (if (string= dic "deutsch8") "english" "deutsch8")))
        (ispell-change-dictionary change)
        (message "Dictionary switched from %s to %s" dic change)
        ))
    
      (global-set-key (kbd "<f8>")   'fd-switch-dictionary)
    

FlorianDiesch

I too cycle through different languages, but not all that is available in the system. I use the following code inside my .emacs.

    (let ((langs '("american" "francais" "brasileiro")))
      (setq lang-ring (make-ring (length langs)))
      (dolist (elem langs) (ring-insert lang-ring elem)))
    (defun cycle-ispell-languages ()
      (interactive)
      (let ((lang (ring-ref lang-ring -1)))
        (ring-insert lang-ring lang)
        (ispell-change-dictionary lang)))
    (global-set-key [f6] 'cycle-ispell-languages)

DiogoRamos

How can I ignore or add a word without using the popup menu?

Use flyspell-auto-correct-word.

This is not working for me. With flyspell-auto-correct-word I can go through all suggestions for correction, but I do not get an option to insert the word into my dictionary.

Success in adding new words into the personal dictionary

I used “M x ispell-region”, and the words that ispell considered having incorrect spellings were highlighted. The point moved to the first “mis-spelled” word. By typing “i”, I inserted the word into my personal dictionary. Later I found that the personal dictionary was stored in the file $HOME/.aspell.en.pws in pure text format. Although the word was added when I used “ispell” instead of “flyspell”, but once added, flyspell also recognized the word as having a correct spelling. 😊 This information came from the web page: http://www.delorie.com/gnu/docs/emacs/emacs_109.html . Thanks!

– Namo Amitabha

You can also type “a” to make the word session-local and “A” to make it buffer-local (i.e. to add it to your LocalWords list.)

Bernard Hurley

I wanted a way to automagically insert a word into the user dictionary, and added this to my .emacs file:

;;; --------------------------------------------------- adding words to flyspell

(eval-when-compile (require 'cl))

(defun append-aspell-word (new-word)
 (let ((header "personal_ws-1.1")
       (file-name (substitute-in-file-name "$HOME/.aspell.en.pws"))
       (read-words (lambda (file-name)
                    (let ((all-lines (with-temp-buffer
                                      (insert-file-contents file-name)
                                      (split-string (buffer-string) "\n" t))))
                     (if (null all-lines)
                       ""
                      (split-string (mapconcat 'identity (cdr all-lines) "\n")
                                    nil 
                                    t))))))
  (when (file-readable-p file-name)
   (let* ((cur-words (eval (list read-words file-name)))
          (all-words (delq header (cons new-word cur-words)))
          (words (delq nil (remove-duplicates all-words :test 'string=))))
    (with-temp-file file-name     
     (insert (concat header 
                     " en "
                     (number-to-string (length words))
                     "\n"
                     (mapconcat 'identity (sort words #'string<) "\n"))))))
  (unless (file-readable-p file-name)
   (with-temp-file file-name
    (insert (concat header " en 1\n" new-word "\n")))))
 (ispell-kill-ispell t) ; restart ispell
 (flyspell-mode)
 (flyspell-mode))

(defun append-aspell-current ()
 "Add current word to aspell dictionary"
 (interactive)
 (append-aspell-word (thing-at-point 'word)))

– Aaron Michaux

Easy Spell Check: key bindings and function to make FlySpell/ispell/aspell easy to use w/ out a mouse

Place the below code in your .emacs

F8 will call ispell (or aspell, etc) for the word the cursor is on (or near). You can also use the built-in key binding M-$.

Ctrl-Shift-F8 enables/disables FlySpell for your current buffer (highlights misspelled words as you type)

Crtl-Meta-F8 runs FlySpell on your current buffer (highlights all misspelled words in the buffer)

Ctrl-F8 calls ispell for the FlySpell highlighted word prior to the cursor’s position

Meta-F8 calls ispell for the FlySpell highlighted word after the cursor’s position

;; easy spell check
(global-set-key (kbd "<f8>") 'ispell-word)
(global-set-key (kbd "C-S-<f8>") 'flyspell-mode)
(global-set-key (kbd "C-M-<f8>") 'flyspell-buffer)
(global-set-key (kbd "C-<f8>") 'flyspell-check-previous-highlighted-word)
(defun flyspell-check-next-highlighted-word ()
  "Custom function to spell check next highlighted word"
  (interactive)
  (flyspell-goto-next-error)
  (ispell-word)
  )
(global-set-key (kbd "M-<f8>") 'flyspell-check-next-highlighted-word)

How can I position the flyspell suggestions in a window that is below the current window? Currently, on Aquamacs, running leuven color theme, when the suggestions come up, the tabs do not disappear (they did when i wasn’t using the color theme). The theme is really nice (in conjunction with org-mode) so I do not wish to get rid of that. How can i force the suggestion window to appear just above the modeline?

Run flyspell with aspell instead of ispell

If you use flyspell with aspell instead of ispell you have to add :

(setq ispell-list-command "--list")

Because the “-l” option mean “--lang” in aspell and the “-l” option mean “--list” in ispell. flyspell-buffer, and flyspell-region are affected by this problem.

Run flyspell-buffer after change to dictionary

If I add a word during a flyspell session, it’s still marked up as misspelled. And flyspell-correct-previous-word tells me that it’s spelling is correct. How do I run flyspell-buffer on the buffer every time the dictionary is modified?

-kd

Found a working solution at https://www.reddit.com/r/emacs/comments/4oc7pg/spellcheck_flyspellmode_underlines_disappear_when/:

(defun flyspell-buffer-after-pdict-save (&rest _)
  (flyspell-buffer))

(advice-add 'ispell-pdict-save :after #'flyspell-buffer-after-pdict-save)

Flyspell with subword-mode

When the subword mode is on, especially with cc-mode, the words are distinguished more skilfully, e.g., “GoodBadType” → “Good”, “Bad”, and “Type”. How do I set the flyspell to work in this context?

-Kiwon

Flyspell has no built-in support for subword-mode, however, it is possible to adapt Flyspell to be more competent when subword-mode is activated. There are three primary changes that need to be made:

  1. Word boundary detection needs to updated for both Flyspell and ispell
  2. flyspell-small-region needs to be updated to advance by subwords, not whole words
    1. flyspell-large-region has similar issues which are more difficult to fix, though aspell offers a pseudo-solution
  3. flyspell-post-command-hook needs to know to trigger after typing a subword boundary

Code addressing (1) is as follows:

;; Like looking-at but with an offset
(defun my-looking-at (regexp &optional offset)
  (let ((pos (+ (or offset 0) (point))))
    (when (and (>= pos (point-min)) (< pos (point-max)))
      (string-match regexp (string (char-after pos))))))

;; Call the right forward function and move past otherchars
(defun my-forward (&optional backward)
  (let ((ispell-casechars (ispell-get-casechars))
        (ispell-otherchars (ispell-get-otherchars))
        (ispell-many-otherchars-p (ispell-get-many-otherchars-p))
        (offset (if backward -1 0))
        (dir (if backward -1 1))
        (continue t))
    (if subword-mode (subword-forward dir) (forward-word dir))
    (while (and continue
                (not (string= "" ispell-otherchars))
                (my-looking-at ispell-otherchars offset)
                (my-looking-at ispell-casechars (+ dir offset)))
      (if subword-mode (subword-forward dir) (forward-word dir))
      (setq continue ispell-many-otherchars-p))))
(defun my-backward () (my-forward t))

;; Properly find boundaries of words in CamelCase
(defun my-ispell-get-word (orig-fun &optional following extra-otherchars)
  (if (not subword-mode)
      (funcall orig-fun following extra-otherchars)
    (if following (my-forward) (if (not (eobp)) (forward-char)))
    (let* ((beg (progn (my-backward) (point-marker)))
           (end (progn (my-forward) (point-marker)))
           (word (buffer-substring-no-properties beg end)))
      (list word beg end))))
(advice-add #'ispell-get-word :around #'my-ispell-get-word)
(advice-add #'flyspell-get-word :around #'my-ispell-get-word)

This makes use of subword-forward and -backward to identify word boundaries while being careful to respect spelling non-delimiters like ' when used as an apostrophe (expressed in ispell’s otherchars). Optional argument ‘extra-otherchars’ is ignored in the above, but can be incorporated similarly if desired.

Code addressing (2) is as follows:

;; Simplify and use my-forward to handle CamelCase words
(defun my-flyspell-small-region (orig-fun beg end)
  ;; (if (not subword-mode)
  ;;     (funcall orig-fun beg end)
  (save-excursion
    (if (> beg end) (setq beg (prog1 end (setq end beg))))
    (if (< beg (point-min)) (setq beg (point-min)))
    (if (> end (point-max)) (setq end (point-max)))
    (goto-char beg)
    (while (< (point) end)
      (flyspell-word t)
      ;; (sit-for 0) ;; uncomment to enable animation
      (my-forward))))
(advice-add #'flyspell-small-region :around #'my-flyspell-small-region)

(Note that this depends on my-forward from (1).) This removes the status messages and the cursor sweep animation, which become a bit jarring when used with (3) below. (This should be fine for small regions, after all, unless you’ve disabled flyspell-large-region.) Note the use use of (flyspell-word t) to check forward rather than backward: this permits simpler cursor movement and also avoids double-checking each word (as is done in the standard implementation!).

A pseudo-solution for flyspell-large-region with aspell is as follows:

;; Fake handling of CamelCase words in flyspell-large-region
(defun my-flyspell-large-region (orig-fun beg end)
  (let ((ispell-extra-args ispell-extra-args)
        (subword-mode subword-mode))
    (when (and subword-mode (string-match "aspell\\'" ispell-program-name))
      (push "--run-together" ispell-extra-args)
      (push "--run-together-limit=6" ispell-extra-args)
      (push "--run-together-min=2" ispell-extra-args)
      (setq subword-mode nil))
    (funcall orig-fun beg end)))
(advice-add #'flyspell-large-region :around #'my-flyspell-large-region)

...

;; Use aspell if installed
(when (executable-find "aspell")
  (setq ispell-program-name "aspell")
  (setq ispell-list-command "--list"))

This exploits aspell’s --run-together family of options to accept CamelCase words, but it also ends up permitting missingspaces and other typos that form run-together words, like “theis”. aspell’s default case sensitivity does at least prevent the flagrant disregard of word boundaries within CamelCase words. (The choice of --run-together-limit=6 and -min=2 should serve most uses of CamelCase, which often include words as short as “is” but typically stick to brief phrases.)

In order to address (3), it is necessary to alter the logic Flyspell uses to decide when to trigger:

;; Only check the previous word if no longer editing it
(defun my-flyspell-check-pre-word-p ()
  (and (eq flyspell-pre-buffer (current-buffer))
       (numberp flyspell-pre-point)
       (/= (save-excursion
             (goto-char (1- flyspell-pre-point))
             (my-forward)
             (point))
           (save-excursion
             (if (not (bobp)) (backward-char))
             (my-forward)
             (point)))))

;; Simplify and use flyspell-region in the post-command-hook
(defun my-flyspell-post-command-hook (orig-fun)
  (when flyspell-mode
    (with-local-quit
      (let ((command this-command)
            deactivate-mark)
        ;; Handle word at previous location
        (when (my-flyspell-check-pre-word-p)
          (save-excursion
            (goto-char (1- flyspell-pre-point))
            (flyspell-word)))
        ;; Handle word at current location
        (when (flyspell-check-word-p)
          (flyspell-word))
        ;; Handle all other recent changes
        (while (and (not (input-pending-p)) (consp flyspell-changes))
          (let* ((change (pop flyspell-changes))
                 (beg (car change))
                 (end (cdr change)))
            (flyspell-region beg end)))
        (setq flyspell-previous-command command)))))
(advice-add #'flyspell-post-command-hook :around #'my-flyspell-post-command-hook)

(Also depends on my-forward from (1).) flyspell-post-command-hook is replaced primarily to check the word at (1- flyspell-pre-point) rather than directly at flyspell-pre-point so subwords are checked as you type them. The while-loop at the end now also unconditionally calls flyspell-region rather than flyspell-word, which renders flyspell extremely aggressive when altering large chunks of text.

I realize the above is a fairly extensive change, but I believe it’s roughly the minimum alteration needed to add subword checking as you type. All of the above is also compatible with disabling subword-mode, though doing so still leaves in some differences: notably, unconditionally calling flyspell-region in flyspell-post-command-hook. Should the maintainers of Flyspell ever read this, I would ask that they check that the logic expressed in their various -p functions to ensure they behave as intended. In particular flypsell-check-changed-word-p’s last line appears to be missing an and, and as a result may be incapable of returning non-nil. —rriegs

Flyspell with popup.el

If you’d like to use Flyspell’s menu selection in the terminal, or just prefer to use popup.el over the graphical menu, stick this somewhere in your load path:

    (defun flyspell-emacs-popup-textual (event poss word)
      "A textual flyspell popup menu."
      (require 'popup)
      (let* ((corrects (if flyspell-sort-corrections
                           (sort (car (cdr (cdr poss))) 'string<)
                         (car (cdr (cdr poss)))))
             (cor-menu (if (consp corrects)
                           (mapcar (lambda (correct)
                                     (list correct correct))
                                   corrects)
                         '()))
             (affix (car (cdr (cdr (cdr poss)))))
             show-affix-info
             (base-menu  (let ((save (if (and (consp affix) show-affix-info)
                                         (list
                                          (list (concat "Save affix: " (car affix))
                                                'save)
                                          '("Accept (session)" session)
                                          '("Accept (buffer)" buffer))
                                       '(("Save word" save)
                                         ("Accept (session)" session)
                                         ("Accept (buffer)" buffer)))))
                           (if (consp cor-menu)
                               (append cor-menu (cons "" save))
                             save)))
             (menu (mapcar
                    (lambda (arg) (if (consp arg) (car arg) arg))
                    base-menu)))
        (cadr (assoc (popup-menu* menu :scroll-bar t) base-menu))))

and put this in your init file:

    (eval-after-load "flyspell"
      '(progn
         (fset 'flyspell-emacs-popup 'flyspell-emacs-popup-textual)))

Now calling “flyspell-correct-word-before-point” or middle-clicking a word will create a textual popup. When working from the terminal, this will prevent the dreaded “This command requires pop-up dialogs” error.

Automatically displaying a textual popup in a terminal while using the usual emacs menu in the GUI

If you run an emacs server with both terminal and GUI clients you may wish for the type of menu to be selected automatically depending on which client you are using. Instead of redefining flyspell-emacs-popup it’s better to advise it so that flyspell-emacs-popup-textual (defined above) or the original function can be called as necessary

First a small helper function to use as the advice:

  (defun flyspell-emacs-popup-choose (org-fun event poss word)
    (if (window-system)
        (funcall org-fun event poss word)
      (flyspell-emacs-popup-textual event poss word)))

Now put this in your init file:

    (eval-after-load "flyspell"
      '(progn
          (advice-add 'flyspell-emacs-popup :around #'flyspell-emacs-popup-choose)))

Note: I have used the new syntax for advice. If you don’t have the latest emacs you may need to change this to the old syntax. Bernard Hurley

Skipping flyspell on specific region

This is useful for code block in org files, but any region with clear delimiters can be skipped

  (add-to-list 'ispell-skip-region-alist '("^#+BEGIN_SRC" . "^#+END_SRC"))

- chedi -

Flyspell with Hunspell on buffer with Japanese

Lines (false positives) are shown under many Japanese phrases. One solution (http://lists.gnu.org/archive/html/help-gnu-emacs/2018-02/msg00141.html) is shown below. – Tak Kunihiro

(defvar ispell-regexp-ja "[δΈ€-龠ぁ-πŸˆ€γ‚‘-𛀀ー・、。々]+"
  "Regular expression to match a Japanese word.
The expression can be [^\000-\377]+, [^!-~]+, or [δΈ€-龠ぁ-πŸˆ€γ‚‘-𛀀ー・、。々]+")
;; (add-to-list 'ispell-skip-region-alist (list ispell-regexp-ja))
(defun flyspell-skip-ja (beg end info)
  "Tell flyspell to skip a Japanese word.
Call this on `flyspell-incorrect-hook'."
  (string-match ispell-regexp-ja (buffer-substring beg end)))
(add-hook 'flyspell-incorrect-hook 'flyspell-skip-ja)

CategoryModes | CategorySpelling ==