]> code.delx.au - gnu-emacs/blobdiff - lisp/textmodes/flyspell.el
Switch to recommended form of GPLv3 permissions notice.
[gnu-emacs] / lisp / textmodes / flyspell.el
index 185f2e8dea34803459017d640e495206add5b83c..0267dfda7ca93ac41e951b870757bb528e039b1c 100644 (file)
@@ -1,7 +1,7 @@
 ;;; flyspell.el --- on-the-fly spell checker
 
 ;; Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007 Free Software Foundation, Inc.
+;;   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 ;; Author: Manuel Serrano <Manuel.Serrano@sophia.inria.fr>
 ;; Maintainer: FSF
@@ -9,10 +9,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +20,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
@@ -67,11 +65,21 @@ Non-nil means use highlight, nil means use minibuffer messages."
 
 (defcustom flyspell-mark-duplications-flag t
   "Non-nil means Flyspell reports a repeated word as an error.
+See `flyspell-mark-duplications-exceptions' to add exceptions to this rule.
 Detection of repeated words is not implemented in
 \"large\" regions; see `flyspell-large-region'."
   :group 'flyspell
   :type 'boolean)
 
+(defcustom flyspell-mark-duplications-exceptions
+  '(("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."
+  :group 'flyspell
+  :type '(alist :key-type string :value-type (repeat string)))
+
 (defcustom flyspell-sort-corrections nil
   "Non-nil means, sort the corrections alphabetically before popping them."
   :group 'flyspell
@@ -88,7 +96,8 @@ This variable specifies how far to search to find such a duplicate.
 0 means do not search for duplicate unrecognized spellings."
   :group 'flyspell
   :version "21.1"
-  :type 'number)
+  :type '(choice (const :tag "no limit" -1)
+                number))
 
 (defcustom flyspell-delay 3
   "The number of seconds to wait before checking, after a \"delayed\" command."
@@ -286,6 +295,7 @@ property of the major mode name.")
 ;;*--- mail mode -------------------------------------------------------*/
 (put 'mail-mode 'flyspell-mode-predicate 'mail-mode-flyspell-verify)
 (put 'message-mode 'flyspell-mode-predicate 'mail-mode-flyspell-verify)
+(defvar message-signature-separator)
 (defun mail-mode-flyspell-verify ()
   "Function used for `flyspell-generic-check-word-predicate' in Mail mode."
   (let ((header-end (save-excursion
@@ -338,6 +348,7 @@ property of the major mode name.")
 ;;*--- sgml mode -------------------------------------------------------*/
 (put 'sgml-mode 'flyspell-mode-predicate 'sgml-mode-flyspell-verify)
 (put 'html-mode 'flyspell-mode-predicate 'sgml-mode-flyspell-verify)
+(put 'nxml-mode 'flyspell-mode-predicate 'sgml-mode-flyspell-verify)
 
 (defun sgml-mode-flyspell-verify ()
   "Function used for `flyspell-generic-check-word-predicate' in SGML mode."
@@ -457,7 +468,8 @@ See also `flyspell-duplicate-distance'."
 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 iff ARG is positive.
+With a prefix argument ARG, turn Flyspell minor mode on if ARG is positive,
+otherwise turn it off.
 
 Bindings:
 \\[ispell-word]: correct words (using Ispell).
@@ -466,7 +478,7 @@ Bindings:
 \\[flyspell-correct-word] (or down-mouse-2): popup correct words.
 
 Hooks:
-This runs `flyspell-mode-hook' after flyspell is entered.
+This runs `flyspell-mode-hook' after flyspell mode is entered or exit.
 
 Remark:
 `flyspell-mode' uses `ispell-mode'.  Thus all Ispell options are
@@ -484,7 +496,10 @@ in your .emacs file.
   :keymap flyspell-mode-map
   :group 'flyspell
   (if flyspell-mode
-      (flyspell-mode-on)
+      (condition-case ()
+         (flyspell-mode-on)
+       (error (message "Enabling Flyspell mode gave an error")
+              (flyspell-mode -1)))
     (flyspell-mode-off)))
 
 ;;;###autoload
@@ -562,7 +577,7 @@ in your .emacs file.
 ;;*---------------------------------------------------------------------*/
 (defun flyspell-mode-on ()
   "Turn Flyspell mode on.  Do not use this; use `flyspell-mode' instead."
-  (ispell-maybe-find-aspell-dictionaries)
+  (ispell-set-spellchecker-params) ; Initialize variables and dicts alists
   (setq ispell-highlight-face 'flyspell-incorrect)
   ;; local dictionaries setup
   (or ispell-local-dictionary ispell-dictionary
@@ -601,16 +616,14 @@ in your .emacs file.
         (if binding
             (format "Welcome to flyspell. Use %s or Mouse-2 to correct words."
                     (key-description binding))
-          "Welcome to flyspell. Use Mouse-2 to correct words."))))
-  ;; we end with the flyspell hooks
-  (run-hooks 'flyspell-mode-hook))
+          "Welcome to flyspell. Use Mouse-2 to correct words.")))))
 
 ;;*---------------------------------------------------------------------*/
 ;;*    flyspell-delay-commands ...                                      */
 ;;*---------------------------------------------------------------------*/
 (defun flyspell-delay-commands ()
   "Install the standard set of Flyspell delayed commands."
-  (mapcar 'flyspell-delay-command flyspell-default-delayed-commands)
+  (mapc 'flyspell-delay-command flyspell-default-delayed-commands)
   (mapcar 'flyspell-delay-command flyspell-delayed-commands))
 
 ;;*---------------------------------------------------------------------*/
@@ -629,7 +642,7 @@ It will be checked only after `flyspell-delay' seconds."
 ;;*---------------------------------------------------------------------*/
 (defun flyspell-deplacement-commands ()
   "Install the standard set of Flyspell deplacement commands."
-  (mapcar 'flyspell-deplacement-command flyspell-default-deplacement-commands)
+  (mapc 'flyspell-deplacement-command flyspell-default-deplacement-commands)
   (mapcar 'flyspell-deplacement-command flyspell-deplacement-commands))
 
 ;;*---------------------------------------------------------------------*/
@@ -1000,6 +1013,7 @@ Mostly we check word delimiters."
 (defun flyspell-word (&optional following)
   "Spell check a word."
   (interactive (list ispell-following-word))
+  (ispell-set-spellchecker-params)    ; Initialize variables and dicts alists
   (save-excursion
     ;; use the correct dictionary
     (flyspell-accept-buffer-local-defs)
@@ -1021,6 +1035,13 @@ Mostly we check word delimiters."
                     (and (> start (point-min))
                          (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)))))
                 (save-excursion
                   (goto-char start)
                   (let* ((bound
@@ -1508,30 +1529,43 @@ The buffer to mark them in is `flyspell-large-region-buffer'."
     ;; this is done, we can start checking...
     (if flyspell-issue-message-flag (message "Checking region..."))
     (set-buffer curbuf)
-    (ispell-check-version)
-    (let ((c (apply 'ispell-call-process-region beg
-                   end
-                   ispell-program-name
-                   nil
-                   buffer
-                   nil
-                   (if ispell-really-aspell "list" "-l")
-                   (let (args)
-                     ;; Local dictionary becomes the global dictionary in use.
-                     (if ispell-local-dictionary
-                         (setq ispell-dictionary ispell-local-dictionary))
-                     (setq args (ispell-get-ispell-args))
-                     (if ispell-dictionary ; use specified dictionary
-                         (setq args
-                               (append (list "-d" ispell-dictionary) args)))
-                     (if ispell-personal-dictionary ; use specified pers dict
-                         (setq args
-                               (append args
-                                       (list "-p"
-                                             (expand-file-name
-                                              ispell-personal-dictionary)))))
-                     (setq args (append args ispell-extra-args))
-                     args))))
+    (ispell-set-spellchecker-params)  ; Initialize variables and dicts alists
+    ;; Local dictionary becomes the global dictionary in use.
+    (setq ispell-current-dictionary
+         (or ispell-local-dictionary ispell-dictionary))
+    (setq ispell-current-personal-dictionary
+         (or ispell-local-pdict ispell-personal-dictionary))
+    (let ((args (ispell-get-ispell-args))
+         (encoding (ispell-get-coding-system))
+         c)
+      (if (and ispell-current-dictionary  ; use specified dictionary
+              (not (member "-d" args)))  ; only define if not overridden
+         (setq args
+               (append (list "-d" ispell-current-dictionary) args)))
+      (if ispell-current-personal-dictionary ; use specified pers dict
+         (setq args
+               (append args
+                       (list "-p"
+                             (expand-file-name
+                              ispell-current-personal-dictionary)))))
+      (setq args (append args ispell-extra-args))
+      (if (and ispell-really-aspell
+              ispell-aspell-supports-utf8)
+         (setq args
+               (append args
+                       (list
+                        (concat "--encoding="
+                                (symbol-name
+                                 encoding))))))
+      (let ((process-coding-system-alist (list (cons "\\.*" encoding))))
+       (setq c (apply 'ispell-call-process-region beg
+                      end
+                      ispell-program-name
+                      nil
+                      buffer
+                      nil
+                      (if ispell-really-aspell "list" "-l")
+                      args)))
       (if (eq c 0)
          (progn
            (flyspell-process-localwords buffer)
@@ -1554,6 +1588,7 @@ The buffer to mark them in is `flyspell-large-region-buffer'."
 (defun flyspell-region (beg end)
   "Flyspell text between BEG and END."
   (interactive "r")
+  (ispell-set-spellchecker-params)  ; Initialize variables and dicts alists
   (if (= beg end)
       ()
     (save-excursion
@@ -1621,7 +1656,7 @@ FLYSPELL-BUFFER."
 ;;*    flyspell-overlay-p ...                                           */
 ;;*---------------------------------------------------------------------*/
 (defun flyspell-overlay-p (o)
-  "A predicate that return true iff O is an overlay used by flyspell."
+  "Return true if O is an overlay used by flyspell."
   (and (overlayp o) (overlay-get o 'flyspell-overlay)))
 
 ;;*---------------------------------------------------------------------*/
@@ -1961,12 +1996,8 @@ Sets `flyspell-auto-correct-previous-pos' to nil"
 But don't look beyond what's visible on the screen."
   (interactive "d")
 
-  (let (top bot)
-    (save-excursion
-      (move-to-window-line 0)
-      (setq top (point))
-      (move-to-window-line -1)
-      (setq bot (point)))
+  (let ((top (window-start))
+       (bot (window-end)))
     (save-excursion
       (save-restriction
        (narrow-to-region top bot)
@@ -2029,6 +2060,7 @@ If OPOINT is non-nil, restore point there after adjusting it for replacement."
     (error "Pop-up menus do not work on this terminal"))
   ;; use the correct dictionary
   (flyspell-accept-buffer-local-defs)
+  (or opoint (setq opoint (point-marker)))
   (let ((cursor-location (point))
        (word (flyspell-get-word nil)))
     (if (consp word)
@@ -2137,6 +2169,8 @@ If OPOINT is non-nil, restore point there after adjusting it for replacement."
 ;;*---------------------------------------------------------------------*/
 (defun flyspell-emacs-popup (event poss word)
   "The Emacs popup menu."
+  (unless window-system
+    (error "This command requires pop-up dialogs"))
   (if (not event)
       (let* ((mouse-pos  (mouse-position))
             (mouse-pos  (if (nth 1 mouse-pos)