Effective spell check in Emacs
CREATED:
UPDATED:
I use Flyspell in web-mode as sample. Other major modes also works.
At first, please turn on flyspell
for all programming languages by inserting below code into .emacs
,
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
There is also a short tutorial on:
- How to setup flyspell
- Difference between hunspell and aspell
- How to setup hunspell
Spell check in HTML
I will spell check,
- Text between html tag like
<label>Please input email</label>
- Value of html input control like
<input type
"text" value="Please input your name">= - CSS class name like
<div class
"btn btn-default" />=
My setup:
;; {{ flyspell setup for web-mode
(defun web-mode-flyspell-verify ()
(let* ((f (get-text-property (- (point) 1) 'face))
rlt)
(cond
;; Check the words with these font faces, possibly.
;; this *blacklist* will be tweaked in next condition
((not (memq f '(web-mode-html-attr-value-face
web-mode-html-tag-face
web-mode-html-attr-name-face
web-mode-constant-face
web-mode-doctype-face
web-mode-keyword-face
web-mode-comment-face ;; focus on get html label right
web-mode-function-name-face
web-mode-variable-name-face
web-mode-css-property-name-face
web-mode-css-selector-face
web-mode-css-color-face
web-mode-type-face
web-mode-block-control-face)))
(setq rlt t))
;; check attribute value under certain conditions
((memq f '(web-mode-html-attr-value-face))
(save-excursion
(search-backward-regexp "=['\"]" (line-beginning-position) t)
(backward-char)
(setq rlt (string-match "^\\(value\\|class\\|ng[A-Za-z0-9-]*\\)$"
(thing-at-point 'symbol)))))
;; finalize the blacklist
(t
(setq rlt nil)))
rlt))
(put 'web-mode 'flyspell-mode-predicate 'web-mode-flyspell-verify)
;; }}
I use web-mode for HTML files. The technique applies on other modes (php-mode, html-mode ….) .
Don't display doublon (double word) as error
Modern CSS frameworks like Bootstrap make doublon unavoidable. For example, CSS class name btn btn-default
contains double word btn
.
So we need stop displaying doublon as error in HTML,
(defvar flyspell-check-doublon t
"Check doublon (double word) when calling `flyspell-highlight-incorrect-region'.")
(make-variable-buffer-local 'flyspell-check-doublon)
(defadvice flyspell-highlight-incorrect-region (around flyspell-highlight-incorrect-region-hack activate)
(if (or flyspell-check-doublon (not (eq 'doublon (ad-get-arg 2))))
ad-do-it))
(defun web-mode-hook-setup ()
(flyspell-mode 1)
(setq flyspell-check-doublon nil))
(add-hook 'web-mode-hook 'web-mode-hook-setup)
Spell check camel case strings
We can check camel cased string/variable/function if and only if aspell is used.
Insert below code into .emacs
,
;; if (aspell installed) { use aspell}
;; else if (hunspell installed) { use hunspell }
;; whatever spell checker I use, I always use English dictionary
;; I prefer use aspell because:
;; 1. aspell is older
;; 2. looks Kevin Atkinson still get some road map for aspell:
;; @see http://lists.gnu.org/archive/html/aspell-announce/2011-09/msg00000.html
(setq ispell-program-name "aspell"
;; force the English dictionary, support Camel Case spelling check (tested with aspell 0.6)
ispell-extra-args '("--sug-mode=ultra" "--lang=en_US" "--run-together")
Summary
EmacsWiki suggests (flyspell-prog-mode)
which only checks typo in comments.
But as I proved, Emacs gives you full freedom to design a different solution.
Screen shot (typos are underscored):
Javascript and ReactJS setup (OPTIONAL)
If you fully understand my previous sections, you don't need read this section.
Insert below code into .emacs
,
(defun js-flyspell-verify ()
(let* ((f (get-text-property (- (point) 1) 'face)))
;; *whitelist*
;; only words with following font face will be checked
(memq f '(js2-function-call
js2-function-param
js2-object-property
font-lock-variable-name-face
font-lock-string-face
font-lock-function-name-face))))
(put 'js2-mode 'flyspell-mode-predicate 'js-flyspell-verify)
(put 'rjsx-mode 'flyspell-mode-predicate 'js-flyspell-verify)