ispell.el 159 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

3
;; Copyright (C) 1994-1995, 1997-2011  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))))

Richard M. Stallman's avatar
Richard M. Stallman committed
257 258
;;; Code:

259 260
(defvar mail-yank-prefix)

261
(defgroup ispell nil
262
  "User variables for Emacs ispell interface."
263
  :group 'applications)
264

265 266 267
(if (not (fboundp 'buffer-substring-no-properties))
    (defun buffer-substring-no-properties (start end)
      (buffer-substring start end)))
268

269
(defalias 'check-ispell-version 'ispell-check-version)
270

271 272 273 274 275 276
;;; **********************************************************************
;;; The following variables should be set according to personal preference
;;; and location of binaries:
;;; **********************************************************************


277
;;;  ******* THIS FILE IS WRITTEN FOR ISPELL VERSION 3.1+
278 279 280 281

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

285 286 287 288 289 290 291 292 293 294 295
(defcustom ispell-lazy-highlight (boundp 'lazy-highlight-cleanup)
  "*Controls the lazy-highlighting of spelling errors.
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)
Stefan Monnier's avatar
Stefan Monnier committed
296
  "*The face used for Ispell highlighting.  For Emacsen with overlays.
Richard M. Stallman's avatar
Richard M. Stallman committed
297 298
Possible values are `highlight', `modeline', `secondary-selection',
`region', and `underline'.
Richard M. Stallman's avatar
Richard M. Stallman committed
299 300
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
301 302 303
slightly different."
  :type 'face
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
304

305
(defcustom ispell-check-comments t
306 307 308 309
  "*Spelling of comments checked when non-nil.
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."
310
  :type '(choice (const exclusive) (const :tag "off" nil) (const :tag "on" t))
311
  :group 'ispell)
312 313 314
;;;###autoload
(put 'ispell-check-comments 'safe-local-variable
     (lambda (a) (memq a '(nil t exclusive))))
Richard M. Stallman's avatar
Richard M. Stallman committed
315

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

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

TeX users beware:  Any field starting with [. will skip until a .] -- even
Richard M. Stallman's avatar
Richard M. Stallman committed
328
your whole buffer -- unless you set `ispell-skip-tib' to nil.  That includes
329 330 331
a [.5mm] type of number...."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
332 333 334 335 336 337 338

(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.")

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

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

351
(defcustom ispell-program-name
352 353 354
  (or (locate-file "aspell"   exec-path exec-suffixes 'file-executable-p)
      (locate-file "ispell"   exec-path exec-suffixes 'file-executable-p)
      (locate-file "hunspell" exec-path exec-suffixes 'file-executable-p)
355
      "ispell")
356 357 358
  "Program invoked by \\[ispell-word] and \\[ispell-region] commands."
  :type 'string
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
359

360
(defcustom ispell-alternate-dictionary
361 362 363 364 365 366
  (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")
367
	 "/usr/share/lib/dict/words")
368 369
	((file-readable-p "/sys/dict") "/sys/dict"))
  "*Alternate plain word-list dictionary for spelling help."
370
  :type '(choice file (const :tag "None" nil))
371
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
372

373 374 375
(defcustom ispell-complete-word-dict nil
  "*Plain word-list dictionary used for word completion if
different from `ispell-alternate-dictionary'."
376
  :type '(choice file (const :tag "None" nil))
377
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
378

379 380 381 382 383 384 385 386 387 388
(defcustom ispell-message-dictionary-alist nil
  "*List used by `ispell-message' to select a new dictionary.
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:
  '((\"^Newsgroups:[ \\t]*de\\\\.\" . \"deutsch8\")
    (\"^To:[^\\n,]+\\\\.de[ \\t\\n,>]\" . \"deutsch8\"))"
  :type '(repeat (cons regexp string))
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
389

390

391 392 393 394 395 396 397
(defcustom ispell-message-fcc-skip 50000
  "*Query before saving Fcc message copy if attachment larger than this value.
Always stores Fcc copy of message when nil."
  :type '(choice integer (const :tag "off" nil))
  :group 'ispell)


398 399 400 401 402
(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")
403 404 405 406
  "Name of the grep command for search processes."
  :type 'string
  :group 'ispell)

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

415 416 417 418 419
(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
420
  "Name of the look command for search processes.
421 422 423
This must be an absolute file name."
  :type 'file
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
424

425
(defcustom ispell-look-p (file-exists-p ispell-look-command)
426
  "*Non-nil means use `look' rather than `grep'.
427 428 429
Default is based on whether `look' seems to be available."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
430

431 432 433 434
(defcustom ispell-have-new-look nil
  "*Non-nil means use the `-r' option (regexp) when running `look'."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
435

436 437 438 439
(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
440

441
(defcustom ispell-use-ptys-p nil
Richard M. Stallman's avatar
Richard M. Stallman committed
442
  "When non-nil, Emacs uses ptys to communicate with Ispell.
443 444 445
When nil, Emacs uses pipes."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
446

447
(defcustom ispell-following-word nil
Richard M. Stallman's avatar
Richard M. Stallman committed
448
  "*Non-nil means `ispell-word' checks the word around or after point.
449 450 451
Otherwise `ispell-word' checks the preceding word."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
452

453
(defcustom ispell-help-in-bufferp nil
Richard M. Stallman's avatar
Richard M. Stallman committed
454
  "*Non-nil means display interactive keymap help in a buffer.
455
The following values are supported:
456 457 458 459
  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.
460
  electric   Pop up a new buffer and display a long help message there.
461
             User can browse and then exit the help mode."
462
  :type '(choice (const electric) (const :tag "off" nil) (const :tag "on" t))
463
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
464

465 466 467 468
(defcustom ispell-quietly nil
  "*Non-nil means suppress messages in `ispell-word'."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
469

470
(defcustom ispell-format-word-function (function upcase)
Richard M. Stallman's avatar
Richard M. Stallman committed
471
  "*Formatting function for displaying word being spell checked.
472 473 474
The function must take one string argument and return a string."
  :type 'function
  :group 'ispell)
475
(defvaralias 'ispell-format-word 'ispell-format-word-function)
Richard M. Stallman's avatar
Richard M. Stallman committed
476

477 478 479 480 481 482 483 484
(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:
  (and window-system (condition-case () (require 'framepop) (error nil)))"
  :type 'boolean
  :group 'ispell)

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

495 496 497 498
(defcustom ispell-silently-savep nil
  "*When non-nil, save the personal dictionary without confirmation."
  :type 'boolean
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
499

500 501
(defvar ispell-local-dictionary-overridden nil
  "Non-nil means the user has explicitly set this buffer's Ispell dictionary.")
502
(make-variable-buffer-local 'ispell-local-dictionary-overridden)
503

504
(defcustom ispell-local-dictionary nil
505 506 507 508
  "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'
509
and `ispell-dictionary-alist'.
510

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

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

523 524 525 526 527 528
(defcustom ispell-dictionary nil
  "Default dictionary to use if `ispell-local-dictionary' is nil."
  :type '(choice string
		 (const :tag "default" nil))
  :group 'ispell)

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

537

538

539
(defcustom ispell-skip-html 'use-mode-name
540 541 542 543 544 545 546 547
  "*Indicates whether ispell should skip spell checking of SGML markup.
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)

548 549
(make-variable-buffer-local 'ispell-skip-html)

550

551
(defcustom ispell-local-dictionary-alist nil
552 553
  "*List of local or customized dictionary definitions.
These can override the values in `ispell-dictionary-alist'.
554

555 556
To make permanent changes to your dictionary definitions, you
will need to make your changes in this variable, save, and then
557
re-start Emacs."
558 559 560 561 562 563 564 565 566 567 568 569
  :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")
570
			       (const "~latin1") (const "~latin3")
571
 			       (const :tag "default" nil))
572
		       (coding-system :tag "Coding System")))
573 574 575
  :group 'ispell)


Stefan Monnier's avatar
Stefan Monnier committed
576
(defvar ispell-dictionary-base-alist
577 578 579 580 581 582
  '((nil
     ;; 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
     ;; just use an approximate regexp.
     "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-B") nil iso-8859-1)
Stefan Monnier's avatar
Stefan Monnier committed
583 584 585 586 587 588 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
    ("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)
621 622 623 624
    ("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
625 626 627 628 629 630 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
    ("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
665 666
     "[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
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
     "[']" 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]"
     "[']" nil ("-C") "~list" iso-8859-1))
  "Base value for `ispell-dictionary-alist'.")

(defvar ispell-dictionary-alist nil
Richard M. Stallman's avatar
Richard M. Stallman committed
691 692 693 694
  "An alist of dictionaries and their associated parameters.

Each element of this list is also a list:

Richard M. Stallman's avatar
Richard M. Stallman committed
695
\(DICTIONARY-NAME CASECHARS NOT-CASECHARS OTHERCHARS MANY-OTHERCHARS-P
696
        ISPELL-ARGS EXTENDED-CHARACTER-MODE CHARACTER-SET\)
Richard M. Stallman's avatar
Richard M. Stallman committed
697

698 699
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
700

701
CASECHARS is a regular expression of valid characters that comprise a word.
Richard M. Stallman's avatar
Richard M. Stallman committed
702 703 704

NOT-CASECHARS is the opposite regexp of CASECHARS.

705 706 707
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,
708
otherwise they become word-breaks.  As an example in English, assume the
709
regular expression \"[']\" for OTHERCHARS.  Then \"they're\" and
710 711
\"Steven's\" are parsed as single words including the \"'\" character, but
\"Stevens'\" does not include the quote character as part of the word.
712
If you want OTHERCHARS to be empty, use the empty string.
Richard M. Stallman's avatar
Richard M. Stallman committed
713 714
Hint: regexp syntax requires the hyphen to be declared first here.

715
CASECHARS, NOT-CASECHARS, and OTHERCHARS must be unibyte strings
716 717 718 719 720
containing bytes of CHARACTER-SET.  In addition, if they contain
a non-ASCII byte, the regular expression must be a single
`character set' construct that doesn't specify a character range
for non-ASCII bytes.

721 722 723
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
724 725 726 727 728

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

EXTENDED-CHARACTER-MODE should be used when dictionaries are used which
729
have been configured in an Ispell affix file.  (For example, umlauts
Richard M. Stallman's avatar
Richard M. Stallman committed
730
can be encoded as \\\"a, a\\\", \"a, ...)  Defaults are ~tex and ~nroff
Richard M. Stallman's avatar
Richard M. Stallman committed
731 732
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
733
but the dictionary can control the extended character mode.
Juanma Barranquero's avatar
Juanma Barranquero committed
734
Both defaults can be overruled in a buffer-local fashion.  See
Richard M. Stallman's avatar
Richard M. Stallman committed
735
`ispell-parsing-keyword' for details on this.
Richard M. Stallman's avatar
Richard M. Stallman committed
736

737 738
CHARACTER-SET used for languages with multibyte characters.

Richard M. Stallman's avatar
Richard M. Stallman committed
739 740
Note that the CASECHARS and OTHERCHARS slots of the alist should
contain the same character set as casechars and otherchars in the
741
LANGUAGE.aff file \(e.g., english.aff\).")
742

743 744
(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.
745 746 747 748
(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
this variable will contain \"--encoding=\" for aspell and \"-i \" for hunspell,
Juanma Barranquero's avatar
Juanma Barranquero committed
749
so UTF-8 or other mime charsets can be selected.  That will be set for hunspell
750 751 752
>=1.1.6 or aspell >= 0.60 in `ispell-check-version'.

For aspell non-nil means to try to automatically find aspell dictionaries.
753 754
Earlier aspell versions do not consistently support UTF-8.  Handling
this would require some extra guessing in `ispell-aspell-find-dictionary'.")
755

756
(defvar ispell-aspell-supports-utf8 nil
Juanma Barranquero's avatar
Juanma Barranquero committed
757
  "Non nil if aspell has consistent command line UTF-8 support.  Obsolete.
758
ispell.el and flyspell.el will use for this purpose the more generic
Juanma Barranquero's avatar
Juanma Barranquero committed
759
variable `ispell-encoding8-command' for both aspell and hunspell.  Is left
760 761 762 763
here just for backwards compatibility.")

(make-obsolete-variable 'ispell-aspell-supports-utf8
                        'ispell-encoding8-command "23.1")
764 765 766 767 768 769


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

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

771

772 773
;; 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.
774 775 776 777 778
(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.")

779
(defconst ispell-version "ispell.el 3.6 - 7-Jan-2003")
780 781


782
(defun ispell-check-version (&optional interactivep)
783 784
  "Ensure that `ispell-program-name' is valid and the correct version.
Returns version number if called interactively.
785
Otherwise returns the library directory name, if that is defined."
786 787 788 789 790 791 792 793
  ;; 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")
794
  (let ((default-directory (or (and (boundp 'temporary-file-directory)
795 796
				    temporary-file-directory)
			       default-directory))
797
	result status ispell-program-version)
798 799

    (with-temp-buffer
800
      (setq status (ispell-call-process
Eli Zaretskii's avatar
Eli Zaretskii committed
801 802 803 804 805 806 807 808
		    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"))))
809 810
      (goto-char (point-min))
      (if interactivep
811
	  ;; report version information of ispell and ispell.el
812 813 814 815 816 817
	  (progn
	    (end-of-line)
	    (setq result (concat (buffer-substring-no-properties (point-min)
								 (point))
				 ", "
				 ispell-version))
Deepak Goel's avatar
Deepak Goel committed
818
	    (message "%s" result))
819
	;; return library directory.
820
	(if (re-search-forward "LIBDIR = \\\"\\([^ \t\n]*\\)\\\"" nil t)
821
	    (setq result (match-string 1))))
822 823 824 825
      (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))
826 827 828 829 830 831 832 833 834 835

      ;; 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
836 837
	      ispell-really-hunspell nil
	      ispell-encoding8-command nil)
838 839 840 841

	(goto-char (point-min))
	(or (setq ispell-really-aspell
		  (and (search-forward-regexp
842
			"(but really Aspell \\([0-9]+\\.[0-9\\.-]+\\)?)" nil t)
843 844 845
		       (match-string 1)))
	    (setq ispell-really-hunspell
		  (and (search-forward-regexp
846 847
			"(but really Hunspell \\([0-9]+\\.[0-9\\.-]+\\)?)"
                        nil t)
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866
		       (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)
867 868 869
		  (progn
		    (setq ispell-aspell-supports-utf8 t)
		    (setq ispell-encoding8-command "--encoding=")))
870 871
	    (setq ispell-really-aspell nil)))
	 (ispell-really-hunspell
872 873 874
	  (if (ispell-check-minver hunspell8-minver ispell-really-hunspell)
	      (setq ispell-encoding8-command "-i ")
	    (setq ispell-really-hunspell nil))))))
875 876
    result))

877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
(defun ispell-call-process (&rest args)
  "Like `call-process' but defend against bad `default-directory'."
  (let ((default-directory default-directory))
    (unless (and (file-directory-p default-directory)
		 (file-readable-p default-directory))
      (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))
    (unless (and (file-directory-p default-directory)
		 (file-readable-p default-directory))
      (setq default-directory (expand-file-name "~/")))
    (apply 'call-process-region args)))

893

894

895 896 897
;; The preparation of the menu bar menu must be autoloaded
;; because otherwise this file gets autoloaded every time Emacs starts
;; so that it can set up the menus and determine keyboard equivalents.
898

899
;;;###autoload
900 901
(defvar ispell-menu-map nil "Key map for ispell menu.")
;;; redo menu when loading ispell to get dictionary modifications
Karl Heuer's avatar
Karl Heuer committed
902
(setq ispell-menu-map nil)
Richard M. Stallman's avatar
Richard M. Stallman committed
903

904
;;;###autoload
905 906 907 908
(defvar ispell-menu-xemacs nil
  "Spelling menu for XEmacs.
If nil when package is loaded, a standard menu will be set,
and added as a submenu of the \"Edit\" menu.")
909

Stefan Monnier's avatar
Stefan Monnier committed
910 911
;; Break out XEmacs menu and split into several calls to avoid having
;; long lines in loaddefs.el.  Detect need off following constant.
912

913
;;; Set up dictionary
914
;;;###autoload
915
(defvar ispell-menu-map-needed
916
  ;; only needed when not version 18 and not XEmacs.
917
  (and (not ispell-menu-map)
918
       (not (featurep 'xemacs))
919 920
       'reload))

921
(defvar ispell-library-directory (condition-case ()
922
				     (ispell-check-version)
923 924
				   (error nil))
  "Directory where ispell dictionaries reside.")
925

926 927 928
(defvar ispell-process nil
  "The process object for Ispell.")

929
(defvar ispell-async-processp (and (fboundp 'delete-process)
930 931 932 933 934 935 936
				   (fboundp 'process-send-string)
				   (fboundp 'accept-process-output)
				   ;;(fboundp 'start-process)
				   ;;(fboundp 'set-process-filter)
				   ;;(fboundp 'process-kill-without-query)
				   )
  "Non-nil means that the OS supports asynchronous processes.")
937

938 939
;; Make ispell.el work better with aspell.

940 941 942
(defvar ispell-aspell-dictionary-alist nil
  "An alist of parsed aspell dicts and associated parameters.
Internal use.")
943

944 945
(defun ispell-find-aspell-dictionaries ()
  "Find Aspell's dictionaries, and record in `ispell-dictionary-alist'."
946
  (unless (and ispell-really-aspell ispell-encoding8-command)
Juanma Barranquero's avatar
Juanma Barranquero committed
947
    (error "This function only works with aspell >= 0.60"))
948 949 950
  (let* ((dictionaries
	  (split-string
	   (with-temp-buffer
951
	     (ispell-call-process ispell-program-name nil t nil "dicts")
952 953 954
	     (buffer-string))))
	 ;; Search for the named dictionaries.
	 (found
955
	  (delq nil
956
		(mapcar #'ispell-aspell-find-dictionary dictionaries))))
957 958 959
    ;; Ensure aspell's alias dictionary will override standard
    ;; definitions.
    (setq found (ispell-aspell-add-aliases found))
960
    ;; Merge into FOUND any elements from the standard ispell-dictionary-alist
961
    ;; which have no element in FOUND at all.
962 963 964
    (dolist (dict ispell-dictionary-alist)
      (unless (assoc (car dict) found)
	(setq found (nconc found (list dict)))))
965
    (setq ispell-aspell-dictionary-alist found)
966
    ;; Add a default entry
967 968
    (let ((default-dict
           '(nil "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-B") nil utf-8)))
969
      (push default-dict ispell-aspell-dictionary-alist))))
970 971 972 973 974 975 976 977 978 979 980

(defvar ispell-aspell-data-dir nil
  "Data directory of Aspell.")

(defvar ispell-aspell-dict-dir nil
  "Dictionary directory of Aspell.")

(defun ispell-get-aspell-config-value (key)
  "Return value of Aspell configuration option KEY.
Assumes that value contains no whitespace."
  (with-temp-buffer