ispell.el 156 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, 1998, 1999, 2000, 2001, 2002, 2003,
Glenn Morris's avatar
Glenn Morris committed
4
;;   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
5

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

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

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

;; 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
28
;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
Erik Naggum's avatar
Erik Naggum committed
29 30

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

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

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

37 38 39 40
;;   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
41
;; themselves.
42
;;   You particularly may want to change the default dictionary for your
Erik Naggum's avatar
Erik Naggum committed
43
;; country and language.
44 45
;;   Most dictionary changes should be made in this file so all users can
;; enjoy them.  Local or modified dictionaries are supported in your .emacs
46 47
;; file.  Use the variable `ispell-local-dictionary-alist' to specify
;; your own dictionaries.
48

Erik Naggum's avatar
Erik Naggum committed
49 50 51 52
;;  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)
53

54
;;   Ispell has a TeX parser and a nroff parser (the default).
Erik Naggum's avatar
Erik Naggum committed
55 56 57
;; 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.
58 59


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

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

Erik Naggum's avatar
Erik Naggum committed
75 76
;; Commands in ispell-region:
;; Character replacement: Replace word with choice.  May query-replace.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
;; ` ': 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
93
;; `C-z': suspend Emacs or iconify frame
94

Erik Naggum's avatar
Erik Naggum committed
95 96 97 98 99 100 101 102
;; 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:
103

Erik Naggum's avatar
Erik Naggum committed
104 105 106 107 108 109
;;  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
110 111 112 113 114 115 116

;; 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
117
;; BUGS:
118 119 120
;;  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
121 122
;;    evil "misalignment error" in some versions of MULE Emacs.
;;  On some versions of Emacs, growing the minibuffer fails.
123
;;    see `ispell-help-in-bufferp'.
124 125
;;  Recursive edits (?C-r or ?R) inside a keyboard text replacement check (?r)
;;    can cause misalignment errors.
126 127 128 129 130

;; HISTORY

;; Modifications made in latest versions:

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
;; 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)

149 150 151 152 153 154 155 156
;; 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
157
;; one arg always for XEmacs sleep-for (gunnar Evermann)
158 159
;; support for synchronous processes (Eli Zaretskii)

160 161 162 163 164 165 166 167 168 169 170
;; 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.

171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
;; 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.
194
;; Improved skipping support for SGML.
195 196 197
;; 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
198

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

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

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

208 209 210 211
(if (fboundp 'version<=)
    (defalias 'ispell-check-minver 'version<=)
  (defun ispell-check-minver (minver version)
    "Check if string VERSION is at least string MINVER.
212 213
Both must be in [0-9]+.[0-9]+... format.  This is a fallback
compatibility function in case `version<=' is not available."
214 215 216 217 218 219 220 221 222 223
    (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)
Glenn Morris's avatar
Glenn Morris committed
224
		    ver (string-to-number (substring version (match-beginning 0) (match-end 0)))))
225 226
	  (if (string-match "[0-9]+" minver start-mver)
	      (setq start-mver (match-end 0)
Glenn Morris's avatar
Glenn Morris committed
227
		    mver (string-to-number (substring minver (match-beginning 0) (match-end 0)))))
228 229 230 231 232 233 234 235 236 237 238 239 240 241

	  (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)))
242

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
;; 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
258 259
;;; Code:

260 261
(defvar mail-yank-prefix)

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

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

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

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


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

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

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

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

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

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

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

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

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

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

350
(defcustom ispell-program-name
351 352 353
  (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)
354
      "ispell")
355 356 357
  "Program invoked by \\[ispell-word] and \\[ispell-region] commands."
  :type 'string
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
358

359
(defcustom ispell-alternate-dictionary
Richard M. Stallman's avatar
Richard M. Stallman committed
360
  (cond ((file-exists-p "/usr/dict/web2") "/usr/dict/web2")
361
	((file-exists-p "/usr/share/dict/web2") "/usr/share/dict/web2")
Richard M. Stallman's avatar
Richard M. Stallman committed
362 363
	((file-exists-p "/usr/dict/words") "/usr/dict/words")
	((file-exists-p "/usr/lib/dict/words") "/usr/lib/dict/words")
364
	((file-exists-p "/usr/share/dict/words") "/usr/share/dict/words")
365 366
	((file-exists-p "/usr/share/lib/dict/words")
	 "/usr/share/lib/dict/words")
Richard M. Stallman's avatar
Richard M. Stallman committed
367 368
	((file-exists-p "/sys/dict") "/sys/dict")
	(t "/usr/dict/words"))
369
  "*Alternate 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
(defcustom ispell-complete-word-dict ispell-alternate-dictionary
  "*Dictionary used for word completion."
375
  :type '(choice file (const :tag "None" nil))
376
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
377

378 379 380 381 382 383 384 385 386 387
(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
388

389

390 391 392 393 394 395 396
(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)


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

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

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

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

430 431 432 433
(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
434

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

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

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

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

464 465 466 467
(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
468

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

476 477 478 479 480 481 482 483
(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)

484
;;;###autoload
485
(defcustom ispell-personal-dictionary nil
486
  "*File name of your personal spelling dictionary, or nil.
487 488 489
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."
490 491
  :type '(choice file
		 (const :tag "default" nil))
492
  :group 'ispell)
Richard M. Stallman's avatar
Richard M. Stallman committed
493

494 495 496 497
(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
498

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

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

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

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

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

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

535

536

537
(defcustom ispell-skip-html 'use-mode-name
538 539 540 541 542 543 544 545
  "*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)

546 547
(make-variable-buffer-local 'ispell-skip-html)

548

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

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


Stefan Monnier's avatar
Stefan Monnier committed
574
(defvar ispell-dictionary-base-alist
575 576 577 578 579 580
  '((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
581 582 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 621 622 623 624 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 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
    ("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)
    ("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
     "[a-zA-Z\301\302\311\323\340\341\342\351\352\355\363\343\372]"
     "[^a-zA-Z\301\302\311\323\340\341\342\351\352\355\363\343\372]"
     "[']" 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
685 686 687 688
  "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
689
\(DICTIONARY-NAME CASECHARS NOT-CASECHARS OTHERCHARS MANY-OTHERCHARS-P
690
        ISPELL-ARGS EXTENDED-CHARACTER-MODE CHARACTER-SET\)
Richard M. Stallman's avatar
Richard M. Stallman committed
691

692 693
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
694

695
CASECHARS is a regular expression of valid characters that comprise a word.
Richard M. Stallman's avatar
Richard M. Stallman committed
696 697 698

NOT-CASECHARS is the opposite regexp of CASECHARS.

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

709
CASECHARS, NOT-CASECHARS, and OTHERCHARS must be unibyte strings
710 711 712 713 714
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.

715 716 717
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
718 719 720 721 722

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

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

731 732
CHARACTER-SET used for languages with multibyte characters.

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

737 738
(defvar ispell-really-aspell nil)   ; Non-nil if aspell extensions should be used
(defvar ispell-really-hunspell nil) ; Non-nil if hunspell extensions should be used
739 740 741 742 743 744 745 746
(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,
so UTF-8 or other mime charsets can be selected. That will be set for hunspell
>=1.1.6 or aspell >= 0.60 in `ispell-check-version'.

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

750 751 752 753 754 755 756 757
(defvar ispell-aspell-supports-utf8 nil
  "Non nil if aspell has consistent command line UTF-8 support. Obsolete.
ispell.el and flyspell.el will use for this purpose the more generic
variable `ispell-encoding8-command' for both aspell and hunspell. Is left
here just for backwards compatibility.")

(make-obsolete-variable 'ispell-aspell-supports-utf8
                        'ispell-encoding8-command "23.1")
758 759 760 761 762 763


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

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

765 766 767 768 769 770 771 772

;;; The version must be 3.1 or greater for this version of ispell.el
;;; There is an incompatibility between version 3.1.12 and lower versions.
(defconst ispell-required-version '(3 1 12)
  "Ispell versions with which this version of ispell.el is known to work.")
(defvar ispell-offset -1
  "Offset that maps protocol differences between ispell 3.1 versions.")

773
(defconst ispell-version "ispell.el 3.6 - 7-Jan-2003")
774 775


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

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

      ;; 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
830 831
	      ispell-really-hunspell nil
	      ispell-encoding8-command nil)
832 833 834 835

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

871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886
(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)))

887

888

889 890 891
;; 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.
892

893
;;;###autoload
894 895
(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
896
(setq ispell-menu-map nil)
Richard M. Stallman's avatar
Richard M. Stallman committed
897

898
;;;###autoload
899 900 901 902
(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.")
903

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

907
;;; Set up dictionary
908
;;;###autoload
909
(defvar ispell-menu-map-needed
910
  ;; only needed when not version 18 and not XEmacs.
911
  (and (not ispell-menu-map)
912
       (not (featurep 'xemacs))
913 914
       'reload))

915
(defvar ispell-library-directory (condition-case ()
916
				     (ispell-check-version)
917 918
				   (error nil))
  "Directory where ispell dictionaries reside.")
919

920 921 922
(defvar ispell-process nil
  "The process object for Ispell.")

923
(defvar ispell-async-processp (and (fboundp 'delete-process)
924 925 926 927 928 929 930
				   (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.")
931

932 933
;; Make ispell.el work better with aspell.

934 935 936
(defvar ispell-aspell-dictionary-alist nil
  "An alist of parsed aspell dicts and associated parameters.
Internal use.")
937

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

(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
974
    (ispell-call-process ispell-program-name nil t nil "config" key)
975 976 977
    (car (split-string (buffer-string)))))

(defun ispell-aspell-find-dictionary (dict-name)
978 979 980
  ;; This returns nil if the data file does not exist.
  ;; Can someone please explain the return value format when the
  ;; file does exist -- rms?
981 982 983 984 985 986 987 988 989
  (let* ((lang ;; Strip out region, variant, etc.
	  (and (string-match "^[[:alpha:]]+" dict-name)
	       (match-string 0 dict-name)))
	 (data-file
	  (concat (or ispell-aspell-data-dir
		      (setq ispell-aspell-data-dir
			    (ispell-get-aspell-config-value "data-dir")))
		  "/" lang ".dat"))
	 otherchars)
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006