;;; flyspell.el --- on-the-fly spell checker
-;; Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-;; 2008, 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 2000-2011 Free Software Foundation, Inc.
;; Author: Manuel Serrano <Manuel.Serrano@sophia.inria.fr>
;; Maintainer: FSF
;; M-x flyspell-prog-mode.
;; In that mode only text inside comments is checked.
;;
-;; Note: consider setting the variable ispell-parser to `tex' to
-;; avoid TeX command checking; use `(setq ispell-parser 'tex)'.
-;;
;; Some user variables control the behavior of flyspell. They are
;; those defined under the `User variables' comment.
:type 'boolean)
(defcustom flyspell-mark-duplications-exceptions
- '(("francais" . ("nous" "vous")))
+ '((nil . ("that" "had")) ; Common defaults for English.
+ ("\\`francais" . ("nous" "vous")))
"A list of exceptions for duplicated words.
-It should be a list of (LANGUAGE . EXCEPTION-LIST). LANGUAGE is matched
-against the current dictionary and EXCEPTION-LIST is a list of strings.
-The duplicated word is downcased before it is compared with the exceptions."
+It should be a list of (LANGUAGE . EXCEPTION-LIST).
+
+LANGUAGE is nil, which means the exceptions apply regardless of
+the current dictionary, or a regular expression matching the
+dictionary name (`ispell-local-dictionary' or
+`ispell-dictionary') for which the exceptions should apply.
+
+EXCEPTION-LIST is a list of strings. The checked word is
+downcased before comparing with these exceptions."
:group 'flyspell
- :type '(alist :key-type string :value-type (repeat string)))
+ :type '(alist :key-type (choice (const :tag "All dictionaries" nil)
+ string)
+ :value-type (repeat string))
+ :version "24.1")
(defcustom flyspell-sort-corrections nil
"Non-nil means, sort the corrections alphabetically before popping them."
(defcustom flyspell-check-tex-math-command nil
"Non-nil means check even inside TeX math environment.
-TeX math environments are discovered by the TEXMATHP that implemented
-inside the texmathp.el Emacs package. That package may be found at:
-http://strw.leidenuniv.nl/~dominik/Tools"
+TeX math environments are discovered by `texmathp', implemented
+inside AUCTeX package. That package may be found at
+URL `http://www.gnu.org/software/auctex/'"
:group 'flyspell
:type 'boolean)
;;* using flyspell with mail-mode add the following expression */
;;* in your .emacs file: */
;;* (add-hook 'mail-mode */
-;;* '(lambda () (setq flyspell-generic-check-word-predicate */
+;;* (lambda () (setq flyspell-generic-check-word-predicate */
;;* 'mail-mode-flyspell-verify))) */
;;*---------------------------------------------------------------------*/
(defvar flyspell-generic-check-word-predicate nil
(defun flyspell-generic-progmode-verify ()
"Used for `flyspell-generic-check-word-predicate' in programming modes."
- (let ((f (get-text-property (point) 'face)))
+ ;; (point) is next char after the word. Must check one char before.
+ (let ((f (get-text-property (- (point) 1) 'face)))
(memq f flyspell-prog-text-faces)))
;;;###autoload
;;;###autoload(defvar flyspell-mode nil)
;;;###autoload
(define-minor-mode flyspell-mode
- "Minor mode performing on-the-fly spelling checking.
-This spawns a single Ispell process and checks each word.
-The default flyspell behavior is to highlight incorrect words.
-With no argument, this command toggles Flyspell mode.
-With a prefix argument ARG, turn Flyspell minor mode on if ARG is positive,
-otherwise turn it off.
+ "Toggle on-the-fly spell checking (Flyspell mode).
+With a prefix argument ARG, enable Flyspell mode if ARG is
+positive, and disable it otherwise. If called from Lisp, enable
+the mode if ARG is omitted or nil.
+
+Flyspell mode is a buffer-local minor mode. When enabled, it
+spawns a single Ispell process and checks each word. The default
+flyspell behavior is to highlight incorrect words.
Bindings:
\\[ispell-word]: correct words (using Ispell).
:keymap flyspell-mode-map
:group 'flyspell
(if flyspell-mode
- (condition-case ()
+ (condition-case err
(flyspell-mode-on)
- (error (message "Enabling Flyspell mode gave an error")
+ (error (message "Error enabling Flyspell mode:\n%s" (cdr err))
(flyspell-mode -1)))
(flyspell-mode-off)))
(remove-hook 'after-change-functions 'flyspell-after-change-function t)
(remove-hook 'hack-local-variables-hook
(function flyspell-hack-local-variables-hook) t)
- ;; we remove all the flyspell hilightings
+ ;; we remove all the flyspell highlightings
(flyspell-delete-all-overlays)
;; we have to erase pre cache variables
(setq flyspell-pre-buffer nil)
;;* previous word nor the current word */
;;*---------------------------------------------------------------------*/
(defun flyspell-post-command-hook ()
- "The `post-command-hook' used by flyspell to check a word in-the-fly."
+ "The `post-command-hook' used by flyspell to check a word on-the-fly."
(interactive)
(when flyspell-mode
- (let ((command this-command)
- ;; Prevent anything we do from affecting the mark.
- deactivate-mark)
- (if (flyspell-check-pre-word-p)
- (with-current-buffer flyspell-pre-buffer
- '(flyspell-debug-signal-pre-word-checked)
- (save-excursion
- (goto-char flyspell-pre-point)
- (flyspell-word))))
- (if (flyspell-check-word-p)
- (progn
- '(flyspell-debug-signal-word-checked)
- (flyspell-word)
- ;; we remember which word we have just checked.
- ;; this will be used next time we will check a word
- ;; to compare the next current word with the word
- ;; that as been registered in the pre-command-hook
- ;; that is these variables are used within the predicate
- ;; FLYSPELL-CHECK-PRE-WORD-P
- (setq flyspell-pre-pre-buffer (current-buffer))
- (setq flyspell-pre-pre-point (point)))
- (progn
- (setq flyspell-pre-pre-buffer nil)
- (setq flyspell-pre-pre-point nil)
- ;; when a word is not checked because of a delayed command
- ;; we do not disable the ispell cache.
- (if (and (symbolp this-command) (get this-command 'flyspell-delayed))
- (progn
- (setq flyspell-word-cache-end -1)
- (setq flyspell-word-cache-result '_)))))
- (while (and (not (input-pending-p)) (consp flyspell-changes))
- (let ((start (car (car flyspell-changes)))
- (stop (cdr (car flyspell-changes))))
- (if (flyspell-check-changed-word-p start stop)
- (save-excursion
- '(flyspell-debug-signal-changed-checked)
- (goto-char start)
- (flyspell-word)))
- (setq flyspell-changes (cdr flyspell-changes))))
- (setq flyspell-previous-command command))))
+ (with-local-quit
+ (let ((command this-command)
+ ;; Prevent anything we do from affecting the mark.
+ deactivate-mark)
+ (if (flyspell-check-pre-word-p)
+ (with-current-buffer flyspell-pre-buffer
+ '(flyspell-debug-signal-pre-word-checked)
+ (save-excursion
+ (goto-char flyspell-pre-point)
+ (flyspell-word))))
+ (if (flyspell-check-word-p)
+ (progn
+ '(flyspell-debug-signal-word-checked)
+ ;; FIXME: This should be asynchronous!
+ (flyspell-word)
+ ;; we remember which word we have just checked.
+ ;; this will be used next time we will check a word
+ ;; to compare the next current word with the word
+ ;; that as been registered in the pre-command-hook
+ ;; that is these variables are used within the predicate
+ ;; FLYSPELL-CHECK-PRE-WORD-P
+ (setq flyspell-pre-pre-buffer (current-buffer))
+ (setq flyspell-pre-pre-point (point)))
+ (progn
+ (setq flyspell-pre-pre-buffer nil)
+ (setq flyspell-pre-pre-point nil)
+ ;; when a word is not checked because of a delayed command
+ ;; we do not disable the ispell cache.
+ (if (and (symbolp this-command)
+ (get this-command 'flyspell-delayed))
+ (progn
+ (setq flyspell-word-cache-end -1)
+ (setq flyspell-word-cache-result '_)))))
+ (while (and (not (input-pending-p)) (consp flyspell-changes))
+ (let ((start (car (car flyspell-changes)))
+ (stop (cdr (car flyspell-changes))))
+ (if (flyspell-check-changed-word-p start stop)
+ (save-excursion
+ '(flyspell-debug-signal-changed-checked)
+ (goto-char start)
+ (flyspell-word)))
+ (setq flyspell-changes (cdr flyspell-changes))))
+ (setq flyspell-previous-command command)))))
;;*---------------------------------------------------------------------*/
;;* flyspell-notify-misspell ... */
;;*---------------------------------------------------------------------*/
;;* flyspell-word-search-backward ... */
;;*---------------------------------------------------------------------*/
-(defun flyspell-word-search-backward (word bound)
+(defun flyspell-word-search-backward (word bound &optional ignore-case)
(save-excursion
(let ((r '())
(inhibit-point-motion-hooks t)
p)
(while (and (not r) (setq p (search-backward word bound t)))
(let ((lw (flyspell-get-word)))
- (if (and (consp lw) (string-equal (car lw) word))
+ (if (and (consp lw)
+ (if ignore-case
+ (string-equal (downcase (car lw)) (downcase word))
+ (string-equal (car lw) word)))
(setq r p)
(goto-char p))))
r)))
;;*---------------------------------------------------------------------*/
;;* flyspell-word ... */
;;*---------------------------------------------------------------------*/
-(defun flyspell-word (&optional following)
+(defun flyspell-word (&optional following known-misspelling)
"Spell check a word.
If the optional argument FOLLOWING, or, when called interactively
`ispell-following-word', is non-nil, checks the following (rather
-than preceding) word when the cursor is not over a word."
+than preceding) word when the cursor is not over a word. If
+optional argument KNOWN-MISSPELLING is non nil considers word a
+misspelling and skips redundant spell-checking step."
(interactive (list ispell-following-word))
(ispell-set-spellchecker-params) ; Initialize variables and dicts alists
(save-excursion
(not (memq (char-after (1- start)) '(?\} ?\\)))))
flyspell-mark-duplications-flag
(not (catch 'exception
- (dolist (except flyspell-mark-duplications-exceptions)
- (and (string= (or ispell-local-dictionary
- ispell-dictionary)
- (car except))
- (member (downcase word) (cdr except))
- (throw 'exception t)))))
+ (let ((dict (or ispell-local-dictionary
+ ispell-dictionary)))
+ (dolist (except flyspell-mark-duplications-exceptions)
+ (and (or (null (car except))
+ (and (stringp dict)
+ (string-match (car except) dict)))
+ (member (downcase word) (cdr except))
+ (throw 'exception t))))))
(save-excursion
(goto-char start)
(let* ((bound
(- end start)
(- (skip-chars-backward " \t\n\f"))))
(p (when (>= bound (point-min))
- (flyspell-word-search-backward word bound))))
+ (flyspell-word-search-backward word bound t))))
(and p (/= p start)))))
;; yes, this is a doublon
(flyspell-highlight-incorrect-region start end 'doublon)
(setq flyspell-word-cache-end end)
(setq flyspell-word-cache-word word)
;; now check spelling of word.
- (ispell-send-string "%\n")
- ;; put in verbose mode
- (ispell-send-string (concat "^" word "\n"))
- ;; we mark the ispell process so it can be killed
- ;; when emacs is exited without query
- (set-process-query-on-exit-flag ispell-process nil)
- ;; Wait until ispell has processed word. Since this code is often
- ;; executed from post-command-hook but the ispell process may not
- ;; be responsive, it's important to make sure we re-enable C-g.
- (with-local-quit
- (while (progn
- (accept-process-output ispell-process)
- (not (string= "" (car ispell-filter))))))
- ;; (ispell-send-string "!\n")
- ;; back to terse mode.
- ;; Remove leading empty element
- (setq ispell-filter (cdr ispell-filter))
- ;; ispell process should return something after word is sent.
- ;; Tag word as valid (i.e., skip) otherwise
- (or ispell-filter
- (setq ispell-filter '(*)))
- (if (consp ispell-filter)
- (setq poss (ispell-parse-output (car ispell-filter))))
+ (if (not known-misspelling)
+ (progn
+ (ispell-send-string "%\n")
+ ;; put in verbose mode
+ (ispell-send-string (concat "^" word "\n"))
+ ;; we mark the ispell process so it can be killed
+ ;; when emacs is exited without query
+ (set-process-query-on-exit-flag ispell-process nil)
+ ;; Wait until ispell has processed word.
+ (while (progn
+ (accept-process-output ispell-process)
+ (not (string= "" (car ispell-filter)))))
+ ;; (ispell-send-string "!\n")
+ ;; back to terse mode.
+ ;; Remove leading empty element
+ (setq ispell-filter (cdr ispell-filter))
+ ;; ispell process should return something after word is sent.
+ ;; Tag word as valid (i.e., skip) otherwise
+ (or ispell-filter
+ (setq ispell-filter '(*)))
+ (if (consp ispell-filter)
+ (setq poss (ispell-parse-output (car ispell-filter)))))
+ ;; Else, this was a known misspelling to begin with, and
+ ;; we should forge an ispell return value.
+ (setq poss (list word 1 nil nil)))
(let ((res (cond ((eq poss t)
;; correct
(setq flyspell-word-cache-result t)
;; is used, string is a TeX command
;; (char before beginning of word is
;; backslash) and none of the previous
- ;; contitions match
+ ;; conditions match.
(and (not ispell-really-aspell)
(save-excursion
(goto-char (- (nth 1 found-list) 1))
t
nil))))
(setq keep nil)
- (flyspell-word)
+ (flyspell-word nil t)
;; Search for next misspelled word will begin from
;; end of last validated match.
(setq buffer-scan-pos (point))))
(goto-char (point-min))
;; Localwords parsing copied from ispell.el.
(while (search-forward ispell-words-keyword nil t)
- (let ((end (save-excursion (end-of-line) (point)))
+ (let ((end (point-at-eol))
string)
;; buffer-local words separated by a space, and can contain
;; any character other than a space. Not rigorous enough.
(list "-p"
(expand-file-name
ispell-current-personal-dictionary)))))
+
+ ;; Check for extended character mode
+ (let ((extended-char-mode (ispell-get-extended-character-mode)))
+ (and extended-char-mode ; ~ extended character mode
+ (string-match "[^~]+$" extended-char-mode)
+ (add-to-list 'args (concat "-T" (match-string 0 extended-char-mode)))))
+
+ ;; Add ispell-extra-args
(setq args (append args ispell-extra-args))
;; If we are using recent aspell or hunspell, make sure we use the right encoding
(provide 'flyspell)
-;; arch-tag: 05d915b9-e9cf-44fb-9137-fc28f5eaab2a
;;; flyspell.el ends here