]> code.delx.au - gnu-emacs/blobdiff - lisp/textmodes/ispell.el
Spelling fixes.
[gnu-emacs] / lisp / textmodes / ispell.el
index ad591eb0e7f619d29c22227ac9a9cc13a2c41735..d22346b518b649677b04f5a27def6ee5552daee2 100644 (file)
@@ -1,7 +1,6 @@
 ;;; ispell.el --- interface to International Ispell Versions 3.1 and 3.2
 
-;; Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
-;;   2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 1994-1995, 1997-2011  Free Software Foundation, Inc.
 
 ;; Author:           Ken Stevens <k.stevens@ieee.org>
 ;; Maintainer:       Ken Stevens <k.stevens@ieee.org>
@@ -221,10 +220,10 @@ compatibility function in case `version<=' is not available."
        (let (ver mver)
          (if (string-match "[0-9]+" version start-ver)
              (setq start-ver (match-end 0)
-                   ver (string-to-number (substring version (match-beginning 0) (match-end 0)))))
+                   ver (string-to-number (match-string 0 version))))
          (if (string-match "[0-9]+" minver start-mver)
              (setq start-mver (match-end 0)
-                   mver (string-to-number (substring minver (match-beginning 0) (match-end 0)))))
+                   mver (string-to-number (match-string 0 minver))))
 
          (if (or ver mver)
              (progn
@@ -310,7 +309,9 @@ Warning!  Not checking comments, when a comment start is embedded in strings,
 may produce undesired results."
   :type '(choice (const exclusive) (const :tag "off" nil) (const :tag "on" t))
   :group 'ispell)
-;;;###autoload(put 'ispell-check-comments 'safe-local-variable (lambda (a) (memq a '(nil t exclusive))))
+;;;###autoload
+(put 'ispell-check-comments 'safe-local-variable
+     (lambda (a) (memq a '(nil t exclusive))))
 
 (defcustom ispell-query-replace-choices nil
   "*Corrections made throughout region when non-nil.
@@ -514,7 +515,8 @@ is automatically set when defined in the file with either
   :type '(choice string
                 (const :tag "default" nil))
   :group 'ispell)
-;;;###autoload(put 'ispell-local-dictionary 'safe-local-variable 'string-or-null-p)
+;;;###autoload
+(put 'ispell-local-dictionary 'safe-local-variable 'string-or-null-p)
 
 (make-variable-buffer-local 'ispell-local-dictionary)
 
@@ -738,8 +740,8 @@ Note that the CASECHARS and OTHERCHARS slots of the alist should
 contain the same character set as casechars and otherchars in the
 LANGUAGE.aff file \(e.g., english.aff\).")
 
-(defvar ispell-really-aspell nil)   ; Non-nil if aspell extensions should be used
-(defvar ispell-really-hunspell nil) ; Non-nil if hunspell extensions should be used
+(defvar ispell-really-aspell nil)   ; Non-nil if we can use aspell extensions.
+(defvar ispell-really-hunspell nil) ; Non-nil if we can use hunspell extensions.
 (defvar ispell-encoding8-command nil
   "Command line option prefix to select UTF-8 if supported, nil otherwise.
 If UTF-8 if supported by spellchecker and is selectable from the command line
@@ -767,8 +769,8 @@ here just for backwards compatibility.")
 
 
 
-;;; The version must be 3.1 or greater for this version of ispell.el
-;;; There is an incompatibility between version 3.1.12 and lower versions.
+;; The version must be 3.1 or greater for this version of ispell.el
+;; There is an incompatibility between version 3.1.12 and lower versions.
 (defconst ispell-required-version '(3 1 12)
   "Ispell versions with which this version of ispell.el is known to work.")
 (defvar ispell-offset -1
@@ -962,7 +964,8 @@ Internal use.")
        (setq found (nconc found (list dict)))))
     (setq ispell-aspell-dictionary-alist found)
     ;; Add a default entry
-    (let ((default-dict '(nil "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-B") nil utf-8)))
+    (let ((default-dict
+           '(nil "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-B") nil utf-8)))
       (push default-dict ispell-aspell-dictionary-alist))))
 
 (defvar ispell-aspell-data-dir nil
@@ -979,19 +982,32 @@ Assumes that value contains no whitespace."
     (car (split-string (buffer-string)))))
 
 (defun ispell-aspell-find-dictionary (dict-name)
-  ;; This returns nil if the data file does not exist.
-  ;; Can someone please explain the return value format when the
-  ;; file does exist -- rms?
-  (let* ((lang ;; Strip out variant, etc.
-         (and (string-match "^[[:alpha:]_]+" dict-name)
-              (match-string 0 dict-name)))
+  "For aspell dictionary DICT-NAME, return a list of parameters if an
+  associated data file is found or nil otherwise.  List format is
+  that of `ispell-dictionary-base-alist' elements."
+  ;; Make sure `ispell-aspell-data-dir' is defined
+  (or ispell-aspell-data-dir
+      (setq ispell-aspell-data-dir
+           (ispell-get-aspell-config-value "data-dir")))
+  ;; Try finding associated datafile
+  (let* ((datafile1
+         (concat ispell-aspell-data-dir "/"
+                 ;; Strip out variant, country code, etc.
+                 (and (string-match "^[[:alpha:]]+" dict-name)
+                      (match-string 0 dict-name)) ".dat"))
+        (datafile2
+         (concat ispell-aspell-data-dir "/"
+                 ;; Strip out anything but xx_YY.
+                 (and (string-match "^[[:alpha:]_]+" dict-name)
+                      (match-string 0 dict-name)) ".dat"))
         (data-file
-         (concat (or ispell-aspell-data-dir
-                     (setq ispell-aspell-data-dir
-                           (ispell-get-aspell-config-value "data-dir")))
-                 "/" lang ".dat"))
+         (if (file-readable-p datafile1)
+             datafile1
+           (if (file-readable-p datafile2)
+               datafile2)))
         otherchars)
-    (condition-case ()
+
+    (if data-file
        (with-temp-buffer
          (insert-file-contents data-file)
          ;; There is zero or one line with special characters declarations.
@@ -1019,14 +1035,13 @@ Assumes that value contains no whitespace."
                ;; Here we specify the encoding to use while communicating with
                ;; aspell.  This doesn't apply to command line arguments, so
                ;; just don't pass words to spellcheck as arguments...
-               'utf-8))
-      (file-error
-       nil))))
+               'utf-8)))))
 
 (defun ispell-aspell-add-aliases (alist)
   "Find aspell's dictionary aliases and add them to dictionary ALIST.
 Return the new dictionary alist."
-  (let ((aliases (file-expand-wildcards
+  (let ((aliases
+         (file-expand-wildcards
                  (concat (or ispell-aspell-dict-dir
                              (setq ispell-aspell-dict-dir
                                    (ispell-get-aspell-config-value "dict-dir")))
@@ -1101,7 +1116,7 @@ aspell is used along with Emacs).")
 
 
 (defun ispell-valid-dictionary-list ()
-  "Returns a list of valid dictionaries.
+  "Return a list of valid dictionaries.
 The variable `ispell-library-directory' defines the library location."
   ;; Initialize variables and dictionaries alists for desired spellchecker.
   ;; Make sure ispell.el is loaded to avoid some autoload loops in XEmacs
@@ -1111,26 +1126,24 @@ The variable `ispell-library-directory' defines the library location."
 
   (let ((dicts (append ispell-local-dictionary-alist ispell-dictionary-alist))
        (dict-list (cons "default" nil))
-       name load-dict)
+       name dict-bname)
     (dolist (dict dicts)
       (setq name (car dict)
-           load-dict (car (cdr (member "-d" (nth 5 dict)))))
+           dict-bname (or (car (cdr (member "-d" (nth 5 dict))))
+                          name))
       ;; Include if the dictionary is in the library, or dir not defined.
       (if (and
           name
-          ;; include all dictionaries if lib directory not known.
           ;; For Aspell, we already know which dictionaries exist.
           (or ispell-really-aspell
+              ;; Include all dictionaries if lib directory not known.
+              ;; Same for Hunspell, where ispell-library-directory is nil.
               (not ispell-library-directory)
               (file-exists-p (concat ispell-library-directory
-                                     "/" name ".hash"))
-              (file-exists-p (concat ispell-library-directory "/" name ".has"))
-              (and load-dict
-                   (or (file-exists-p (concat ispell-library-directory
-                                              "/" load-dict ".hash"))
-                       (file-exists-p (concat ispell-library-directory
-                                              "/" load-dict ".has"))))))
-         (setq dict-list (cons name dict-list))))
+                                     "/" dict-bname ".hash"))
+              (file-exists-p (concat ispell-library-directory
+                                     "/" dict-bname ".has"))))
+         (push name dict-list)))
     dict-list))
 
 ;;; define commands in menu in opposite order you want them to appear.
@@ -1168,7 +1181,8 @@ The variable `ispell-library-directory' defines the library location."
        `(menu-item ,(purecopy "Complete Word") ispell-complete-word
                    :help ,(purecopy "Complete word at cursor using dictionary")))
       (define-key ispell-menu-map [ispell-complete-word-interior-frag]
-       `(menu-item ,(purecopy "Complete Word Fragment") ispell-complete-word-interior-frag
+       `(menu-item ,(purecopy "Complete Word Fragment")
+                    ispell-complete-word-interior-frag
                    :help ,(purecopy "Complete word fragment at cursor")))))
 
 ;;;###autoload
@@ -1185,7 +1199,8 @@ The variable `ispell-library-directory' defines the library location."
        `(menu-item ,(purecopy "Spell-Check Word") ispell-word
                    :help ,(purecopy "Spell-check word at cursor")))
       (define-key ispell-menu-map [ispell-comments-and-strings]
-       `(menu-item ,(purecopy "Spell-Check Comments") ispell-comments-and-strings
+       `(menu-item ,(purecopy "Spell-Check Comments")
+                    ispell-comments-and-strings
                    :help ,(purecopy "Spell-check only comments and strings")))))
 
 ;;;###autoload
@@ -1264,9 +1279,6 @@ The variable `ispell-library-directory' defines the library location."
 
 ;;; **********************************************************************
 
-
-;;; This variable contains the current dictionary being used if the ispell
-;;; process is running.
 (defvar ispell-current-dictionary nil
   "The name of the current dictionary, or nil for the default.
 This is passed to the ispell process using the `-d' switch and is
@@ -1291,6 +1303,7 @@ Protects against bogus binding of `enable-multibyte-characters' in XEmacs."
 
 ;; Return a string decoded from Nth element of the current dictionary.
 (defun ispell-get-decoded-string (n)
+  "Get the decoded string in slot N of the descriptor of the current dict."
   (let* ((slot (or
                (assoc ispell-current-dictionary ispell-local-dictionary-alist)
                (assoc ispell-current-dictionary ispell-dictionary-alist)
@@ -1334,9 +1347,6 @@ Protects against bogus binding of `enable-multibyte-characters' in XEmacs."
 (defvar ispell-process-directory nil
   "The directory where `ispell-process' was started.")
 
-(defvar ispell-process-buffer-name nil
-  "The buffer where `ispell-process' was started.")
-
 (defvar ispell-filter nil
   "Output filter from piped calls to Ispell.")
 
@@ -1400,7 +1410,8 @@ The last occurring definition in the buffer will be used.")
     (ispell-dictionary-keyword    forward-line)
     (ispell-pdict-keyword         forward-line)
     (ispell-parsing-keyword       forward-line)
-    (,(purecopy "^---*BEGIN PGP [A-Z ]*--*") . ,(purecopy "^---*END PGP [A-Z ]*--*"))
+    (,(purecopy "^---*BEGIN PGP [A-Z ]*--*")
+     . ,(purecopy "^---*END PGP [A-Z ]*--*"))
     ;; assume multiline uuencoded file? "\nM.*$"?
     (,(purecopy "^begin [0-9][0-9][0-9] [^ \t]+$") . ,(purecopy "\nend\n"))
     (,(purecopy "^%!PS-Adobe-[123].0")  . ,(purecopy "\n%%EOF\n"))
@@ -1712,7 +1723,11 @@ quit          spell session exited."
                  (extent-at start)
                  (and (fboundp 'delete-extent)
                       (delete-extent (extent-at start)))))
-           ((null poss) (message "Error in ispell process"))
+           ((null poss)
+            (message "Error checking word %s using %s with %s dictionary"
+                     (funcall ispell-format-word-function word)
+                     (file-name-nondirectory ispell-program-name)
+                     (or ispell-current-dictionary "default")))
            (ispell-check-only        ; called from ispell minor mode.
             (if (fboundp 'make-extent)
                 (if (fboundp 'set-extent-property)
@@ -1880,9 +1895,10 @@ Global `ispell-quit' set to start location to continue spell session."
     ;; setup the *Choices* buffer with valid data.
     (with-current-buffer (get-buffer-create ispell-choices-buffer)
       (setq mode-line-format
-           (concat "--  %b  --  word: " word
-                   "  --  dict: " (or ispell-current-dictionary "default")
-                   "  --  prog: " (file-name-nondirectory ispell-program-name)))
+           (concat
+             "--  %b  --  word: " word
+             "  --  dict: " (or ispell-current-dictionary "default")
+             "  --  prog: " (file-name-nondirectory ispell-program-name)))
       ;; XEmacs: no need for horizontal scrollbar in choices window
       (with-no-warnings
        (and (fboundp 'set-specifier)
@@ -1902,7 +1918,7 @@ Global `ispell-quit' set to start location to continue spell session."
                    (setq line (1+ line))))
              (insert (car guess) "    ")
              (setq guess (cdr guess)))
-           (insert "\nUse option `i' to accept this spelling and put it in your private dictionary.")
+           (insert "\nUse option `i' to accept this spelling and put it in your private dictionary.\n")
            (setq line (+ line (if choices 3 2)))))
       (while (and choices
                  (< (if (> (+ 7 (current-column) (length (car choices))
@@ -2147,7 +2163,7 @@ Global `ispell-quit' set to start location to continue spell session."
   (if (and ispell-use-framepop-p (fboundp 'framepop-display-buffer))
       (progn
        (framepop-display-buffer (get-buffer ispell-choices-buffer))
-;;;    (get-buffer-window ispell-choices-buffer t)
+        ;; (get-buffer-window ispell-choices-buffer t)
        (select-window (previous-window))) ; *Choices* window
     ;; standard selection by splitting a small buffer out of this window.
     (let ((choices-window (get-buffer-window ispell-choices-buffer)))
@@ -2280,68 +2296,63 @@ if defined."
       (unless (file-readable-p lookup-dict)
        (error "lookup-words error: Unreadable or missing plain word-list %s."
               lookup-dict))
-    (error (concat "lookup-words error: No plain word-list found at system default "
-                  "locations.  Customize `ispell-alternate-dictionary' to set yours.")))
+    (error (concat "lookup-words error: No plain word-list found at system"
+                   "default locations.  "
+                   "Customize `ispell-alternate-dictionary' to set yours.")))
 
   (let* ((process-connection-type ispell-use-ptys-p)
         (wild-p (string-match "\\*" word))
         (look-p (and ispell-look-p     ; Only use look for an exact match.
                      (or ispell-have-new-look (not wild-p))))
-        (ispell-grep-buffer (get-buffer-create "*Ispell-Temp*")) ; result buf
         (prog (if look-p ispell-look-command ispell-grep-command))
         (args (if look-p ispell-look-options ispell-grep-options))
         status results loc)
-    (unwind-protect
-       (save-window-excursion
-         (message "Starting \"%s\" process..." (file-name-nondirectory prog))
-         (set-buffer ispell-grep-buffer)
-         (if look-p
-             nil
-           ;; convert * to .*
-           (insert "^" word "$")
-           (while (search-backward "*" nil t) (insert "."))
-           (setq word (buffer-string))
-           (erase-buffer))
-         (setq status (apply 'ispell-call-process prog nil t nil
-                             (nconc (if (and args (> (length args) 0))
-                                        (list args)
-                                      (if look-p nil
-                                        (list "-e")))
-                                    (list word)
-                                    (if lookup-dict (list lookup-dict)))))
-         ;; grep returns status 1 and no output when word not found, which
-         ;; is a perfectly normal thing.
-         (if (stringp status)
-             (setq results (cons (format "error: %s exited with signal %s"
-                                         (file-name-nondirectory prog) status)
-                                 results))
-           ;; else collect words into `results' in FIFO order
-           (goto-char (point-max))
-           ;; assure we've ended with \n
-           (or (bobp) (= (preceding-char) ?\n) (insert ?\n))
-           (while (not (bobp))
-             (setq loc (point))
-             (forward-line -1)
-             (setq results (cons (buffer-substring-no-properties (point)
-                                                                 (1- loc))
-                                 results)))))
-      ;; protected
-      (kill-buffer ispell-grep-buffer)
-      (if (and results (string-match ".+: " (car results)))
-         (error "%s error: %s" ispell-grep-command (car results))))
+    (with-temp-buffer
+      (message "Starting \"%s\" process..." (file-name-nondirectory prog))
+      (if look-p
+          nil
+        ;; Convert * to .*
+        (insert "^" word "$")
+        (while (search-backward "*" nil t) (insert "."))
+        (setq word (buffer-string))
+        (erase-buffer))
+      (setq status (apply 'ispell-call-process prog nil t nil
+                          (nconc (if (and args (> (length args) 0))
+                                     (list args)
+                                   (if look-p nil
+                                     (list "-e")))
+                                 (list word)
+                                 (if lookup-dict (list lookup-dict)))))
+      ;; `grep' returns status 1 and no output when word not found, which
+      ;; is a perfectly normal thing.
+      (if (stringp status)
+          (error "error: %s exited with signal %s"
+                 (file-name-nondirectory prog) status)
+        ;; Else collect words into `results' in FIFO order.
+        (goto-char (point-max))
+        ;; Assure we've ended with \n.
+        (or (bobp) (= (preceding-char) ?\n) (insert ?\n))
+        (while (not (bobp))
+          (setq loc (point))
+          (forward-line -1)
+          (push (buffer-substring-no-properties (point)
+                                                (1- loc))
+                results))))
+    (if (and results (string-match ".+: " (car results)))
+        (error "%s error: %s" ispell-grep-command (car results)))
     results))
 
 
-;;; "ispell-filter" is a list of output lines from the generating function.
-;;;   Each full line (ending with \n) is a separate item on the list.
-;;; "output" can contain multiple lines, part of a line, or both.
-;;; "start" and "end" are used to keep bounds on lines when "output" contains
-;;;   multiple lines.
-;;; "ispell-filter-continue" is true when we have received only part of a
-;;;   line as output from a generating function ("output" did not end with \n)
-;;; THIS FUNCTION WILL FAIL IF THE PROCESS OUTPUT DOESN'T END WITH \n!
-;;;   This is the case when a process dies or fails. The default behavior
-;;;   in this case treats the next input received as fresh input.
+;; "ispell-filter" is a list of output lines from the generating function.
+;;   Each full line (ending with \n) is a separate item on the list.
+;; "output" can contain multiple lines, part of a line, or both.
+;; "start" and "end" are used to keep bounds on lines when "output" contains
+;;   multiple lines.
+;; "ispell-filter-continue" is true when we have received only part of a
+;;   line as output from a generating function ("output" did not end with \n)
+;; THIS FUNCTION WILL FAIL IF THE PROCESS OUTPUT DOESN'T END WITH \n!
+;;   This is the case when a process dies or fails. The default behavior
+;;   in this case treats the next input received as fresh input.
 
 (defun ispell-filter (process output)
   "Output filter function for ispell, grep, and look."
@@ -2541,18 +2552,18 @@ Optional third arg SHIFT is an offset to apply based on previous corrections."
        (setq count (string-to-number output) ; get number of misses.
              output (substring output (1+ (string-match " " output 1)))))
       (setq offset (string-to-number output))
-      (if (eq type ?#)                 ; No miss or guess list.
-         (setq output nil)
-       (setq output (substring output (1+ (string-match " " output 1)))))
+      (setq output (if (eq type ?#)     ; No miss or guess list.
+                       nil
+                     (substring output (1+ (string-match " " output 1)))))
       (while output
        (let ((end (string-match ", \\|\\($\\)" output))) ; end of miss/guess.
          (setq cur-count (1+ cur-count))
          (if (> cur-count count)
-             (setq guess-list (cons (substring output 0 end) guess-list))
-           (setq miss-list (cons (substring output 0 end) miss-list)))
-         (if (match-end 1)             ; True only when at end of line.
-             (setq output nil)         ; no more misses or guesses
-           (setq output (substring output (+ end 2))))))
+             (push (substring output 0 end) guess-list)
+           (push (substring output 0 end) miss-list))
+         (setq output (if (match-end 1) ; True only when at end of line.
+                           nil           ; No more misses or guesses.
+                         (substring output (+ end 2))))))
       ;; return results.  Accept word if it was already accepted.
       ;; adjust offset.
       (if (member original-word accept-list)
@@ -2573,37 +2584,35 @@ When asynchronous processes are not supported, `run' is always returned."
 (defun ispell-start-process ()
   "Start the ispell process, with support for no asynchronous processes.
 Keeps argument list for future ispell invocations for no async support."
-  (let ((default-directory default-directory)
-       args)
-    (unless (and (file-directory-p default-directory)
-                (file-readable-p default-directory))
-      ;; Defend against bad `default-directory'.
-      (setq default-directory (expand-file-name "~/")))
-    ;; 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))
-    (setq args (ispell-get-ispell-args))
-    (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)))))
-
-    ;; If we are using recent aspell or hunspell, make sure we use the right encoding
-    ;; for communication. ispell or older aspell/hunspell does not support this
-    (if ispell-encoding8-command
-       (setq args
-             (append args
-                     (list
-                      (concat ispell-encoding8-command
-                              (symbol-name (ispell-get-coding-system)))))))
-    (setq args (append args ispell-extra-args))
+  ;; 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* ((default-directory
+           (if (and (file-directory-p default-directory)
+                    (file-readable-p default-directory))
+               default-directory
+             ;; Defend against bad `default-directory'.
+             (expand-file-name "~/")))
+        (orig-args (ispell-get-ispell-args))
+         (args
+          (append
+           (if (and ispell-current-dictionary      ; Not for default dict (nil)
+                    (not (member "-d" orig-args))) ; Only define if not overridden.
+               (list "-d" ispell-current-dictionary))
+           orig-args
+           (if ispell-current-personal-dictionary ; Use specified pers dict.
+               (list "-p"
+                     (expand-file-name ispell-current-personal-dictionary)))
+           ;; If we are using recent aspell or hunspell, make sure we use the
+           ;; right encoding for communication. ispell or older aspell/hunspell
+           ;; does not support this.
+           (if ispell-encoding8-command
+               (list
+                (concat ispell-encoding8-command
+                        (symbol-name (ispell-get-coding-system)))))
+           ispell-extra-args)))
 
     ;; Initially we don't know any buffer's local words.
     (setq ispell-buffer-local-name nil)
@@ -2612,9 +2621,11 @@ Keeps argument list for future ispell invocations for no async support."
        (let ((process-connection-type ispell-use-ptys-p))
          (apply 'start-process
                 "ispell" nil ispell-program-name
-                "-a"                                ; accept single input lines
-                (if ispell-really-hunspell "" "-m") ; make root/affix combos not in dict
-                args))                              ; hunspell -m option means different
+                "-a"                   ; Accept single input lines.
+                 ;; Make root/affix combos not in dict.
+                 ;; hunspell -m option means different.
+                (if ispell-really-hunspell "" "-m")
+                args))
       (setq ispell-cmd-args args
            ispell-output-buffer (generate-new-buffer " *ispell-output*")
            ispell-session-buffer (generate-new-buffer " *ispell-session*"))
@@ -2622,79 +2633,114 @@ Keeps argument list for future ispell invocations for no async support."
       t)))
 
 
-
 (defun ispell-init-process ()
   "Check status of Ispell process and start if necessary."
-  (if (and ispell-process
-          (eq (ispell-process-status) 'run)
-          ;; Unless we are using an explicit personal dictionary,
-          ;; ensure we're in the same default directory!
-          ;; Restart check for personal dictionary is done in
-          ;; `ispell-internal-change-dictionary', called from `ispell-buffer-local-dict'
-          (or (or ispell-local-pdict ispell-personal-dictionary)
-              (equal ispell-process-directory (expand-file-name default-directory))))
-      (setq ispell-filter nil ispell-filter-continue nil)
-    ;; may need to restart to select new personal dictionary.
-    (ispell-kill-ispell t)
-    (message "Starting new Ispell process [%s] ..."
-            (or ispell-local-dictionary ispell-dictionary "default"))
-    (sit-for 0)
-    (setq ispell-library-directory (ispell-check-version)
-         ispell-process (ispell-start-process)
-         ispell-filter nil
-         ispell-filter-continue nil)
-    ;; When spellchecking minibuffer contents, make sure ispell process
-    ;; is not restarted every time the minibuffer is killed.
-    (if (window-minibuffer-p)
-       (if (fboundp 'minibuffer-selected-window)
-           ;; Assign ispell process to parent buffer
-           (setq ispell-process-directory (expand-file-name default-directory)
-                 ispell-process-buffer-name (window-buffer (minibuffer-selected-window)))
-         ;; Force `ispell-process-directory' to $HOME and use a dummy name
-         (setq ispell-process-directory (expand-file-name "~/")
-               ispell-process-buffer-name " * Minibuffer-has-spellcheck-enabled"))
-      ;; Not in a minibuffer
-      (setq ispell-process-directory (expand-file-name default-directory)
-           ispell-process-buffer-name (buffer-name)))
-    (if ispell-async-processp
-       (set-process-filter ispell-process 'ispell-filter))
-    ;; protect against bogus binding of `enable-multibyte-characters' in XEmacs
-    (if (and (or (featurep 'xemacs)
-                (and (boundp 'enable-multibyte-characters)
-                     enable-multibyte-characters))
-            (fboundp 'set-process-coding-system))
-       (set-process-coding-system ispell-process (ispell-get-coding-system)
-                                  (ispell-get-coding-system)))
-    ;; Get version ID line
-    (ispell-accept-output 3)
-    ;; get more output if filter empty?
-    (if (null ispell-filter) (ispell-accept-output 3))
-    (cond ((null ispell-filter)
-          (error "%s did not output version line" ispell-program-name))
-         ((and
-           (stringp (car ispell-filter))
-           (if (string-match "warning: " (car ispell-filter))
-               (progn
-                 (ispell-accept-output 3) ; was warn msg.
-                 (stringp (car ispell-filter)))
-             (null (cdr ispell-filter)))
-           (string-match "^@(#) " (car ispell-filter)))
-          ;; got the version line as expected (we already know it's the right
-          ;; version, so don't bother checking again.)
-          nil)
-         (t
-          ;; Otherwise, it must be an error message.  Show the user.
-          ;; But first wait to see if some more output is going to arrive.
-          ;; Otherwise we get cool errors like "Can't open ".
-          (sleep-for 1)
-          (ispell-accept-output 3)
-          (error "%s" (mapconcat 'identity ispell-filter "\n"))))
-    (setq ispell-filter nil)           ; Discard version ID line
-    (let ((extended-char-mode (ispell-get-extended-character-mode)))
-      (if extended-char-mode           ; ~ extended character mode
-         (ispell-send-string (concat extended-char-mode "\n"))))
-    (if ispell-async-processp
-       (set-process-query-on-exit-flag ispell-process nil))))
+  (let* (;; Basename of dictionary used by the spell-checker
+        (dict-bname (or (car (cdr (member "-d" (ispell-get-ispell-args))))
+                        ispell-current-dictionary))
+        ;; Use "~/" as default-directory unless using Ispell with per-dir
+        ;; personal dictionaries and not in a minibuffer under XEmacs
+        (default-directory
+          (if (or ispell-really-aspell
+                  ispell-really-hunspell
+                  ;; Protect against bad default-directory
+                  (not (and (file-directory-p default-directory)
+                            (file-readable-p default-directory)))
+                  ;; Ispell and per-dir personal dicts available
+                  (not (or (file-readable-p (concat default-directory
+                                                    ".ispell_words"))
+                           (file-readable-p (concat default-directory
+                                                    ".ispell_"
+                                                    (or dict-bname
+                                                        "default")))))
+                  ;; Ispell, in a minibuffer, and XEmacs
+                  (and (window-minibuffer-p)
+                       (not (fboundp 'minibuffer-selected-window))))
+              (expand-file-name "~/")
+            (expand-file-name default-directory))))
+    ;; Check if process needs restart
+    (if (and ispell-process
+            (eq (ispell-process-status) 'run)
+            ;; Unless we are using an explicit personal dictionary, ensure
+            ;; we're in the same default directory!  Restart check for
+            ;; personal dictionary is done in
+            ;; `ispell-internal-change-dictionary', called from
+            ;; `ispell-buffer-local-dict'
+            (or (or ispell-local-pdict ispell-personal-dictionary)
+                (equal ispell-process-directory default-directory)))
+       (setq ispell-filter nil ispell-filter-continue nil)
+      ;; may need to restart to select new personal dictionary.
+      (ispell-kill-ispell t)
+      (message "Starting new Ispell process [%s] ..."
+              (or ispell-local-dictionary ispell-dictionary "default"))
+      (sit-for 0)
+      (setq ispell-library-directory (ispell-check-version)
+           ispell-process (ispell-start-process)
+           ispell-filter nil
+           ispell-filter-continue nil
+           ispell-process-directory default-directory)
+
+      (unless (equal ispell-process-directory (expand-file-name "~/"))
+       ;; At this point, `ispell-process-directory' will be "~/" unless using
+       ;; Ispell with directory-specific dicts and not in XEmacs minibuffer.
+       ;; If not, kill ispell process when killing buffer.  It may be in a
+       ;; removable device that would otherwise become un-mountable.
+       (with-current-buffer
+           (if (and (window-minibuffer-p)                  ;; In minibuffer
+                    (fboundp 'minibuffer-selected-window)) ;; Not XEmacs.
+               ;; In this case kill ispell only when parent buffer is killed
+               ;; to avoid over and over ispell kill.
+               (window-buffer (minibuffer-selected-window))
+             (current-buffer))
+         ;; 'local does not automatically make hook buffer-local in XEmacs.
+         (if (featurep 'xemacs)
+             (make-local-hook 'kill-buffer-hook))
+         (add-hook 'kill-buffer-hook
+                   (lambda () (ispell-kill-ispell t)) nil 'local)))
+
+      (if ispell-async-processp
+         (set-process-filter ispell-process 'ispell-filter))
+      ;; Protect against XEmacs bogus binding of `enable-multibyte-characters'.
+      (if (and (or (featurep 'xemacs)
+                  (and (boundp 'enable-multibyte-characters)
+                       enable-multibyte-characters))
+              (fboundp 'set-process-coding-system))
+         (set-process-coding-system ispell-process (ispell-get-coding-system)
+                                    (ispell-get-coding-system)))
+      ;; Get version ID line
+      (ispell-accept-output 3)
+      ;; get more output if filter empty?
+      (if (null ispell-filter) (ispell-accept-output 3))
+      (cond ((null ispell-filter)
+            (error "%s did not output version line" ispell-program-name))
+           ((and
+             (stringp (car ispell-filter))
+             (if (string-match "warning: " (car ispell-filter))
+                 (progn
+                   (ispell-accept-output 3) ; was warn msg.
+                   (stringp (car ispell-filter)))
+               (null (cdr ispell-filter)))
+             (string-match "^@(#) " (car ispell-filter)))
+            ;; got the version line as expected (we already know it's the right
+            ;; version, so don't bother checking again.)
+            nil)
+           (t
+            ;; Otherwise, it must be an error message.  Show the user.
+            ;; But first wait to see if some more output is going to arrive.
+            ;; Otherwise we get cool errors like "Can't open ".
+            (sleep-for 1)
+            (ispell-accept-output 3)
+            (error "%s" (mapconcat 'identity ispell-filter "\n"))))
+      (setq ispell-filter nil)         ; Discard version ID line
+      (let ((extended-char-mode (ispell-get-extended-character-mode)))
+       (if extended-char-mode          ; ~ extended character mode
+           (ispell-send-string (concat extended-char-mode "\n"))))
+      (if ispell-async-processp
+         (if (featurep 'emacs)
+             (set-process-query-on-exit-flag ispell-process nil)
+           (if (fboundp 'set-process-query-on-exit-flag)
+               (set-process-query-on-exit-flag ispell-process nil)
+             (process-kill-without-query ispell-process)))))))
 
 ;;;###autoload
 (defun ispell-kill-ispell (&optional no-error)
@@ -2716,17 +2762,10 @@ With NO-ERROR, just return non-nil if there was no Ispell running."
       (kill-buffer ispell-session-buffer)
       (setq ispell-output-buffer nil
            ispell-session-buffer nil))
-    (setq ispell-process-buffer-name nil)
     (setq ispell-process nil)
     (message "Ispell process killed")
     nil))
 
-;; Kill ispell process when killing its associated buffer
-(add-hook 'kill-buffer-hook
-         '(lambda ()
-            (if (equal ispell-process-buffer-name (buffer-name))
-                (ispell-kill-ispell t))))
-
 ;;; ispell-change-dictionary is set in some people's hooks.  Maybe this should
 ;;;  call ispell-init-process rather than wait for a spell checking command?
 
@@ -2744,7 +2783,7 @@ By just answering RET you can find out what the current dictionary is."
               (mapcar 'list (ispell-valid-dictionary-list)))
          nil t)
         current-prefix-arg))
-  (ispell-set-spellchecker-params) ; Initilize variables and dicts alists
+  (ispell-set-spellchecker-params) ; Initialize variables and dicts alists
   (unless arg (ispell-buffer-local-dict 'no-reload))
   (if (equal dict "default") (setq dict nil))
   ;; This relies on completing-read's bug of returning "" for no match
@@ -2787,7 +2826,11 @@ a new one will be started when needed."
       (setq ispell-current-dictionary dict
            ispell-current-personal-dictionary pdict))))
 
-;;; Spelling of comments are checked when ispell-check-comments is non-nil.
+;; Avoid error messages when compiling for these dynamic variables.
+(defvar ispell-start)
+(defvar ispell-end)
+
+;; Spelling of comments are checked when ispell-check-comments is non-nil.
 
 ;;;###autoload
 (defun ispell-region (reg-start reg-end &optional recheckp shift)
@@ -2818,14 +2861,14 @@ Return nil if spell session is quit,
              (message "searching for regions to skip"))
            (if (re-search-forward (ispell-begin-skip-region-regexp) reg-end t)
                (progn
-                 (setq key (buffer-substring-no-properties
-                            (match-beginning 0) (match-end 0)))
+                 (setq key (match-string-no-properties 0))
                  (set-marker skip-region-start (- (point) (length key)))
                  (goto-char reg-start)))
            (let (message-log-max)
-             (message "Continuing spelling check using %s with %s dictionary..."
-                      (file-name-nondirectory ispell-program-name)
-                      (or ispell-current-dictionary "default")))
+             (message
+               "Continuing spelling check using %s with %s dictionary..."
+               (file-name-nondirectory ispell-program-name)
+               (or ispell-current-dictionary "default")))
            (set-marker rstart reg-start)
            (set-marker ispell-region-end reg-end)
            (while (and (not ispell-quit)
@@ -2864,18 +2907,19 @@ Return nil if spell session is quit,
                                 (if (marker-position skip-region-start)
                                     (min skip-region-start ispell-region-end)
                                   (marker-position ispell-region-end))))
-             (let* ((start (point))
-                    (end (save-excursion (end-of-line) (min (point) reg-end)))
-                    (string (ispell-get-line start end in-comment)))
+             (let* ((ispell-start (point))
+                    (ispell-end (min (point-at-eol) reg-end))
+                    (string (ispell-get-line
+                              ispell-start ispell-end in-comment)))
                (if in-comment          ; account for comment chars added
-                   (setq start (- start (length in-comment))
+                   (setq ispell-start (- ispell-start (length in-comment))
                          in-comment nil))
-               (setq end (point))      ; "end" tracks region retrieved.
+               (setq ispell-end (point)) ; "end" tracks region retrieved.
                (if string              ; there is something to spell check!
                    ;; (special start end)
                    (setq shift (ispell-process-line string
                                                     (and recheckp shift))))
-               (goto-char end)))))
+               (goto-char ispell-end)))))
        (if ispell-quit
            nil
          (or shift 0)))
@@ -2912,42 +2956,30 @@ Return nil if spell session is quit,
   "Return a regexp of the search keys for region skipping.
 Includes `ispell-skip-region-alist' plus tex, tib, html, and comment keys.
 Must call after `ispell-buffer-local-parsing' due to dependence on mode."
-  ;; start with regions generic to all buffers
-  (let ((skip-regexp (ispell-begin-skip-region ispell-skip-region-alist)))
-    ;; Comments
-    (if (and (null ispell-check-comments) comment-start)
-       (setq skip-regexp (concat (regexp-quote comment-start) "\\|"
-                                 skip-regexp)))
-    (if (and (eq 'exclusive ispell-check-comments) comment-start)
-       ;; search from end of current comment to start of next comment.
-       (setq skip-regexp (concat (if (string= "" comment-end) "^"
-                                   (regexp-quote comment-end))
-                                 "\\|" skip-regexp)))
-    ;; tib
-    (if ispell-skip-tib
-       (setq skip-regexp (concat ispell-tib-ref-beginning "\\|" skip-regexp)))
-    ;; html stuff
-    (if ispell-skip-html
-       (setq skip-regexp (concat
-                          (ispell-begin-skip-region ispell-html-skip-alists)
-                          "\\|"
-                          skip-regexp)))
-    ;; tex
-    (if (eq ispell-parser 'tex)
-       (setq skip-regexp (concat (ispell-begin-tex-skip-regexp) "\\|"
-                                 skip-regexp)))
-    ;; messages
-    (if (and ispell-checking-message
-            (not (eq t ispell-checking-message)))
-       (setq skip-regexp (concat
-                          (mapconcat (lambda (lst) (car lst))
-                                     ispell-checking-message
-                                     "\\|")
-                          "\\|"
-                          skip-regexp)))
-
-    ;; return new regexp
-    skip-regexp))
+  (mapconcat
+   'identity
+   (delq nil
+         (list
+          ;; messages
+          (if (and ispell-checking-message
+                   (not (eq t ispell-checking-message)))
+              (mapconcat #'car ispell-checking-message "\\|"))
+          ;; tex
+          (if (eq ispell-parser 'tex)
+              (ispell-begin-tex-skip-regexp))
+          ;; html stuff
+          (if ispell-skip-html
+              (ispell-begin-skip-region ispell-html-skip-alists))
+          ;; tib
+          (if ispell-skip-tib ispell-tib-ref-beginning)
+          ;; Comments
+          (if (and (eq 'exclusive ispell-check-comments) comment-start)
+              ;; search from end of current comment to start of next comment.
+              (if (string= "" comment-end) "^" (regexp-quote comment-end)))
+          (if (and (null ispell-check-comments) comment-start)
+              (regexp-quote comment-start))
+          (ispell-begin-skip-region ispell-skip-region-alist)))
+   "\\|"))
 
 
 (defun ispell-begin-skip-region (skip-alist)
@@ -3006,7 +3038,7 @@ Must call after `ispell-buffer-local-parsing' due to dependence on mode."
        (while (looking-at "[ \t\n]*\\[") (forward-sexp))
        (forward-sexp (or arg 1)))
     (error
-     (message "error skipping s-expressions at point %d." (point))
+     (message "Error skipping s-expressions at point %d." (point))
      (beep)
      (sit-for 2))))
 
@@ -3090,9 +3122,9 @@ Point is placed at end of skipped region."
          (sit-for 2)))))
 
 
-;;; Grab the next line of data.
-;;; Returns a string with the line data
 (defun ispell-get-line (start end in-comment)
+  "Grab the next line of data.
+Returns a string with the line data."
   (let ((ispell-casechars (ispell-get-casechars))
        string)
     (cond                              ; LOOK AT THIS LINE AND SKIP OR PROCESS
@@ -3119,16 +3151,13 @@ Point is placed at end of skipped region."
                                       (point) (+ (point) len))
                                      coding)))))
 
-;;; Avoid error messages when compiling for these dynamic variables.
-(defvar start)
-(defvar end)
-
 (defun ispell-process-line (string shift)
   "Send STRING, a line of text, to ispell and processes the result.
 This will modify the buffer for spelling errors.
-Requires variables START and END to be defined in its lexical scope.
+Requires variables ISPELL-START and ISPELL-END to be defined in its
+dynamic scope.
 Returns the sum SHIFT due to changes in word replacements."
-  ;;(declare special start end)
+  ;;(declare special ispell-start ispell-end)
   (let (poss accept-list)
     (if (not (numberp shift))
        (setq shift 0))
@@ -3151,10 +3180,10 @@ Returns the sum SHIFT due to changes in word replacements."
          ;; Markers can move with highlighting!  This destroys
          ;; end of region markers line-end and ispell-region-end
          (let ((word-start
-                (copy-marker (+ start ispell-offset (car (cdr poss)))))
+                (copy-marker (+ ispell-start ispell-offset (car (cdr poss)))))
                (word-len (length (car poss)))
-               (line-end (copy-marker end))
-               (line-start (copy-marker start))
+               (line-end (copy-marker ispell-end))
+               (line-start (copy-marker ispell-start))
                recheck-region replace)
            (goto-char word-start)
            ;; Adjust the horizontal scroll & point
@@ -3254,16 +3283,19 @@ Returns the sum SHIFT due to changes in word replacements."
              ;;                           (length (car poss)))))
              ))
            (if (not ispell-quit)
+                ;; FIXME: remove redundancy with identical code above.
                (let (message-log-max)
-                 (message "Continuing spelling check using %s with %s dictionary..."
-                          (file-name-nondirectory ispell-program-name)
-                          (or ispell-current-dictionary "default"))))
+                 (message
+                   "Continuing spelling check using %s with %s dictionary..."
+                   (file-name-nondirectory ispell-program-name)
+                   (or ispell-current-dictionary "default"))))
            (sit-for 0)
-           (setq start (marker-position line-start)
-                 end (marker-position line-end))
+           (setq ispell-start (marker-position line-start)
+                 ispell-end (marker-position line-end))
            ;; Adjust markers when end of region lost from highlighting.
-           (if (and (not recheck-region) (< end (+ word-start word-len)))
-               (setq end (+ word-start word-len)))
+           (if (and (not recheck-region)
+                     (< ispell-end (+ word-start word-len)))
+               (setq ispell-end (+ word-start word-len)))
            (if (= word-start ispell-region-end)
                (set-marker ispell-region-end (+ word-start word-len)))
            ;; going out of scope - unneeded
@@ -3330,7 +3362,7 @@ Returns the sum SHIFT due to changes in word replacements."
 
 
 ;;; Interactive word completion.
-;;; Forces "previous-word" processing.  Do we want to make this selectable?
+;; Forces "previous-word" processing.  Do we want to make this selectable?
 
 ;;;###autoload
 (defun ispell-complete-word (&optional interior-frag)
@@ -3421,15 +3453,6 @@ available on the net."
 ;;;                    Ispell Minor Mode
 ;;; **********************************************************************
 
-(defvar ispell-minor-mode nil
-  "Non-nil if Ispell minor mode is enabled.")
-;; Variable indicating that ispell minor mode is active.
-(make-variable-buffer-local 'ispell-minor-mode)
-
-(or (assq 'ispell-minor-mode minor-mode-alist)
-    (setq minor-mode-alist
-          (cons '(ispell-minor-mode " Spell") minor-mode-alist)))
-
 (defvar ispell-minor-keymap
   (let ((map (make-sparse-keymap)))
     (define-key map " " 'ispell-minor-check)
@@ -3437,28 +3460,24 @@ available on the net."
     map)
   "Keymap used for Ispell minor mode.")
 
-(or (not (boundp 'minor-mode-map-alist))
-    (assoc 'ispell-minor-mode minor-mode-map-alist)
-    (setq minor-mode-map-alist
-          (cons (cons 'ispell-minor-mode ispell-minor-keymap)
-                minor-mode-map-alist)))
-
 ;;;###autoload
-(defun ispell-minor-mode (&optional arg)
-  "Toggle Ispell minor mode.
-With prefix argument ARG, turn Ispell minor mode on if ARG is positive,
-otherwise turn it off.
+(define-minor-mode ispell-minor-mode
+  "Toggle last-word spell checking (Ispell minor mode).
+With a prefix argument ARG, enable Ispell minor mode if ARG is
+positive, and disable it otherwise.  If called from Lisp, enable
+the mode if ARG is omitted or nil.
 
-In Ispell minor mode, pressing SPC or RET
-warns you if the previous word is incorrectly spelled.
+Ispell minor mode is a buffer-local mior mode.  When enabled,
+typing SPC or RET warns you if the previous word is incorrectly
+spelled.
 
-All the buffer-local variables and dictionaries are ignored -- to read
-them into the running ispell process, type \\[ispell-word] SPC."
-  (interactive "P")
-  (setq ispell-minor-mode
-       (not (or (and (null arg) ispell-minor-mode)
-                (<= (prefix-numeric-value arg) 0))))
-  (force-mode-line-update))
+All the buffer-local variables and dictionaries are ignored.  To
+read them into the running ispell process, type \\[ispell-word]
+SPC.
+
+For spell-checking \"on the fly\", not just after typing SPC or
+RET, use `flyspell-mode'."
+  nil " Spell" ispell-minor-keymap)
 
 (defun ispell-minor-check ()
   "Check previous word then continue with the normal binding of this key.
@@ -3724,15 +3743,14 @@ You can bind this to the key C-c i in GNUS or mail by adding to
            (goto-char (point-min))
            ;; Select type or skip checking if this is a non-multipart message
            ;; Point moved to end of buffer if region is encoded.
-           (if (and mimep (not boundary))
-               (let (skip-regexp)      ; protect from `ispell-mime-skip-part'
+           (when (and mimep (not boundary))
                  (goto-char (point-min))
                  (re-search-forward "Content-[^ \t]*:" end-of-headers t)
                  (forward-line -1)     ; following fn starts one line above
                  (ispell-mime-skip-part nil)
                  ;; if message-text-end region, limit may be less than point.
                  (if (> (point) limit)
-                     (set-marker limit (point)))))
+                  (set-marker limit (point))))
            (goto-char (max end-of-headers (point)))
            (forward-line 1)
            (setq case-fold-search old-case-fold-search)
@@ -3798,7 +3816,7 @@ Includes Latex/Nroff modes and extended character mode."
     (goto-char (point-max))
     ;; Uses last occurrence of ispell-parsing-keyword
     (if (search-backward ispell-parsing-keyword nil t)
-       (let ((end (save-excursion (end-of-line) (point)))
+       (let ((end (point-at-eol))
              string)
          (search-forward ispell-parsing-keyword)
          (while (re-search-forward " *\\([^ \"]+\\)" end t)
@@ -3815,7 +3833,7 @@ Includes Latex/Nroff modes and extended character mode."
                     (sit-for 2))))))))
 
 
-;;; Can kill the current ispell process
+;; Can kill the current ispell process
 
 (defun ispell-buffer-local-dict (&optional no-reload)
   "Initializes local dictionary and local personal dictionary.
@@ -3834,7 +3852,7 @@ Both should not be used to define a buffer-local dictionary."
        (if (search-backward ispell-dictionary-keyword nil t)
            (progn
              (search-forward ispell-dictionary-keyword)
-             (setq end (save-excursion (end-of-line) (point)))
+             (setq end (point-at-eol))
              (if (re-search-forward " *\\([^ \"]+\\)" end t)
                  (setq ispell-local-dictionary
                        (match-string-no-properties 1))))))
@@ -3842,7 +3860,7 @@ Both should not be used to define a buffer-local dictionary."
       (if (search-backward ispell-pdict-keyword nil t)
          (progn
            (search-forward ispell-pdict-keyword)
-           (setq end (save-excursion (end-of-line) (point)))
+           (setq end (point-at-eol))
            (if (re-search-forward " *\\([^ \"]+\\)" end t)
                (setq ispell-local-pdict
                      (match-string-no-properties 1)))))))
@@ -3866,7 +3884,7 @@ Both should not be used to define a buffer-local dictionary."
     (while (search-forward ispell-words-keyword nil t)
       (or ispell-buffer-local-name
          (setq ispell-buffer-local-name (buffer-name)))
-      (let ((end (save-excursion (end-of-line) (point)))
+      (let ((end (point-at-eol))
            (ispell-casechars (ispell-get-casechars))
            string)
        ;; buffer-local words separated by a space, and can contain
@@ -3882,22 +3900,23 @@ Both should not be used to define a buffer-local dictionary."
 
 ;;; returns optionally adjusted region-end-point.
 
+;; If comment-padright is defined, newcomment must be loaded.
+(declare-function comment-add "newcomment" (arg))
+
 (defun ispell-add-per-file-word-list (word)
   "Add WORD to the per-file word list."
   (or ispell-buffer-local-name
       (setq ispell-buffer-local-name (buffer-name)))
   (save-excursion
     (goto-char (point-min))
-    (let ((old-case-fold-search case-fold-search)
-         line-okay search done found)
+    (let (line-okay search done found)
       (while (not done)
-       (setq case-fold-search nil
-             search (search-forward ispell-words-keyword nil 'move)
+        (let ((case-fold-search nil))
+          (setq search (search-forward ispell-words-keyword nil 'move)
              found (or found search)
              line-okay (< (+ (length word) 1 ; 1 for space after word..
                              (progn (end-of-line) (current-column)))
-                          80)
-             case-fold-search old-case-fold-search)
+                             fill-column)))
        (if (or (and search line-okay)
                (null search))
            (progn
@@ -3906,8 +3925,18 @@ Both should not be used to define a buffer-local dictionary."
                  (progn
                    (open-line 1)
                    (unless found (newline))
-                   (insert (concat comment-start " " ispell-words-keyword))
-                   (if (> (length comment-end) 0)
+                   (insert (if comment-start
+                                (concat
+                                  (if (fboundp 'comment-padright)
+                                      ;; Try and use the proper comment marker,
+                                      ;; e.g. ";;" rather than ";".
+                                      (comment-padright comment-start
+                                                        (comment-add nil))
+                                    comment-start)
+                                  " ")
+                              "")
+                            ispell-words-keyword)
+                    (if (and comment-end (> (length comment-end) 0))
                        (save-excursion
                          (newline)
                          (insert comment-end)))))
@@ -3952,5 +3981,4 @@ Both should not be used to define a buffer-local dictionary."
 ; LocalWords:  uuencoded unidiff sc nn VM SGML eval IspellPersDict unsplitable
 ; LocalWords:  lns XEmacs HTML casechars Multibyte
 
-;; arch-tag: 4941b9f9-3b7c-4a76-a4ed-5fa8b6010ef5
 ;;; ispell.el ends here