ispell.el 182 KB
Newer Older
1
;;; ispell.el --- interface to International Ispell Versions 3.1 and 3.2
Richard M. Stallman's avatar
Richard M. Stallman committed
2

Paul Eggert's avatar
Paul Eggert committed
3
;; Copyright (C) 1994-1995, 1997-2016 Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
4

5 6
;; Author:           Ken Stevens <k.stevens@ieee.org>
;; Maintainer:       Ken Stevens <k.stevens@ieee.org>
7 8
;; Stevens Mod Date: Mon Jan  7 12:32:44 PST 2003
;; Stevens Revision: 3.6
9
;; Status          : Release with 3.1.12+ and 3.2.0+ ispell.
10 11
;; Bug Reports     : ispell-el-bugs@itcorp.com
;; Web Site        : http://kdstevens.com/~stevens/ispell-page.html
Dave Love's avatar
Dave Love committed
12
;; Keywords: unix wp
Richard M. Stallman's avatar
Richard M. Stallman committed
13

Erik Naggum's avatar
Erik Naggum committed
14 15
;; This file is part of GNU Emacs.

16
;; GNU Emacs is free software: you can redistribute it and/or modify
Erik Naggum's avatar
Erik Naggum committed
17
;; it under the terms of the GNU General Public License as published by
18 19
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
Erik Naggum's avatar
Erik Naggum committed
20 21 22 23 24 25 26

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
27
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
Erik Naggum's avatar
Erik Naggum committed
28 29

;; Note: version numbers and time stamp are not updated
Stefan Monnier's avatar
Stefan Monnier committed
30
;;   when this file is edited for release with GNU Emacs.
Richard M. Stallman's avatar
Richard M. Stallman committed
31

Richard M. Stallman's avatar
Richard M. Stallman committed
32 33
;;; Commentary:

Erik Naggum's avatar
Erik Naggum committed
34
;; INSTRUCTIONS
35

36 37 38 39
;;   This code contains a section of user-settable variables that you
;; should inspect prior to installation.  Look past the end of the history
;; list.  Set them up for your locale and the preferences of the majority
;; of the users.  Otherwise the users may need to set a number of variables
Erik Naggum's avatar
Erik Naggum committed
40
;; themselves.
41
;;   You particularly may want to change the default dictionary for your
Erik Naggum's avatar
Erik Naggum committed
42
;; country and language.
43 44
;;   Most dictionary changes should be made in this file so all users can
;; enjoy them.  Local or modified dictionaries are supported in your .emacs
45 46
;; file.  Use the variable `ispell-local-dictionary-alist' to specify
;; your own dictionaries.
47

Erik Naggum's avatar
Erik Naggum committed
48 49 50 51
;;  Depending on the mail system you use, you may want to include these:
;;  (add-hook 'news-inews-hook 'ispell-message)
;;  (add-hook 'mail-send-hook  'ispell-message)
;;  (add-hook 'mh-before-send-letter-hook 'ispell-message)
52

53
;;   Ispell has a TeX parser and a nroff parser (the default).
Erik Naggum's avatar
Erik Naggum committed
54 55 56
;; The parsing is controlled by the variable ispell-parser.  Currently
;; it is just a "toggle" between TeX and nroff, but if more parsers are
;; added it will be updated.  See the variable description for more info.
57 58


Erik Naggum's avatar
Erik Naggum committed
59
;; TABLE OF CONTENTS
60

Erik Naggum's avatar
Erik Naggum committed
61 62 63 64
;;   ispell-word
;;   ispell-region
;;   ispell-buffer
;;   ispell-message
65
;;   ispell-comments-and-strings
Erik Naggum's avatar
Erik Naggum committed
66 67 68 69 70 71
;;   ispell-continue
;;   ispell-complete-word
;;   ispell-complete-word-interior-frag
;;   ispell-change-dictionary
;;   ispell-kill-ispell
;;   ispell-pdict-save
72 73
;;   ispell-skip-region-alist

Erik Naggum's avatar
Erik Naggum committed
74 75
;; Commands in ispell-region:
;; Character replacement: Replace word with choice.  May query-replace.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
;; ` ': Accept word this time.
;; `i': Accept word and insert into private dictionary.
;; `a': Accept word for this session.
;; `A': Accept word and place in buffer-local dictionary.
;; `r': Replace word with typed-in value.  Rechecked.
;; `R': Replace word with typed-in value. Query-replaced in buffer. Rechecked.
;; `?': Show these commands
;; `x': Exit spelling buffer.  Move cursor to original point.
;; `X': Exit spelling buffer.  Leaves cursor at the current point, and permits
;;      the check to be completed later.
;; `q': Quit spelling session (Kills ispell process).
;; `l': Look up typed-in replacement in alternate dictionary.  Wildcards okay.
;; `u': Like `i', but the word is lower-cased first.
;; `m': Place entered value in personal dictionary, then recheck current word.
;; `C-l': redraws screen
;; `C-r': recursive edit
Stefan Monnier's avatar
Stefan Monnier committed
92
;; `C-z': suspend Emacs or iconify frame
93

Erik Naggum's avatar
Erik Naggum committed
94 95 96 97 98 99 100 101
;; Buffer-Local features:
;; There are a number of buffer-local features that can be used to customize
;;  ispell for the current buffer.  This includes language dictionaries,
;;  personal dictionaries, parsing, and local word spellings.  Each of these
;;  local customizations are done either through local variables, or by
;;  including the keyword and argument(s) at the end of the buffer (usually
;;  prefixed by the comment characters).  See the end of this file for
;;  examples.  The local keywords and variables are:
102

Erik Naggum's avatar
Erik Naggum committed
103 104 105 106 107 108
;;  ispell-dictionary-keyword   language-dictionary
;;      uses local variable ispell-local-dictionary
;;  ispell-pdict-keyword        personal-dictionary
;;      uses local variable ispell-local-pdict
;;  ispell-parsing-keyword      mode-arg extended-char-arg
;;  ispell-words-keyword        any number of local word spellings
109 110 111 112 113 114 115

;; Region skipping:
;;  Place new regular expression definitions of regions you prefer not to
;;  spell check in `ispell-skip-region-alist'.  Mode-dependent features can
;;  be added to latex by modifying `ispell-tex-skip-alists'.
;;  `ispell-message' contains some custom skipping code for e-mail messages.

Erik Naggum's avatar
Erik Naggum committed
116
;; BUGS:
117 118 119
;;  Need a way to select between different character mappings without separate
;;    dictionary entries.
;;  Multi-byte characters if not defined by current dictionary may result in the
Stefan Monnier's avatar
Stefan Monnier committed
120 121
;;    evil "misalignment error" in some versions of MULE Emacs.
;;  On some versions of Emacs, growing the minibuffer fails.
122
;;    see `ispell-help-in-bufferp'.
123 124
;;  Recursive edits (?C-r or ?R) inside a keyboard text replacement check (?r)
;;    can cause misalignment errors.
125 126 127 128 129

;; HISTORY

;; Modifications made in latest versions:

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
;; Revision 3.6 2003/01/07 12:32:44	kss
;; Removed extra -d LIB in dictionary defs. (Pavel Janik)
;; Filtered process calls with duplicate dictionary entries.
;; Fixed bug where message-text-end is inside a mime skipped region.
;; Minor fixes to get ispell menus right in XEmacs
;; Fixed skip regexp so it doesn't match stuff like `/.\w'.
;; Detecting dictionary change not working.  Fixed.  kss
;; function `ispell-change-dictionary' now only completes valid dicts.

;; Revision 3.5 2001/7/11 18:43:57	kss
;; Added fix for aspell to work in XEmacs (ispell-check-version).
;; Added Portuguese dictionary definition.
;; New feature: MIME mail message support, Fcc support.
;; Bug fix: retain comment syntax on lines with region skipping. (TeX $ bug...)
;; Improved allocation for graphic mode lines.  (Miles Bader)
;; Support -v flag for old versions of aspell.  (Eli Zaretskii)
;; Clear minibuffer on ^G from ispell-help (Tak Ota)

148 149 150 151 152 153 154 155
;; Revision 3.4 2000/8/4 09:41:50	kss
;; Support new color display functions.
;; Fixed misalignment offset bug when replacing a string after a shift made.
;; Set to standard Author/Maintainer heading,
;; ensure localwords lists are separated from the text by newline. (Dave Love)
;; Added dictionary definition for Italian (William Deakin)
;; HTML region skipping greatly improved. (Chuck D. Phillips)
;; improved menus.  Fixed regexp matching http/email addresses.
Stefan Monnier's avatar
Stefan Monnier committed
156
;; one arg always for XEmacs sleep-for (gunnar Evermann)
157 158
;; support for synchronous processes (Eli Zaretskii)

159 160 161 162 163 164 165 166 167 168 169
;; Revision 3.3  1999/11/29 11:38:34     kss
;; Only word replacements entered in from the keyboard are rechecked.
;; This fixes a bug in tex parsing and misalignment.
;; Exceptions exist for recursive edit and query-replace, with tex error
;; condition tested.  Recursive editing improved.
;; XEmacs repair for when `enable-multibyte-characters' defined - Didier Verna.
;; ispell-help fixed for XEmacs.  Choices minibuffer now displayed in XEmacs.
;; Only list valid dictionaries in Spell menu.  Russian dictionary doesn't allow
;; run-together words, and uses koi8-r font.  Don't skip text in html <TT>
;; fonts.

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
;; Revision 3.2  1999/5/7 14:25:14	kss
;; Accept ispell versions 3.X.Y where X>=1
;; fine tuned latex region skipping.  Fixed bug in ispell-word that did not
;; point in right place on words < 2 chars.  Simplified ispell-minor-mode.
;; Fixed bug in TeX parsing when math commands are in the comments.
;; Removed calls to `when' macro.

;; Revision 3.1  1998/12/1 13:21:52	kss
;; Improved and fixed customize support.
;; Improved and fixed comments in variables and messages.
;; A coding system is now required for all languages.
;; casechars improved for castellano, castellano8, and norsk dictionaries.
;; Dictionary norsk7-tex removed.  Dictionary polish added.
;; Dictionaries redefined at load-time to support dictionary changes.
;; Menu redefined at load time to support dictionary changes.
;; ispell-check-version added as an alias for `check-ispell-version'.
;; Spelling suggestions returned in order generated by ispell.
;; Small bug fixed in matching ispell error messages.
;; Robustness added to ensure `case-fold-search' doesn't get redefined.
;; Fixed bug that didn't respect case of word in `ispell-complete-word'.
;; Multibyte character coding support added for process interactions.
;; Ensure ispell process has terminated before starting new process.
;;  This can otherwise confuse process filters and hang ispell.
193
;; Improved skipping support for SGML.
194 195 196
;; Fixed bug using ^M rather than \r in `ispell-minor-check'.
;; Improved message reference matching in `ispell-message'.
;; Fixed bug in returning to nroff mode from tex mode.
Richard M. Stallman's avatar
Richard M. Stallman committed
197

198
;;; Compatibility code for XEmacs and (not too) older emacsen:
199

200
(eval-and-compile ;; Protect against declare-function undefined in XEmacs
201 202
  (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))

Glenn Morris's avatar
Glenn Morris committed
203
(declare-function ispell-check-minver "ispell" (v1 v2))
204 205
(declare-function ispell-looking-back "ispell"
		  (regexp &optional limit &rest ignored))
Glenn Morris's avatar
Glenn Morris committed
206

207 208 209 210
(if (fboundp 'version<=)
    (defalias 'ispell-check-minver 'version<=)
  (defun ispell-check-minver (minver version)
    "Check if string VERSION is at least string MINVER.
211 212
Both must be in [0-9]+.[0-9]+... format.  This is a fallback
compatibility function in case `version<=' is not available."
213 214 215 216 217 218 219 220 221 222
    (let ((pending t)
	  (return t)
	  start-ver start-mver)
      ;; Loop until an absolute greater or smaller condition is reached
      ;; or until no elements are left in any of version and minver. In
      ;; this case version is exactly the minimal, so return OK.
      (while pending
	(let (ver mver)
	  (if (string-match "[0-9]+" version start-ver)
	      (setq start-ver (match-end 0)
223
		    ver (string-to-number (match-string 0 version))))
224 225
	  (if (string-match "[0-9]+" minver start-mver)
	      (setq start-mver (match-end 0)
226
		    mver (string-to-number (match-string 0 minver))))
227 228 229 230 231 232 233 234 235 236 237 238 239 240

	  (if (or ver mver)
	      (progn
		(or ver  (setq ver 0))
		(or mver (setq mver 0))
		;; If none of below conditions match, this element is the
		;; same. Go checking next element.
		(if (> ver mver)
		    (setq pending nil)
		  (if (< ver mver)
		      (setq pending nil
			    return nil))))
	    (setq pending nil))))
      return)))
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
;; XEmacs does not have looking-back
(if (fboundp 'looking-back)
    (defalias 'ispell-looking-back 'looking-back)
  (defun ispell-looking-back (regexp &optional limit &rest ignored)
    "Return non-nil if text before point matches regular expression REGEXP.
Like `looking-at' except matches before point, and is slower.
LIMIT if non-nil speeds up the search by specifying a minimum
starting position, to avoid checking matches that would start
before LIMIT.

This is a stripped down compatibility function for use when
full featured `looking-back' function is missing."
    (save-excursion
      (re-search-backward (concat "\\(?:" regexp "\\)\\=") limit t))))

257 258 259
;;; XEmacs21 does not have `with-no-warnings'. Taken from org mode.
(defmacro ispell-with-no-warnings (&rest body)
  (cons (if (fboundp 'with-no-warnings) 'with-no-warnings 'progn) body))
260

Richard M. Stallman's avatar
Richard M. Stallman committed
261 262
;;; Code:

263 264
(defvar mail-yank-prefix)

265
(defgroup ispell nil
266
  "User variables for Emacs ispell interface."
267
  :group 'applications)
268

269 270 271
(if (not (fboundp 'buffer-substring-no-properties))
    (defun buffer-substring-no-properties (start end)
      (buffer-substring start end)))
272

273
(defalias 'check-ispell-version 'ispell-check-version)
274

275 276 277 278 279 280
;;; **********************************************************************
;;; The following variables should be set according to personal preference
;;; and location of binaries:
;;; **********************************************************************


281
;;;  ******* THIS FILE IS WRITTEN FOR ISPELL VERSION 3.1+
282 283

(defcustom ispell-highlight-p 'block
284
  "Highlight spelling errors when non-nil.
285
When set to `block', assumes a block cursor with TTY displays."
286
  :type '(choice (const block) (const :tag "off" nil) (const :tag "on" t))
287 288
  :group 'ispell)

289
(defcustom ispell-lazy-highlight (boundp 'lazy-highlight-cleanup)
290
  "Controls the lazy-highlighting of spelling errors.
291 292 293 294 295 296 297 298 299
When non-nil, all text in the buffer matching the current spelling
error is highlighted lazily using isearch lazy highlighting (see
`lazy-highlight-initial-delay' and `lazy-highlight-interval')."
  :type 'boolean
  :group 'lazy-highlight
  :group 'ispell
  :version "22.1")

(defcustom ispell-highlight-face (if ispell-lazy-highlight 'isearch 'highlight)
300
  "Face used for Ispell highlighting.
Richard M. Stallman's avatar
Richard M. Stallman committed
301 302
This variable can be set by the user to whatever face they desire.
It's most convenient if the cursor color and highlight color are
303 304 305
slightly different."
  :type 'face
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
306

307
(defcustom ispell-check-comments t
308
  "Spelling of comments checked when non-nil.
309 310 311
When set to `exclusive', ONLY comments are checked.  (For code comments).
Warning!  Not checking comments, when a comment start is embedded in strings,
may produce undesired results."
312
  :type '(choice (const exclusive) (const :tag "off" nil) (const :tag "on" t))
313
  :group 'ispell)
314 315 316
;;;###autoload
(put 'ispell-check-comments 'safe-local-variable
     (lambda (a) (memq a '(nil t exclusive))))
Richard M. Stallman's avatar
Richard M. Stallman committed
317

318
(defcustom ispell-query-replace-choices nil
319
  "Corrections made throughout region when non-nil.
320 321 322
Uses `query-replace' (\\[query-replace]) for corrections."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
323

324
(defcustom ispell-skip-tib nil
325
  "Does not spell check `tib' bibliography references when non-nil.
Richard M. Stallman's avatar
Richard M. Stallman committed
326
Skips any text between strings matching regular expressions
Richard M. Stallman's avatar
Richard M. Stallman committed
327
`ispell-tib-ref-beginning' and `ispell-tib-ref-end'.
Richard M. Stallman's avatar
Richard M. Stallman committed
328

Eli Zaretskii's avatar
Eli Zaretskii committed
329 330 331
TeX users beware:  Any text between [. and .] will be skipped -- even if
that's your whole buffer -- unless you set `ispell-skip-tib' to nil.
That includes the [.5mm] type of number..."
332 333
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
334 335 336 337 338 339 340

(defvar ispell-tib-ref-beginning "[[<]\\."
  "Regexp matching the beginning of a Tib reference.")

(defvar ispell-tib-ref-end "\\.[]>]"
  "Regexp matching the end of a Tib reference.")

341
(defcustom ispell-keep-choices-win t
342
  "If non-nil, keep the `*Choices*' window for the entire spelling session.
343 344 345
This minimizes redisplay thrashing."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
346

347
(defcustom ispell-choices-win-default-height 2
348
  "The default size of the `*Choices*' window, including the mode line.
349
Must be greater than 1."
350 351
  :type 'integer
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
352

353
(defcustom ispell-program-name
354 355 356
  (or (executable-find "aspell")
      (executable-find "ispell")
      (executable-find "hunspell")
357
      "ispell")
358 359
  "Program invoked by \\[ispell-word] and \\[ispell-region] commands."
  :type 'string
360 361 362 363
  :set (lambda (symbol value)
         (set-default symbol value)
         (if (featurep 'ispell)
             (ispell-set-spellchecker-params)))
364
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
365

366
(defcustom ispell-alternate-dictionary
367 368 369 370 371 372
  (cond ((file-readable-p "/usr/dict/web2") "/usr/dict/web2")
	((file-readable-p "/usr/share/dict/web2") "/usr/share/dict/web2")
	((file-readable-p "/usr/dict/words") "/usr/dict/words")
	((file-readable-p "/usr/lib/dict/words") "/usr/lib/dict/words")
	((file-readable-p "/usr/share/dict/words") "/usr/share/dict/words")
	((file-readable-p "/usr/share/lib/dict/words")
373
	 "/usr/share/lib/dict/words")
374
	((file-readable-p "/sys/dict") "/sys/dict"))
375
  "Alternate plain word-list dictionary for spelling help."
376
  :type '(choice file (const :tag "None" nil))
377
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
378

379
(defcustom ispell-complete-word-dict nil
380
  "Plain word-list dictionary used for word completion if
381
different from `ispell-alternate-dictionary'."
382
  :type '(choice file (const :tag "None" nil))
383
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
384

385
(defcustom ispell-message-dictionary-alist nil
386
  "List used by `ispell-message' to select a new dictionary.
387 388 389 390
It consists of pairs (REGEXP . DICTIONARY).  If REGEXP is found
in the message headers, `ispell-local-dictionary' will be set to
DICTIONARY if `ispell-local-dictionary' is not buffer-local.
E.g. you may use the following value:
391
   ((\"^Newsgroups:[ \\t]*de\\\\.\" . \"deutsch8\")
392 393 394
    (\"^To:[^\\n,]+\\\\.de[ \\t\\n,>]\" . \"deutsch8\"))"
  :type '(repeat (cons regexp string))
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
395

396

397
(defcustom ispell-message-fcc-skip 50000
398
  "Query before saving Fcc message copy if attachment larger than this value.
399 400 401 402 403
Always stores Fcc copy of message when nil."
  :type '(choice integer (const :tag "off" nil))
  :group 'ispell)


404 405 406 407 408
(defcustom ispell-grep-command
  ;; MS-Windows/MS-DOS have `egrep' as a Unix shell script, so they
  ;; cannot invoke it.  Use "grep -E" instead (see ispell-grep-options
  ;; below).
  (if (memq system-type '(windows-nt ms-dos)) "grep" "egrep")
409 410 411 412
  "Name of the grep command for search processes."
  :type 'string
  :group 'ispell)

413 414
(defcustom ispell-grep-options
  (if (memq system-type '(windows-nt ms-dos)) "-Ei" "-i")
Richard M. Stallman's avatar
Richard M. Stallman committed
415
  "String of options to use when running the program in `ispell-grep-command'.
Richard M. Stallman's avatar
Richard M. Stallman committed
416
Should probably be \"-i\" or \"-e\".
Juanma Barranquero's avatar
Juanma Barranquero committed
417
Some machines (like the NeXT) don't support \"-i\"."
418 419
  :type 'string
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
420

421 422 423 424 425
(defcustom ispell-look-command
  (cond ((file-exists-p "/bin/look") "/bin/look")
	((file-exists-p "/usr/local/bin/look") "/usr/local/bin/look")
	((file-exists-p "/usr/bin/look") "/usr/bin/look")
	(t "look"))
Richard M. Stallman's avatar
Richard M. Stallman committed
426
  "Name of the look command for search processes.
427 428 429
This must be an absolute file name."
  :type 'file
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
430

431
(defcustom ispell-look-p (file-exists-p ispell-look-command)
432
  "Non-nil means use `look' rather than `grep'.
433 434 435
Default is based on whether `look' seems to be available."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
436

437
(defcustom ispell-have-new-look nil
438
  "Non-nil means use the `-r' option (regexp) when running `look'."
439 440
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
441

442 443 444 445
(defcustom ispell-look-options (if ispell-have-new-look "-dfr" "-df")
  "String of command options for `ispell-look-command'."
  :type 'string
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
446

447
(defcustom ispell-use-ptys-p nil
Richard M. Stallman's avatar
Richard M. Stallman committed
448
  "When non-nil, Emacs uses ptys to communicate with Ispell.
449 450 451
When nil, Emacs uses pipes."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
452

453
(defcustom ispell-following-word nil
454
  "Non-nil means `ispell-word' checks the word around or after point.
455 456 457
Otherwise `ispell-word' checks the preceding word."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
458

459
(defcustom ispell-help-in-bufferp nil
460
  "Non-nil means display interactive keymap help in a buffer.
461
The following values are supported:
462 463 464 465
  nil        Expand the minibuffer and display a short help message
             there for a couple of seconds.
  t          Pop up a new buffer and display a short help message there
             for a couple of seconds.
466
  electric   Pop up a new buffer and display a long help message there.
467
             User can browse and then exit the help mode."
468
  :type '(choice (const electric) (const :tag "off" nil) (const :tag "on" t))
469
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
470

471
(defcustom ispell-quietly nil
472
  "Non-nil means suppress messages in `ispell-word'."
473 474
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
475

476
(defcustom ispell-format-word-function (function upcase)
477
  "Formatting function for displaying word being spell checked.
478 479 480
The function must take one string argument and return a string."
  :type 'function
  :group 'ispell)
481
(defvaralias 'ispell-format-word 'ispell-format-word-function)
Richard M. Stallman's avatar
Richard M. Stallman committed
482

483 484 485 486
(defcustom ispell-use-framepop-p nil
  "When non-nil ispell uses framepop to display choices in a dedicated frame.
You can set this variable to dynamically use framepop if you are in a
window system by evaluating the following on startup to set this variable:
487
  (and window-system (condition-case () (require \\='framepop) (error nil)))"
488 489 490
  :type 'boolean
  :group 'ispell)

491
;;;###autoload
492
(defcustom ispell-personal-dictionary nil
493
  "File name of your personal spelling dictionary, or nil.
494
If nil, the default personal dictionary, (\"~/.ispell_DICTNAME\" for ispell or
495
\"~/.aspell.LANG.pws\" for Aspell) is used, where DICTNAME is the name of your
496
default dictionary and LANG the two letter language code."
497 498
  :type '(choice file
		 (const :tag "default" nil))
499
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
500

501
(defcustom ispell-silently-savep nil
502
  "When non-nil, save personal dictionary without asking for confirmation."
503 504
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
505

506 507
(defvar ispell-local-dictionary-overridden nil
  "Non-nil means the user has explicitly set this buffer's Ispell dictionary.")
508
(make-variable-buffer-local 'ispell-local-dictionary-overridden)
509

510
(defcustom ispell-local-dictionary nil
511 512 513 514
  "If non-nil, the dictionary to be used for Ispell commands in this buffer.
The value must be a string dictionary name,
or nil, which means use the global setting in `ispell-dictionary'.
Dictionary names are defined in `ispell-local-dictionary-alist'
515
and `ispell-dictionary-alist'.
516

517
Setting `ispell-local-dictionary' to a value has the same effect as
518 519
calling \\[ispell-change-dictionary] with that value.  This variable
is automatically set when defined in the file with either
520
`ispell-dictionary-keyword' or the Local Variable syntax."
521 522 523
  :type '(choice string
		 (const :tag "default" nil))
  :group 'ispell)
524 525
;;;###autoload
(put 'ispell-local-dictionary 'safe-local-variable 'string-or-null-p)
526 527 528

(make-variable-buffer-local 'ispell-local-dictionary)

529 530 531 532 533 534
(defcustom ispell-dictionary nil
  "Default dictionary to use if `ispell-local-dictionary' is nil."
  :type '(choice string
		 (const :tag "default" nil))
  :group 'ispell)

535
(defcustom ispell-extra-args nil
536
  "If non-nil, a list of extra switches to pass to the Ispell program.
537
For example, (\"-W\" \"3\") to cause it to accept all 1-3 character
Richard M. Stallman's avatar
Richard M. Stallman committed
538
words as correct.  See also `ispell-dictionary-alist', which may be used
539 540 541
for language-specific arguments."
  :type '(repeat string)
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
542

543

544

545
(defcustom ispell-skip-html 'use-mode-name
546
  "Indicates whether ispell should skip spell checking of SGML markup.
547 548 549 550 551 552 553
If t, always skip SGML markup; if nil, never skip; if non-t and non-nil,
guess whether SGML markup should be skipped according to the name of the
buffer's major mode."
  :type '(choice (const :tag "always" t) (const :tag "never" nil)
		 (const :tag "use-mode-name" use-mode-name))
  :group 'ispell)

554 555
(make-variable-buffer-local 'ispell-skip-html)

556

557
(defcustom ispell-local-dictionary-alist nil
558
  "List of local or customized dictionary definitions.
559
These can override the values in `ispell-dictionary-alist'.
560

561 562
To make permanent changes to your dictionary definitions, you
will need to make your changes in this variable, save, and then
563
re-start Emacs."
564 565 566 567 568 569 570 571 572 573 574 575
  :type '(repeat (list (choice :tag "Dictionary"
			       (string :tag "Dictionary name")
			       (const :tag "default" nil))
		       (regexp :tag "Case characters")
		       (regexp :tag "Non case characters")
		       (regexp :tag "Other characters")
		       (boolean :tag "Many other characters")
		       (repeat :tag "Ispell command line args"
			       (string :tag "Arg"))
		       (choice :tag "Extended character mode"
			       (const "~tex") (const "~plaintex")
			       (const "~nroff") (const "~list")
576
			       (const "~latin1") (const "~latin3")
577
 			       (const :tag "default" nil))
578
		       (coding-system :tag "Coding System")))
579 580 581
  :group 'ispell)


Stefan Monnier's avatar
Stefan Monnier committed
582
(defvar ispell-dictionary-base-alist
583
  '((nil                                ; default
584 585 586
     ;; The default dictionary.  It may be English.aff, or any other
     ;; dictionary depending on locale and such things.  We should probably
     ;; ask ispell what dictionary it's using, but until we do that, let's
587 588
     ;; just use a minimal regexp. [:alpha:] will later be set if possible.
     "[A-Za-z]" "[^A-Za-z]" "[']" nil ("-B") nil iso-8859-1)
Stefan Monnier's avatar
Stefan Monnier committed
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
    ("american"				; Yankee English
     "[A-Za-z]" "[^A-Za-z]" "[']" nil ("-B") nil iso-8859-1)
    ("brasileiro"			; Brazilian mode
     "[A-Z\301\311\315\323\332\300\310\314\322\331\303\325\307\334\302\312\324a-z\341\351\355\363\372\340\350\354\362\371\343\365\347\374\342\352\364]"
     "[^A-Z\301\311\315\323\332\300\310\314\322\331\303\325\307\334\302\312\324a-z\341\351\355\363\372\340\350\354\362\371\343\365\347\374\342\352\364]"
     "[']" nil nil nil iso-8859-1)
    ("british"				; British version
     "[A-Za-z]" "[^A-Za-z]" "[']" nil ("-B") nil iso-8859-1)
    ("castellano"			; Spanish mode
     "[A-Z\301\311\315\321\323\332\334a-z\341\351\355\361\363\372\374]"
     "[^A-Z\301\311\315\321\323\332\334a-z\341\351\355\361\363\372\374]"
     "[-]" nil ("-B") "~tex" iso-8859-1)
    ("castellano8"			; 8 bit Spanish mode
     "[A-Z\301\311\315\321\323\332\334a-z\341\351\355\361\363\372\374]"
     "[^A-Z\301\311\315\321\323\332\334a-z\341\351\355\361\363\372\374]"
     "[-]" nil ("-B" "-d" "castellano") "~latin1" iso-8859-1)
    ("czech"
     "[A-Za-z\301\311\314\315\323\332\331\335\256\251\310\330\317\253\322\341\351\354\355\363\372\371\375\276\271\350\370\357\273\362]"
     "[^A-Za-z\301\311\314\315\323\332\331\335\256\251\310\330\317\253\322\341\351\354\355\363\372\371\375\276\271\350\370\357\273\362]"
     "" nil ("-B") nil iso-8859-2)
    ("dansk"				; Dansk.aff
     "[A-Z\306\330\305a-z\346\370\345]" "[^A-Z\306\330\305a-z\346\370\345]"
     "[']" nil ("-C") nil iso-8859-1)
    ("deutsch"				; Deutsch.aff
     "[a-zA-Z\"]" "[^a-zA-Z\"]" "[']" t ("-C") "~tex" iso-8859-1)
    ("deutsch8"
     "[a-zA-Z\304\326\334\344\366\337\374]"
     "[^a-zA-Z\304\326\334\344\366\337\374]"
     "[']" t ("-C" "-d" "deutsch") "~latin1" iso-8859-1)
    ("english"				; make English explicitly selectable
     "[A-Za-z]" "[^A-Za-z]" "[']" nil ("-B") nil iso-8859-1)
    ("esperanto"
     "[A-Za-z\246\254\266\274\306\330\335\336\346\370\375\376]"
     "[^A-Za-z\246\254\266\274\306\330\335\336\346\370\375\376]"
     "[-']" t ("-C") "~latin3" iso-8859-3)
    ("esperanto-tex"
     "[A-Za-z^\\]" "[^A-Za-z^\\]"
     "[-'`\"]" t ("-C" "-d" "esperanto") "~tex" iso-8859-3)
627 628 629 630
    ("finnish"
     "[A-Za-z\345\344\366\305\304\326]"
     "[^A-Za-z\345\344\366\305\304\326]"
     "[:]" nil ("-C") "~list" iso-8859-1)
Stefan Monnier's avatar
Stefan Monnier committed
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
    ("francais7"
     "[A-Za-z]" "[^A-Za-z]" "[`'^-]" t nil nil iso-8859-1)
    ("francais"				; Francais.aff
     "[A-Za-z\300\302\306\307\310\311\312\313\316\317\324\331\333\334\340\342\347\350\351\352\353\356\357\364\371\373\374]"
     "[^A-Za-z\300\302\306\307\310\311\312\313\316\317\324\331\333\334\340\342\347\350\351\352\353\356\357\364\371\373\374]"
     "[-'.@]" t nil "~list" iso-8859-1)
    ("francais-tex"			; Francais.aff
     "[A-Za-z\300\302\306\307\310\311\312\313\316\317\324\331\333\334\340\342\347\350\351\352\353\356\357\364\371\373\374\\]"
     "[^A-Za-z\300\302\306\307\310\311\312\313\316\317\324\331\333\334\340\342\347\350\351\352\353\356\357\364\371\373\374\\]"
     "[-'^`\".@]" t nil "~tex" iso-8859-1)
    ("german"				; german.aff
     "[a-zA-Z\"]" "[^a-zA-Z\"]" "[']" t ("-C") "~tex" iso-8859-1)
    ("german8"				; german.aff
     "[a-zA-Z\304\326\334\344\366\337\374]"
     "[^a-zA-Z\304\326\334\344\366\337\374]"
     "[']" t ("-C" "-d" "german") "~latin1" iso-8859-1)
    ("italiano"				; Italian.aff
     "[A-Z\300\301\310\311\314\315\322\323\331\332a-z\340\341\350\351\354\355\363\371\372]"
     "[^A-Z\300\301\310\311\314\315\322\323\331\332a-z\340\341\350\351\354\355\363\371\372]"
     "[-.]" nil ("-B" "-d" "italian") "~tex" iso-8859-1)
    ("nederlands"			; Nederlands.aff
     "[A-Za-z\300\301\302\303\304\305\307\310\311\312\313\314\315\316\317\322\323\324\325\326\331\332\333\334\340\341\342\343\344\345\347\350\351\352\353\354\355\356\357\361\362\363\364\365\366\371\372\373\374]"
     "[^A-Za-z\300\301\302\303\304\305\307\310\311\312\313\314\315\316\317\322\323\324\325\326\331\332\333\334\340\341\342\343\344\345\347\350\351\352\353\354\355\356\357\361\362\363\364\365\366\371\372\373\374]"
     "[']" t ("-C") nil iso-8859-1)
    ("nederlands8"			; Dutch8.aff
     "[A-Za-z\300\301\302\303\304\305\307\310\311\312\313\314\315\316\317\322\323\324\325\326\331\332\333\334\340\341\342\343\344\345\347\350\351\352\353\354\355\356\357\361\362\363\364\365\366\371\372\373\374]"
     "[^A-Za-z\300\301\302\303\304\305\307\310\311\312\313\314\315\316\317\322\323\324\325\326\331\332\333\334\340\341\342\343\344\345\347\350\351\352\353\354\355\356\357\361\362\363\364\365\366\371\372\373\374]"
     "[']" t ("-C") nil iso-8859-1)
    ("norsk"				; 8 bit Norwegian mode
     "[A-Za-z\305\306\307\310\311\322\324\330\345\346\347\350\351\362\364\370]"
     "[^A-Za-z\305\306\307\310\311\322\324\330\345\346\347\350\351\362\364\370]"
     "[\"]" nil nil "~list" iso-8859-1)
    ("norsk7-tex"			; 7 bit Norwegian TeX mode
     "[A-Za-z{}\\'^`]" "[^A-Za-z{}\\'^`]"
     "[\"]" nil ("-d" "norsk") "~plaintex" iso-8859-1)
    ("polish"				; Polish mode
     "[A-Za-z\241\243\246\254\257\261\263\266\274\277\306\312\321\323\346\352\361\363]"
     "[^A-Za-z\241\243\246\254\257\261\263\266\274\277\306\312\321\323\346\352\361\363]"
     "[.]" nil nil nil iso-8859-2)
    ("portugues"                        ; Portuguese mode
671 672
     "[a-zA-Z\301\302\307\311\323\340\341\342\351\352\355\363\343\347\372]"
     "[^a-zA-Z\301\302\307\311\323\340\341\342\351\352\355\363\343\347\372]"
Stefan Monnier's avatar
Stefan Monnier committed
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
     "[']" t ("-C") "~latin1" iso-8859-1)
    ("russian"				; Russian.aff (KOI8-R charset)
     "[\341\342\367\347\344\345\263\366\372\351\352\353\354\355\356\357\360\362\363\364\365\346\350\343\376\373\375\370\371\377\374\340\361\301\302\327\307\304\305\243\326\332\311\312\313\314\315\316\317\320\322\323\324\325\306\310\303\336\333\335\330\331\337\334\300\321]"
     "[^\341\342\367\347\344\345\263\366\372\351\352\353\354\355\356\357\360\362\363\364\365\346\350\343\376\373\375\370\371\377\374\340\361\301\302\327\307\304\305\243\326\332\311\312\313\314\315\316\317\320\322\323\324\325\306\310\303\336\333\335\330\331\337\334\300\321]"
     "" nil nil nil koi8-r)
    ("russianw"				; russianw.aff (CP1251 charset)
     "[\300\301\302\303\304\305\250\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\334\333\332\335\336\337\340\341\342\343\344\345\270\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\374\373\372\375\376\377]"
     "[^\300\301\302\303\304\305\250\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\334\333\332\335\336\337\340\341\342\343\344\345\270\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\374\373\372\375\376\377]"
     "" nil nil nil windows-1251)
    ("slovak"				; Slovakian
     "[A-Za-z\301\304\311\315\323\332\324\300\305\245\335\256\251\310\317\253\322\341\344\351\355\363\372\364\340\345\265\375\276\271\350\357\273\362]"
     "[^A-Za-z\301\304\311\315\323\332\324\300\305\245\335\256\251\310\317\253\322\341\344\351\355\363\372\364\340\345\265\375\276\271\350\357\273\362]"
     "" nil ("-B") nil iso-8859-2)
    ("slovenian"                        ; Slovenian
     "[A-Za-z\301\304\311\315\323\332\324\300\305\245\335\256\251\310\317\253\322\341\344\351\355\363\372\364\340\345\265\375\276\271\350\357\273\362]"
     "[^A-Za-z\301\304\311\315\323\332\324\300\305\245\335\256\251\310\317\253\322\341\344\351\355\363\372\364\340\345\265\375\276\271\350\357\273\362]"
     "" nil ("-B" "-d" "slovenian") nil iso-8859-2)
    ("svenska"				; Swedish mode
     "[A-Za-z\345\344\366\351\340\374\350\346\370\347\305\304\326\311\300\334\310\306\330\307]"
     "[^A-Za-z\345\344\366\351\340\374\350\346\370\347\305\304\326\311\300\334\310\306\330\307]"
693 694
     "[']" nil ("-C") "~list" iso-8859-1)
    ("hebrew" "[\340\341\342\343\344\345\346\347\350\351\353\352\354\356\355\360\357\361\362\364\363\367\366\365\370\371\372]" "[^\340\341\342\343\344\345\346\347\350\351\353\352\354\356\355\360\357\361\362\364\363\367\366\365\370\371\372]" "" nil ("-B") nil cp1255))
Stefan Monnier's avatar
Stefan Monnier committed
695 696 697
  "Base value for `ispell-dictionary-alist'.")

(defvar ispell-dictionary-alist nil
Richard M. Stallman's avatar
Richard M. Stallman committed
698 699 700 701
  "An alist of dictionaries and their associated parameters.

Each element of this list is also a list:

702 703
 (DICTIONARY-NAME CASECHARS NOT-CASECHARS OTHERCHARS MANY-OTHERCHARS-P
        ISPELL-ARGS EXTENDED-CHARACTER-MODE CHARACTER-SET)
Richard M. Stallman's avatar
Richard M. Stallman committed
704

705 706
DICTIONARY-NAME is a possible string value of variable `ispell-dictionary',
nil means the default dictionary.
Richard M. Stallman's avatar
Richard M. Stallman committed
707

708
CASECHARS is a regular expression of valid characters that comprise a word.
Richard M. Stallman's avatar
Richard M. Stallman committed
709 710 711

NOT-CASECHARS is the opposite regexp of CASECHARS.

712 713 714
OTHERCHARS is a regexp of characters in the NOT-CASECHARS set but which can be
used to construct words in some special way.  If OTHERCHARS characters follow
and precede characters from CASECHARS, they are parsed as part of a word,
715
otherwise they become word-breaks.  As an example in English, assume the
716
regular expression \"[']\" for OTHERCHARS.  Then \"they're\" and
717 718
\"Steven's\" are parsed as single words including the \"'\" character, but
\"Stevens'\" does not include the quote character as part of the word.
719
If you want OTHERCHARS to be empty, use the empty string.
Richard M. Stallman's avatar
Richard M. Stallman committed
720 721
Hint: regexp syntax requires the hyphen to be declared first here.

722
CASECHARS, NOT-CASECHARS, and OTHERCHARS must be unibyte strings
723
containing bytes of CHARACTER-SET.  In addition, if they contain
Eli Zaretskii's avatar
Eli Zaretskii committed
724
non-ASCII bytes, the regular expression must be a single
725 726 727
`character set' construct that doesn't specify a character range
for non-ASCII bytes.

728 729 730
MANY-OTHERCHARS-P is non-nil when multiple OTHERCHARS are allowed in a word.
Otherwise only a single OTHERCHARS character is allowed to be part of any
single word.
Richard M. Stallman's avatar
Richard M. Stallman committed
731 732 733 734 735

ISPELL-ARGS is a list of additional arguments passed to the ispell
subprocess.

EXTENDED-CHARACTER-MODE should be used when dictionaries are used which
736
have been configured in an Ispell affix file.  (For example, umlauts
Richard M. Stallman's avatar
Richard M. Stallman committed
737
can be encoded as \\\"a, a\\\", \"a, ...)  Defaults are ~tex and ~nroff
Richard M. Stallman's avatar
Richard M. Stallman committed
738 739
in English.  This has the same effect as the command-line `-T' option.
The buffer Major Mode controls Ispell's parsing in tex or nroff mode,
Richard M. Stallman's avatar
Richard M. Stallman committed
740
but the dictionary can control the extended character mode.
Juanma Barranquero's avatar
Juanma Barranquero committed
741
Both defaults can be overruled in a buffer-local fashion.  See
Richard M. Stallman's avatar
Richard M. Stallman committed
742
`ispell-parsing-keyword' for details on this.
Richard M. Stallman's avatar
Richard M. Stallman committed
743

Eli Zaretskii's avatar
Eli Zaretskii committed
744 745
CHARACTER-SET used to encode text sent to the ispell subprocess
when the language uses non-ASCII characters.
746

Eli Zaretskii's avatar
Eli Zaretskii committed
747 748 749
Note that with \"ispell\" as the speller, 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.,
750
english.aff).  Aspell and Hunspell don't have this limitation.")
751

752
(defvar ispell-really-aspell nil
753
  "Non-nil if we can use Aspell extensions.")
754
(defvar ispell-really-hunspell nil
755
  "Non-nil if we can use Hunspell extensions.")
756
(defvar ispell-encoding8-command nil
Eli Zaretskii's avatar
Eli Zaretskii committed
757 758
  "Command line option prefix to select encoding if supported, nil otherwise.
If setting the encoding is supported by spellchecker and is selectable from
759 760 761 762
the command line, this variable will contain \"--encoding=\" for Aspell
and \"-i \" for Hunspell, so the appropriate mime charset can be selected.
That will be set in `ispell-check-version' for Hunspell >= 1.1.6 and
Aspell >= 0.60.
Eli Zaretskii's avatar
Eli Zaretskii committed
763

764
For Aspell, non-nil also means to try to automatically find its dictionaries.
Eli Zaretskii's avatar
Eli Zaretskii committed
765

766
Earlier Aspell versions do not consistently support charset encoding.  Handling
767
this would require some extra guessing in `ispell-aspell-find-dictionary'.")
768

769
(defvar ispell-aspell-supports-utf8 nil
770
  "Non-nil if Aspell has consistent command line UTF-8 support.  Obsolete.
771
ispell.el and flyspell.el will use for this purpose the more generic
772
variable `ispell-encoding8-command' for both Aspell and Hunspell.  Is left
773 774 775 776
here just for backwards compatibility.")

(make-obsolete-variable 'ispell-aspell-supports-utf8
                        'ispell-encoding8-command "23.1")
777

778
(defvar ispell-dicts-name2locale-equivs-alist
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
  '(("american"      "en_US")
    ("brasileiro"    "pt_BR")
    ("british"       "en_GB")
    ("castellano"    "es_ES")
    ("castellano8"   "es_ES")
    ("czech"         "cs_CZ")
    ("dansk"         "da_DK")
    ("deutsch"       "de_DE")
    ("deutsch8"      "de_DE")
    ("english"       "en_US")
    ("esperanto"     "eo")
    ("esperanto-tex" "eo")
    ("finnish"       "fi_FI")
    ("francais7"     "fr_FR")
    ("francais"      "fr_FR")
    ("francais-tex"  "fr_FR")
    ("german"        "de_DE")
    ("german8"       "de_DE")
    ("italiano"      "it_IT")
    ("nederlands"    "nl_NL")
    ("nederlands8"   "nl_NL")
    ("norsk"         "nn_NO")
    ("norsk7-tex"    "nn_NO")
    ("polish"        "pl_PL")
    ("portugues"     "pt_PT")
    ("russian"       "ru_RU")
    ("russianw"      "ru_RU")
    ("slovak"        "sk_SK")
    ("slovenian"     "sl_SI")
    ("svenska"       "sv_SE")
    ("hebrew"        "he_IL"))
810
  "Alist with known matching locales for standard dict names in
811 812
  `ispell-dictionary-base-alist'.")

813 814 815 816 817 818
(defvar ispell-emacs-alpha-regexp
  (if (string-match "^[[:alpha:]]+$" "abcde")
      "[[:alpha:]]"
    nil)
  "[[:alpha:]] if Emacs supports [:alpha:] regexp, nil
otherwise (current XEmacs does not support it).")
819 820 821 822 823

;;; **********************************************************************
;;; The following are used by ispell, and should not be changed.
;;; **********************************************************************

Richard M. Stallman's avatar
Richard M. Stallman committed
824

825

826 827
;; 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.
828 829 830 831 832
(defconst ispell-required-version '(3 1 12)
  "Ispell versions with which this version of ispell.el is known to work.")
(defvar ispell-offset -1
  "Offset that maps protocol differences between ispell 3.1 versions.")

833
(defconst ispell-version "ispell.el 3.6 - 7-Jan-2003")
834 835


836
(defun ispell-check-version (&optional interactivep)
Eli Zaretskii's avatar
Eli Zaretskii committed
837
  "Ensure that `ispell-program-name' is valid and has the correct version.
838
Returns version number if called interactively.
839
Otherwise returns the library directory name, if that is defined."
840 841 842 843 844 845 846 847
  ;; This is a little wasteful as we actually launch ispell twice: once
  ;; to make sure it's the right version, and once for real.  But people
  ;; get confused by version mismatches *all* the time (and I've got the
  ;; email to prove it) so I think this is worthwhile.  And the -v[ersion]
  ;; option is the only way I can think of to do this that works with
  ;; all versions, since versions earlier than 3.0.09 didn't identify
  ;; themselves on startup.
  (interactive "p")
848
  (let ((default-directory (or (and (boundp 'temporary-file-directory)
849 850
				    temporary-file-directory)
			       default-directory))
851
	result status ispell-program-version)
852 853

    (with-temp-buffer
854
      (setq status (ispell-call-process
Eli Zaretskii's avatar
Eli Zaretskii committed
855 856 857 858 859 860 861 862
		    ispell-program-name nil t nil
		    ;; aspell doesn't accept the -vv switch.
		    (let ((case-fold-search
			   (memq system-type '(ms-dos windows-nt)))
			  (speller
			   (file-name-nondirectory ispell-program-name)))
		      ;; Assume anything that isn't `aspell' is Ispell.
		      (if (string-match "\\`aspell" speller) "-v" "-vv"))))
863 864
      (goto-char (point-min))
      (if interactivep
865
	  ;; Report version information of ispell and ispell.el
866 867 868 869 870 871
	  (progn
	    (end-of-line)
	    (setq result (concat (buffer-substring-no-properties (point-min)
								 (point))
				 ", "
				 ispell-version))
Deepak Goel's avatar
Deepak Goel committed
872
	    (message "%s" result))
873
	;; return library directory.
874
	(if (re-search-forward "LIBDIR = \\\"\\([^ \t\n]*\\)\\\"" nil t)
875
	    (setq result (match-string 1))))
876 877 878 879
      (goto-char (point-min))
      (if (not (memq status '(0 nil)))
	  (error "%s exited with %s %s" ispell-program-name
		 (if (stringp status) "signal" "code") status))
880 881 882 883 884 885 886 887 888 889

      ;; Get relevant version strings. Only xx.yy.... format works well
      (let (case-fold-search)
	(setq ispell-program-version
	      (and (search-forward-regexp "\\([0-9]+\\.[0-9\\.]+\\)" nil t)
		   (match-string 1)))

	;; Make sure these variables are (re-)initialized to the default value
	(setq ispell-really-aspell nil
	      ispell-aspell-supports-utf8 nil
890 891
	      ispell-really-hunspell nil
	      ispell-encoding8-command nil)
892 893 894 895

	(goto-char (point-min))
	(or (setq ispell-really-aspell
		  (and (search-forward-regexp
896
			"(but really Aspell \\([0-9]+\\.[0-9\\.-]+\\)?)" nil t)
897 898 899
		       (match-string 1)))
	    (setq ispell-really-hunspell
		  (and (search-forward-regexp
900 901
			"(but really Hunspell \\([0-9]+\\.[0-9\\.-]+\\)?)"
                        nil t)
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
		       (match-string 1)))))

      (let ((aspell-minver    "0.50")
	    (aspell8-minver   "0.60")
	    (ispell0-minver   "3.1.0")
	    (ispell-minver    "3.1.12")
	    (hunspell8-minver "1.1.6"))

	(if (ispell-check-minver ispell0-minver ispell-program-version)
	    (or (ispell-check-minver ispell-minver ispell-program-version)
		(setq ispell-offset 0))
	  (error "%s release %s or greater is required"
		 ispell-program-name
		 ispell-minver))

	(cond
	 (ispell-really-aspell
	  (if (ispell-check-minver aspell-minver ispell-really-aspell)
	      (if (ispell-check-minver aspell8-minver ispell-really-aspell)
921 922 923
		  (progn
		    (setq ispell-aspell-supports-utf8 t)
		    (setq ispell-encoding8-command "--encoding=")))
924 925
	    (setq ispell-really-aspell nil)))
	 (ispell-really-hunspell
926
	  (if (ispell-check-minver hunspell8-minver ispell-really-hunspell)
927
	      (setq ispell-encoding8-command "-i")
928
	    (setq ispell-really-hunspell nil))))))
929 930
    result))

931 932 933
(defun ispell-call-process (&rest args)
  "Like `call-process' but defend against bad `default-directory'."
  (let ((default-directory default-directory))
934
    (unless (file-accessible-directory-p default-directory)
935 936 937 938 939 940
      (setq default-directory (expand-file-name "~/")))
    (apply 'call-process args)))

(defun ispell-call-process-region (&rest args)
  "Like `call-process-region' but defend against bad `default-directory'."
  (let ((default-directory default-directory))
941
    (unless (file-accessible-directory-p default-directory)
942 943 944
      (setq default-directory (expand-file-name "~/")))
    (apply 'call-process-region args)))

945 946
(defun ispell-create-debug-buffer (&optional append)
  "Create an ispell debug buffer for debugging output.
947
If APPEND is non-nil, append the info to previous buffer if exists,