4

Flyspell does a great job ignoring all the source code and only check comments, with one flaw: it still does check the text after #includes. So the iostream here does get highlighted:

#include <iostream>

I tried to add the includes to the skip regions, with no success:

(add-to-list 'ispell-skip-region-alist '("[^#include.*$]"))

Did I write it wrong? Or am I missing a different setting?

3 Answers 3

5

Ispell and flyspell are two packages. Setup of ispell has no effect on flyspell. (flyspell does use very limited ispell APIs but it should be invisible to users).

In your case, "iostream" is checked because its font face is font-lock-string-face. By default, flyspell-prog-mode is used for any major-mode inherits from prog-mode (for example, c++-mode inherits from prog-mode).

Read the code of flyspell-prog-mode, you will find flyspell-generic-progmode-verify is used as predicate. It basically just check whether font face of word matches pre-defined font in flyspell-prog-text-faces whose default values is '(font-lock-string-face font-lock-comment-face font-lock-doc-face).

So there are two simple solutions:

Solution 1, don't check words inside string but do check comments and doc:

(setq flyspell-prog-text-faces '(font-lock-comment-face font-lock-doc-face))

Solution 2 (recommended), do check the word inside string but tell the spell checker (aspell or hunspell) that "iostream" is not typo. If you use aspell, please edit ~/.aspell.en.pws, add a new line containing one word "iostream". For hunspell setup, check http://www.suares.com/index.php?page_id=25&news_id=233

Here is sample .aspell.en.pws containing all C++ header file names:

personal_ws-1.1 en 63
algorithm
array
bitset
cassert
cctype
cerrno
cfenv
cfloat
cinttypes
ciso646
climits
clocale
cmath
complex
csetjmp
csignal
cstdarg
cstdbool
cstddef
cstdint
cstdio
cstdlib
cstring
ctgmath
ctime
cwchar
cwctype
deque
exception
fstream
functional
iomanip
ios
iosfwd
iostream
istream
iterator
limits
list
locale
map
memory
new
numeric
ostream
queue
random
regex
set
sstream
stack
stdexcept
streambuf
string
strstream
tuple
typeinfo
type_traits
unordered_map
unordered_set
utility
valarray
vector

BTW, I don't use flyspell-prog-mode at all because it's too primitive and use less than 1% of Emacs power. I prefer tweak the spell checker options by myself and write my own predicates per major-mode.

How to tweaking spell checker options: http://blog.binchen.org/posts/what-s-the-best-spell-check-set-up-in-emacs.html

My predicate sample: https://github.com/redguardtoo/emacs.d/blob/master/lisp/init-spelling.el

My answer on write predicate for markdown-mode: How to make Flyspell ignore code blocks in Markdown?

6
  • Thanks for the writeup chen. For the first solution, does that mean that also code comments wont be checked? Because the main reason I want flyspell in prog-mode is to only check comments and strings. For the second solution that means I have to add all header file names, I mentioned iostream as an example. So that solution wont be practical for me.
    – SFbay007
    Commented Oct 8, 2017 at 23:55
  • I also got an error on the first solution. wrong number of arguments for setq.
    – SFbay007
    Commented Oct 9, 2017 at 0:16
  • Sorry, there is some typo in my original answer. I fixed them.
    – chen bin
    Commented Oct 9, 2017 at 0:44
  • I suggest solution 2 because solution 1 disabled the syntax check in string. Add all header names takes no more than 10 seconds, pretty easy.
    – chen bin
    Commented Oct 9, 2017 at 1:01
  • The problem Chen is that you might sometimes need to include local header files that are not part of the C++ libraries.
    – SFbay007
    Commented Oct 9, 2017 at 1:24
3

Without looking at the Ispell code, I can guess from what you wrote that you are using a regexp, and it is wrong. Try it without the brackets: "^#include.*$".

A regexp bracketed expression means match the character set expressed by the pattern within the brackets. In your case, you are asking that it NOT match any of the characters #include.*$, because the ^ at the start of a bracketed expression means NOT.

Looking briefly at ispell.el and ispell-skip-region-alist, a guess is that this might be what you want:

(add-to-list 'ispell-skip-region-alist '("^#include" forward-line))

See the Elisp manual, node Regexp Special. See also node Regular Expressions and the following nodes.

1
  • 1
    Thanks again Drew. But that also did not work. I still see flyspell highlighting header files for correction.
    – SFbay007
    Commented Oct 9, 2017 at 1:23
1

I too ran into this and came up with my own solution which was to augment the default processing of flyspell-prog-mode functionality with a check to see if the string is part of an include statement.

(defun my/on-include-line-p ()
  "T if point is on a C/C++ include line."
  (save-excursion
    (beginning-of-line)
    (looking-at-p "^#\\s-*include\\s-+[\"<]")))

(defun my/flyspell-progmode-verify ()
  "Custom `flyspell-generic-progmode-verify' function for C/C++ modes.
Does not allow spell-checking in '#include' strings."
  (and (flyspell-generic-progmode-verify)
       (not (my/on-include-line-p))))

(defun my/c++-mode-hook ()
  "Custom C++ mode hook."
  (flyspell-prog-mode 1)
  (setq flyspell-generic-check-word-predicate #'my/flyspell-progmode-verify)))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.