diff options
| author | Richard M. Stallman | 1994-03-02 04:56:25 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-03-02 04:56:25 +0000 |
| commit | 007852e00dd83cb828dece3bf0727089d7f63d26 (patch) | |
| tree | 9f1453b9d40eed711110fd0fe8ed1dd7b9f4380e | |
| parent | 2bd866cdc65aace6afefe78bcf6dde48eb1ef8a0 (diff) | |
| download | emacs-007852e00dd83cb828dece3bf0727089d7f63d26.tar.gz emacs-007852e00dd83cb828dece3bf0727089d7f63d26.zip | |
Initial revision
| -rw-r--r-- | lisp/textmodes/ispell.el | 1990 |
1 files changed, 1990 insertions, 0 deletions
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el new file mode 100644 index 00000000000..57c174c630e --- /dev/null +++ b/lisp/textmodes/ispell.el | |||
| @@ -0,0 +1,1990 @@ | |||
| 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;; -*- Mode: emacs-lisp -*- ;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2 | ;;; GNU EMACS interface for International Ispell Version 3.1 by Geoff Kuenning. | ||
| 3 | ;;; | ||
| 4 | ;;; | ||
| 5 | ;;; Copyright (C) 1994 Free Software Foundation, Inc. | ||
| 6 | ;;; | ||
| 7 | ;;; | ||
| 8 | ;;; Authors : Ken Stevens et. al. | ||
| 9 | ;;; Last Modified By: Ken Stevens <k.stevens@ieee.org> | ||
| 10 | ;;; Last Modified On: Tue Feb 15 16:11:14 MST 1994 | ||
| 11 | ;;; Update Revision : 2.26 | ||
| 12 | ;;; Syntax : emacs-lisp | ||
| 13 | ;;; Status : Release with 3.1.03 ispell. | ||
| 14 | ;;; Version : International Ispell Version 3.1 by Geoff Kuenning. | ||
| 15 | ;;; | ||
| 16 | ;;; This file is part of GNU Emacs. | ||
| 17 | ;;; | ||
| 18 | ;;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 19 | ;;; it under the terms of the GNU General Public License as published by | ||
| 20 | ;;; the Free Software Foundation; either version 2, or (at your option) | ||
| 21 | ;;; any later version. | ||
| 22 | ;;; | ||
| 23 | ;;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 24 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 25 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 26 | ;;; GNU General Public License for more details. | ||
| 27 | ;;; | ||
| 28 | ;;; You should have received a copy of the GNU General Public License | ||
| 29 | ;;; along with GNU Emacs; see the file COPYING. If not, write to | ||
| 30 | ;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 31 | ;;; | ||
| 32 | ;;; Commentary: | ||
| 33 | ;;; | ||
| 34 | ;;; INSTRUCTIONS | ||
| 35 | ;;; | ||
| 36 | ;;; This code contains a section of user-settable variables that you should | ||
| 37 | ;;; inspect prior to installation. Look past the end of the history list. | ||
| 38 | ;;; Set them up for your locale and the preferences of the majority of the | ||
| 39 | ;;; users. Otherwise the users may need to set a number of variables | ||
| 40 | ;;; themselves. | ||
| 41 | ;;; You particularly may want to change the default dictionary for your | ||
| 42 | ;;; country and language. | ||
| 43 | ;;; | ||
| 44 | ;;; | ||
| 45 | ;;; To fully install this, add this file to your GNU lisp directory and | ||
| 46 | ;;; compile it with M-X byte-compile-file. Then add the following to the | ||
| 47 | ;;; appropriate init file: | ||
| 48 | ;;; | ||
| 49 | ;;; (autoload 'ispell-word "ispell" | ||
| 50 | ;;; "Check the spelling of word in buffer." t) | ||
| 51 | ;;; (global-set-key "\e$" 'ispell-word) | ||
| 52 | ;;; (autoload 'ispell-region "ispell" | ||
| 53 | ;;; "Check the spelling of region." t) | ||
| 54 | ;;; (autoload 'ispell-buffer "ispell" | ||
| 55 | ;;; "Check the spelling of buffer." t) | ||
| 56 | ;;; (autoload 'ispell-complete-word "ispell" | ||
| 57 | ;;; "Look up current word in dictionary and try to complete it." t) | ||
| 58 | ;;; (autoload 'ispell-change-dictionary "ispell" | ||
| 59 | ;;; "Change ispell dictionary." t) | ||
| 60 | ;;; (autoload 'ispell-message "ispell" | ||
| 61 | ;;; "Check spelling of mail message or news post.") | ||
| 62 | ;;; | ||
| 63 | ;;; Depending on the mail system you use, you may want to include these: | ||
| 64 | ;;; | ||
| 65 | ;;; (add-hook 'news-inews-hook 'ispell-message) | ||
| 66 | ;;; (add-hook 'mail-send-hook 'ispell-message) | ||
| 67 | ;;; (add-hook 'mh-before-send-letter-hook 'ispell-message) | ||
| 68 | ;;; | ||
| 69 | ;;; | ||
| 70 | ;;; Ispell has a TeX parser and a nroff parser (the default). | ||
| 71 | ;;; The parsing is controlled by the variable ispell-parser. Currently | ||
| 72 | ;;; it is just a "toggle" between TeX and nroff, but if more parsers are | ||
| 73 | ;;; added it will be updated. See the variable description for more info. | ||
| 74 | ;;; | ||
| 75 | ;;; | ||
| 76 | ;;; TABLE OF CONTENTS | ||
| 77 | ;;; | ||
| 78 | ;;; ispell-word | ||
| 79 | ;;; ispell-region | ||
| 80 | ;;; ispell-buffer | ||
| 81 | ;;; ispell-message | ||
| 82 | ;;; ispell-continue | ||
| 83 | ;;; ispell-complete-word | ||
| 84 | ;;; ispell-complete-word-interior-frag | ||
| 85 | ;;; ispell-change-dictionary | ||
| 86 | ;;; ispell-kill-ispell | ||
| 87 | ;;; ispell-pdict-save | ||
| 88 | ;;; | ||
| 89 | ;;; | ||
| 90 | ;;; Commands in ispell-region: | ||
| 91 | ;;; Character replacement: Replace word with choice. May query-replace. | ||
| 92 | ;;; ' ': Accept word this time. | ||
| 93 | ;;; 'i': Accept word and insert into private dictionary. | ||
| 94 | ;;; 'a': Accept word for this session. | ||
| 95 | ;;; 'A': Accept word and place in buffer-local dictionary. | ||
| 96 | ;;; 'r': Replace word with typed-in value. Rechecked. | ||
| 97 | ;;; 'R': Replace word with typed-in value. Query-replaced in buffer. Rechecked. | ||
| 98 | ;;; '?': Show these commands | ||
| 99 | ;;; 'x': Exit spelling buffer. Move cursor to original point. | ||
| 100 | ;;; 'X': Exit spelling buffer. Leave cursor at the current point. | ||
| 101 | ;;; 'q': Quit spelling session (Kills ispell process). | ||
| 102 | ;;; 'l': Look up typed-in replacement in alternate dictionary. Wildcards okay. | ||
| 103 | ;;; 'u': Like 'i', but the word is lower-cased first. | ||
| 104 | ;;; 'm': Like 'i', but allows one to include dictionary completion info. | ||
| 105 | ;;; 'C-l': redraws screen | ||
| 106 | ;;; 'C-r': recursive edit | ||
| 107 | ;;; 'C-z': suspend emacs | ||
| 108 | ;;; | ||
| 109 | ;;; Buffer-Local features: | ||
| 110 | ;;; There are a number of buffer-local features that can be used to customize | ||
| 111 | ;;; ispell for the current buffer. This includes language dictionaries, | ||
| 112 | ;;; personal dictionaries, parsing, and local word spellings. Each of these | ||
| 113 | ;;; local customizations are done either through local variables, or by | ||
| 114 | ;;; including the keyword and argument(s) at the end of the buffer (usually | ||
| 115 | ;;; prefixed by the comment characters). See the end of this file for | ||
| 116 | ;;; examples. The local keywords and variables are: | ||
| 117 | ;;; | ||
| 118 | ;;; ispell-dictionary-keyword language-dictionary | ||
| 119 | ;;; uses local variable ispell-local-dictionary | ||
| 120 | ;;; ispell-pdict-keyword personal-dictionary | ||
| 121 | ;;; uses local variable ispell-local-pdict | ||
| 122 | ;;; ispell-parsing-keyword mode-arg extended-char-arg | ||
| 123 | ;;; ispell-words-keyword any number of local word spellings | ||
| 124 | ;;; | ||
| 125 | ;;; | ||
| 126 | ;;; BUGS: | ||
| 127 | ;;; Highlighting in version 19 still doesn't work on tty's. | ||
| 128 | ;;; On some versions of emacs, growing the minibuffer fails. | ||
| 129 | ;;; | ||
| 130 | ;;; HISTORY | ||
| 131 | ;;; | ||
| 132 | ;;; Revision 2.26 | ||
| 133 | ;;; name changes for copyright assignment. Added word-frags in complete-word. | ||
| 134 | ;;; Horizontal scroll (John Conover) Query-replace matches words now. bugs. | ||
| 135 | ;;; | ||
| 136 | ;;; Revision 2.25 | ||
| 137 | ;;; minor mods, upgraded ispell-message | ||
| 138 | ;;; | ||
| 139 | ;;; Revision 2.24 | ||
| 140 | ;;; query-replace more robust, messages, defaults, ispell-change-dict. | ||
| 141 | ;;; | ||
| 142 | ;;; Revision 2.23 1993/11/22 23:47:03 stevens | ||
| 143 | ;;; ispell-message, Fixed highlighting, added menu-bar, fixed ispell-help, ... | ||
| 144 | ;;; | ||
| 145 | ;;; Revision 2.22 | ||
| 146 | ;;; Added 'u' command. Fixed default in ispell-local-dictionary. | ||
| 147 | ;;; fixed affix rules display. Tib skipping more robust. Contributions by | ||
| 148 | ;;; Per Abraham (parser selection), Denis Howe, and Eberhard Mattes. | ||
| 149 | ;;; | ||
| 150 | ;;; Revision 2.21 1993/06/30 14:09:04 stevens | ||
| 151 | ;;; minor bugs. (nroff word skipping fixed) | ||
| 152 | ;;; | ||
| 153 | ;;; Revision 2.20 1993/06/30 14:09:04 stevens | ||
| 154 | ;;; | ||
| 155 | ;;; Debugging and contributions by: Boris Aronov, Rik Faith, Chris Moore, | ||
| 156 | ;;; Kevin Rodgers, Malcolm Davis. | ||
| 157 | ;;; Particular thanks to Michael Lipp, Jamie Zawinski, Phil Queinnec | ||
| 158 | ;;; and John Heidemann for suggestions and code. | ||
| 159 | ;;; Major update including many tweaks. | ||
| 160 | ;;; Many changes were integrations of suggestions. | ||
| 161 | ;;; lookup-words rehacked to use call-process (Jamie). | ||
| 162 | ;;; ispell-complete-word rehacked to be compatible with the rest of the | ||
| 163 | ;;; system for word searching and to include multiple wildcards, | ||
| 164 | ;;; and it's own dictionary. | ||
| 165 | ;;; query-replace capability added. New options 'X', 'R', and 'A'. | ||
| 166 | ;;; buffer-local modes for dictionary, word-spelling, and formatter-parsing. | ||
| 167 | ;;; Many random bugs, like commented comments being skipped, fix to | ||
| 168 | ;;; keep-choices-win, fix for math mode, added pipe mode choice, | ||
| 169 | ;;; fixed 'q' command, ispell-word checks previous word and leave cursor | ||
| 170 | ;;; in same location. Fixed tib code which could drop spelling regions. | ||
| 171 | ;;; Cleaned up setq calls for efficiency. Gave more context on window overlays. | ||
| 172 | ;;; Assure context on ispell-command-loop. Window lossage in look cmd fixed. | ||
| 173 | ;;; Due to pervasive opinion, common-lisp package syntax removed. Display | ||
| 174 | ;;; problem when not highlighting. | ||
| 175 | ;;; | ||
| 176 | ;;; Revision 2.19 1992/01/10 10:54:08 geoff | ||
| 177 | ;;; Make another attempt at fixing the "Bogus, dude" problem. This one is | ||
| 178 | ;;; less elegant, but has the advantage of working. | ||
| 179 | ;;; | ||
| 180 | ;;; Revision 2.18 1992/01/07 10:04:52 geoff | ||
| 181 | ;;; Fix the "Bogus, Dude" problem in ispell-word. | ||
| 182 | ;;; | ||
| 183 | ;;; Revision 2.17 1991/09/12 00:01:42 geoff | ||
| 184 | ;;; Add some changes to make ispell-complete-word work better, though | ||
| 185 | ;;; still not perfectly. | ||
| 186 | ;;; | ||
| 187 | ;;; Revision 2.16 91/09/04 18:00:52 geoff | ||
| 188 | ;;; More updates from Sebastian, to make the multiple-dictionary support | ||
| 189 | ;;; more flexible. | ||
| 190 | ;;; | ||
| 191 | ;;; Revision 2.15 91/09/04 17:30:02 geoff | ||
| 192 | ;;; Sebastian Kremer's tib support | ||
| 193 | ;;; | ||
| 194 | ;;; Revision 2.14 91/09/04 16:19:37 geoff | ||
| 195 | ;;; Don't do set-window-start if the move-to-window-line moved us | ||
| 196 | ;;; downward, rather than upward. This prevents getting the buffer all | ||
| 197 | ;;; confused. Also, don't use the "not-modified" function to clear the | ||
| 198 | ;;; modification flag; instead use set-buffer-modified-p. This prevents | ||
| 199 | ;;; extra messages from flashing. | ||
| 200 | ;;; | ||
| 201 | ;;; Revision 2.13 91/09/04 14:35:41 geoff | ||
| 202 | ;;; Fix a spelling error in a comment. Add code to handshake with the | ||
| 203 | ;;; ispell process before sending anything to it. | ||
| 204 | ;;; | ||
| 205 | ;;; Revision 2.12 91/09/03 20:14:21 geoff | ||
| 206 | ;;; Add Sebastian Kremer's multiple-language support. | ||
| 207 | ;;; | ||
| 208 | ;;; | ||
| 209 | ;;; Walt Buehring | ||
| 210 | ;;; Texas Instruments - Computer Science Center | ||
| 211 | ;;; ARPA: Buehring%TI-CSL@CSNet-Relay | ||
| 212 | ;;; UUCP: {smu, texsun, im4u, rice} ! ti-csl ! buehring | ||
| 213 | ;;; | ||
| 214 | ;;; ispell-region and associated routines added by | ||
| 215 | ;;; Perry Smith | ||
| 216 | ;;; pedz@bobkat | ||
| 217 | ;;; Tue Jan 13 20:18:02 CST 1987 | ||
| 218 | ;;; | ||
| 219 | ;;; extensively modified by Mark Davies and Andrew Vignaux | ||
| 220 | ;;; {mark,andrew}@vuwcomp | ||
| 221 | ;;; Sun May 10 11:45:04 NZST 1987 | ||
| 222 | ;;; | ||
| 223 | ;;; Ken Stevens ARPA: k.stevens@ieee.org | ||
| 224 | ;;; Tue Jan 3 16:59:07 PST 1989 | ||
| 225 | ;;; This file has overgone a major overhaul to be compatible with ispell | ||
| 226 | ;;; version 2.1. Most of the functions have been totally rewritten, and | ||
| 227 | ;;; many user-accessible variables have been added. The syntax table has | ||
| 228 | ;;; been removed since it didn't work properly anyway, and a filter is | ||
| 229 | ;;; used rather than a buffer. Regular expressions are used based on | ||
| 230 | ;;; ispell's internal definition of characters (see ispell(4)). | ||
| 231 | ;;; Some new updates: | ||
| 232 | ;;; - Updated to version 3.0 to include terse processing. | ||
| 233 | ;;; - Added a variable for the look command. | ||
| 234 | ;;; - Fixed a bug in ispell-word when cursor is far away from the word | ||
| 235 | ;;; that is to be checked. | ||
| 236 | ;;; - Ispell places the incorrect word or guess in the minibuffer now. | ||
| 237 | ;;; - fixed a bug with 'l' option when multiple windows are on the screen. | ||
| 238 | ;;; - lookup-words just didn't work with the process filter. Fixed. | ||
| 239 | ;;; - Rewrote the process filter to make it cleaner and more robust | ||
| 240 | ;;; in the event of a continued line not being completed. | ||
| 241 | ;;; - Made ispell-init-process more robust in handling errors. | ||
| 242 | ;;; - Fixed bug in continuation location after a region has been modified by | ||
| 243 | ;;; correcting a misspelling. | ||
| 244 | ;;; Mon 17 Sept 1990 | ||
| 245 | ;;; | ||
| 246 | ;;; Sebastian Kremer <sk@thp.uni-koeln.de> | ||
| 247 | ;;; Wed Aug 7 14:02:17 MET DST 1991 | ||
| 248 | ;;; - Ported ispell-complete-word from Ispell 2 to Ispell 3. | ||
| 249 | ;;; - Added ispell-kill-ispell command. | ||
| 250 | ;;; - Added ispell-dictionary and ispell-dictionary-alist variables to | ||
| 251 | ;;; support other than default language. See their docstrings and | ||
| 252 | ;;; command ispell-change-dictionary. | ||
| 253 | ;;; - (ispelled it :-) | ||
| 254 | ;;; - Added ispell-skip-tib variable to support the tib bibliography | ||
| 255 | ;;; program. | ||
| 256 | ;;; | ||
| 257 | ;;; | ||
| 258 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 259 | |||
| 260 | |||
| 261 | |||
| 262 | ;;; ********************************************************************** | ||
| 263 | ;;; The following variables should be set according to personal preference | ||
| 264 | ;;; and location of binaries: | ||
| 265 | ;;; ********************************************************************** | ||
| 266 | |||
| 267 | |||
| 268 | ;;; ******* THIS FILE IS WRITTEN FOR ISPELL VERSION 3.1 | ||
| 269 | ;;; Code: | ||
| 270 | |||
| 271 | (defvar ispell-highlight-p t | ||
| 272 | "*When not nil, spelling errors will be highlighted.") | ||
| 273 | |||
| 274 | (defvar ispell-highlight-face 'highlight | ||
| 275 | "*The face used for ispell highlighting. For Emacses with overlays. | ||
| 276 | Common values for GNU emacs are highlight, modeline, secondary-selection, | ||
| 277 | region, and underline. | ||
| 278 | This variable can be set by the user to whatever face they desire. | ||
| 279 | It's most convenient if the cursor color and highlight color are | ||
| 280 | slightly different.") | ||
| 281 | |||
| 282 | (defvar ispell-check-comments nil | ||
| 283 | "*When true, the spelling of comments in region is checked.") | ||
| 284 | |||
| 285 | (defvar ispell-query-replace-choices nil | ||
| 286 | "*When true and spell checking a region, the correction will be made | ||
| 287 | throughout the buffer using \\[query-replace].") | ||
| 288 | |||
| 289 | (defvar ispell-skip-tib nil | ||
| 290 | "*If non-nil, the spelling of references for the tib(1) bibliography | ||
| 291 | program are skipped. Otherwise any text between strings matching the regexps | ||
| 292 | ispell-tib-ref-beginning and ispell-tib-ref-end is ignored. | ||
| 293 | |||
| 294 | TeX users beware: Any field starting with [. will skip until a .] -- even | ||
| 295 | your whole buffer -- unless you set ispell-skip-tib to nil. That includes | ||
| 296 | a [.5mm] type of number....") | ||
| 297 | |||
| 298 | (defvar ispell-tib-ref-beginning "[[<]\\." | ||
| 299 | "Regexp matching the beginning of a Tib reference.") | ||
| 300 | |||
| 301 | (defvar ispell-tib-ref-end "\\.[]>]" | ||
| 302 | "Regexp matching the end of a Tib reference.") | ||
| 303 | |||
| 304 | (defvar ispell-keep-choices-win t | ||
| 305 | "*When not nil, the *Choices* window remains for spelling session. | ||
| 306 | This minimizes redisplay thrashing.") | ||
| 307 | |||
| 308 | (defvar ispell-choices-win-default-height 2 | ||
| 309 | "*The default size of the *Choices*, including status line. | ||
| 310 | Must be greater than 1.") | ||
| 311 | |||
| 312 | (defvar ispell-program-name "ispell" | ||
| 313 | "Program invoked by \\[ispell-word] and \\[ispell-region] commands.") | ||
| 314 | |||
| 315 | (defvar ispell-alternate-dictionary | ||
| 316 | (cond ((file-exists-p "/usr/dict/web2") "/usr/dict/web2") | ||
| 317 | ((file-exists-p "/usr/dict/words") "/usr/dict/words") | ||
| 318 | ((file-exists-p "/usr/lib/dict/words") "/usr/lib/dict/words") | ||
| 319 | ((file-exists-p "/sys/dict") "/sys/dict") | ||
| 320 | (t "/usr/dict/words")) | ||
| 321 | "*Alternate dictionary for spelling help.") | ||
| 322 | |||
| 323 | (defvar ispell-complete-word-dict ispell-alternate-dictionary | ||
| 324 | "*Dictionary used for word completion.") | ||
| 325 | |||
| 326 | (defvar ispell-grep-command "/usr/bin/egrep" | ||
| 327 | "Name of the grep command for search processes.") | ||
| 328 | |||
| 329 | (defvar ispell-grep-options "-i" | ||
| 330 | "Options for ispell-grep-command. | ||
| 331 | Should probably be \"-i\" or \"-e\". | ||
| 332 | Some machines (like the NeXT) don't support \"-i\"") | ||
| 333 | |||
| 334 | (defvar ispell-look-command "/usr/bin/look" | ||
| 335 | "Name of the look command for search processes. | ||
| 336 | Must contain complete path!") | ||
| 337 | |||
| 338 | (defvar ispell-look-p (file-exists-p ispell-look-command) | ||
| 339 | "*Use look. Should be nil if your UNIX doesn't have this program. | ||
| 340 | Attempts to automatically reset if look not available") | ||
| 341 | |||
| 342 | (defvar ispell-have-new-look nil | ||
| 343 | "*Non-nil means use the `-r' option (regexp) when running `look'.") | ||
| 344 | |||
| 345 | (defvar ispell-look-options (if ispell-have-new-look "-dfr" "-df") | ||
| 346 | "Options for ispell-look-command") | ||
| 347 | |||
| 348 | (defvar ispell-use-ptys-p nil | ||
| 349 | "When t, emacs will use pty's to communicate with ispell. | ||
| 350 | When nil, emacs will use pipes.") | ||
| 351 | |||
| 352 | (defvar ispell-following-word nil | ||
| 353 | "*If non-nil the \\[ispell-word] command will check the spelling | ||
| 354 | of the word under or following \(rather than preceding\) the cursor | ||
| 355 | when called interactively.") | ||
| 356 | |||
| 357 | (defvar ispell-help-in-bufferp t | ||
| 358 | "*If non-nil, the \\[ispell-help] command will display its | ||
| 359 | message in a buffer. Otherwise the minibuffer will be used.") | ||
| 360 | |||
| 361 | (defvar ispell-quietly nil | ||
| 362 | "*If non-nil, the \\[ispell-word] command will suppress all | ||
| 363 | non-corrective messages when called interactively.") | ||
| 364 | |||
| 365 | (defvar ispell-format-word (function upcase) | ||
| 366 | "*The function called to format the word whose spelling is being checked, | ||
| 367 | in diagnostic messages to the user. The function must take one string | ||
| 368 | argument and return a string.") | ||
| 369 | |||
| 370 | (defvar ispell-personal-dictionary nil | ||
| 371 | "*A string or nil. If nil, the default directory, ~/.ispell_words is used.") | ||
| 372 | |||
| 373 | (defvar ispell-silently-savep nil | ||
| 374 | "*When non-nil, save the personal dictionary without user verification.") | ||
| 375 | |||
| 376 | ;;; This variable contains the current dictionary being used if the ispell | ||
| 377 | ;;; process is running. Otherwise it contains the global default. | ||
| 378 | (defvar ispell-dictionary nil | ||
| 379 | "If non-nil, a dictionary to use instead of the default one. | ||
| 380 | This is passed to the ispell process using the \"-d\" switch and is | ||
| 381 | used as key in ispell-dictionary-alist (which see). | ||
| 382 | |||
| 383 | You should set this variable before your first call to ispell (e.g. in | ||
| 384 | your .emacs), or use the \\[ispell-change-dictionary] command to | ||
| 385 | change it, as changing this variable only takes effect in a newly | ||
| 386 | started ispell process.") | ||
| 387 | |||
| 388 | (defvar ispell-dictionary-alist ; sk 9-Aug-1991 18:28 | ||
| 389 | '((nil ; default (english.aff) | ||
| 390 | "[A-Za-z]" "[^A-Za-z]" "[---']" nil ("-B") nil) | ||
| 391 | ("english" ; make english explicitly selectable | ||
| 392 | "[A-Za-z]" "[^A-Za-z]" "[---']" nil ("-B") nil) | ||
| 393 | ("deutsch" ; deutsch.aff | ||
| 394 | "[a-zA-Z\"]" "[^a-zA-Z\"]" "[---']" t ("-C") nil) | ||
| 395 | ("deutsch8" | ||
| 396 | "[a-zA-Z\304\326\334\344\366\337\374]" | ||
| 397 | "[^a-zA-Z\304\326\334\344\366\337\374]" | ||
| 398 | "[---']" t ("-C" "-d" "deutsch") "~latin1") | ||
| 399 | ("nederlands8" ; dutch8.aff | ||
| 400 | "[A-Za-z\300-\305\307\310-\317\322-\326\331-\334\340-\345\347\350-\357\361\362-\366\371-\374]" | ||
| 401 | "[^A-Za-z\300-\305\307\310-\317\322-\326\331-\334\340-\345\347\350-\357\361\362-\366\371-\374]" | ||
| 402 | "[---']" t ("-C") nil) | ||
| 403 | ("svenska" ;7 bit swedish mode | ||
| 404 | "[A-Za-z}{|\\133\\135\\\\]" "[^A-Za-z}{|\\133\\135\\\\]" | ||
| 405 | "[---']" nil ("-C") nil) | ||
| 406 | ("svenska8" ;8 bit swedish mode | ||
| 407 | "[A-Za-z\345\344\366\305\304\366]" "[^A-Za-z\345\344\366\305\304\366]" | ||
| 408 | "[---']" nil ("-C" "-d" "svenska") "~list") ; Add `"-T" "list"' instead? | ||
| 409 | ("francais" | ||
| 410 | "[A-Za-z]" "[^A-Za-z]" "[---`'\^]" nil nil nil) | ||
| 411 | ("dansk" ; dansk.aff | ||
| 412 | "[A-Z\306\330\305a-z\346\370\345]" "[^A-Z\306\330\305a-z\346\370\345]" | ||
| 413 | "[---]" nil ("-C") nil) | ||
| 414 | ) | ||
| 415 | "An alist of dictionaries and their associated parameters. | ||
| 416 | |||
| 417 | Each element of this list is also a list: | ||
| 418 | |||
| 419 | \(DICTIONARY-NAME | ||
| 420 | CASECHARS NOT-CASECHARS OTHERCHARS MANY-OTHERCHARS-P | ||
| 421 | ISPELL-ARGS EXTENDED-CHARACTER-MODE\) | ||
| 422 | |||
| 423 | DICTIONARY-NAME is a possible value of variable ispell-dictionary, nil | ||
| 424 | means the default dictionary. | ||
| 425 | |||
| 426 | CASECHARS is a regular expression of valid characters that comprise a | ||
| 427 | word. | ||
| 428 | |||
| 429 | NOT-CASECHARS is the opposite regexp of CASECHARS. | ||
| 430 | |||
| 431 | OTHERCHARS is a regular expression of other characters that are valid | ||
| 432 | in word constructs. Otherchars cannot be adjacent to each other in a | ||
| 433 | word, nor can they begin or end a word. This implies we can't check | ||
| 434 | \"Stevens'\" as a correct possessive and other correct formations. | ||
| 435 | |||
| 436 | Hint: regexp syntax requires the hyphen to be declared first here. | ||
| 437 | |||
| 438 | MANY-OTHERCHARS-P is non-nil if many otherchars are to be allowed in a | ||
| 439 | word instead of only one. | ||
| 440 | |||
| 441 | ISPELL-ARGS is a list of additional arguments passed to the ispell | ||
| 442 | subprocess. | ||
| 443 | |||
| 444 | EXTENDED-CHARACTER-MODE should be used when dictionaries are used which | ||
| 445 | have been configured in ispell's parse.y. (For example, umlauts | ||
| 446 | can be encoded as \\\"a, a\\\", \"a, ...) Defaults are ~tex and ~nroff | ||
| 447 | in english. This has the same effect as the command-line `-T' option. | ||
| 448 | The buffer Major Mode controls ispell's parsing in tex or nroff mode, | ||
| 449 | but the dictionary can control the extended character mode. | ||
| 450 | Both defaults can be overruled in a buffer-local fashion. See | ||
| 451 | ispell-parsing-keyword for details on this. | ||
| 452 | |||
| 453 | Note that the CASECHARS and OTHERCHARS slots of the alist should | ||
| 454 | contain the same character set as casechars and otherchars in the | ||
| 455 | language.aff file \(e.g., english.aff\).") | ||
| 456 | |||
| 457 | |||
| 458 | ;;; ispell-menu-map from menu-bar.el | ||
| 459 | |||
| 460 | (defvar ispell-menu-map nil) | ||
| 461 | (if (and (featurep 'menu-bar) ; GNU emacs | ||
| 462 | (string-match "^19\\." emacs-version)) | ||
| 463 | (let ((dicts (reverse (cons (cons "default" nil) ispell-dictionary-alist))) | ||
| 464 | name) | ||
| 465 | (setq ispell-menu-map (make-sparse-keymap "Spell")) | ||
| 466 | (while dicts | ||
| 467 | (setq name (car (car dicts)) | ||
| 468 | dicts (cdr dicts)) | ||
| 469 | (if (stringp name) | ||
| 470 | (define-key ispell-menu-map (vector (intern name)) | ||
| 471 | (cons (concat "Select " (capitalize name)) | ||
| 472 | (list 'lambda () '(interactive) | ||
| 473 | (list 'ispell-change-dictionary name)))))) | ||
| 474 | ;; Why do we need an alias here? | ||
| 475 | (defalias 'ispell-menu-map ispell-menu-map) | ||
| 476 | ;; Define commands in opposite order you want them to appear in menu. | ||
| 477 | (define-key ispell-menu-map [ispell-change-dictionary] | ||
| 478 | '("Change Dictionary" . ispell-change-dictionary)) | ||
| 479 | (define-key ispell-menu-map [ispell-kill-ispell] | ||
| 480 | '("Kill Process" . ispell-kill-ispell)) | ||
| 481 | (define-key ispell-menu-map [ispell-pdict-save] | ||
| 482 | '("Save Dictionary" . (lambda () (interactive) (ispell-pdict-save t)))) | ||
| 483 | (define-key ispell-menu-map [ispell-complete-word] | ||
| 484 | '("Complete Word" . ispell-complete-word)) | ||
| 485 | (define-key ispell-menu-map [ispell-complete-word-interior-frag] | ||
| 486 | '("Complete Word Frag" . ispell-complete-word-interior-frag)) | ||
| 487 | (define-key ispell-menu-map [ispell-continue] | ||
| 488 | '("Continue Check" . ispell-continue)) | ||
| 489 | (define-key ispell-menu-map [ispell-region] | ||
| 490 | '("Check Region" . ispell-region)) | ||
| 491 | (define-key ispell-menu-map [ispell-word] | ||
| 492 | '("Check Word" . ispell-word)) | ||
| 493 | (define-key ispell-menu-map [ispell-buffer] | ||
| 494 | '("Check Buffer" . ispell-buffer)) | ||
| 495 | (define-key ispell-menu-map [ispell-message] | ||
| 496 | '("Check Message" . ispell-message)) | ||
| 497 | (define-key ispell-menu-map [ispell-help] | ||
| 498 | '("Help" . (lambda () (interactive) (describe-function 'ispell-help)))) | ||
| 499 | )) | ||
| 500 | |||
| 501 | |||
| 502 | |||
| 503 | ;;; ********************************************************************** | ||
| 504 | ;;; The following are used by ispell, and should not be changed. | ||
| 505 | ;;; ********************************************************************** | ||
| 506 | |||
| 507 | |||
| 508 | ;;; This doesn't match the LAST patch number -- this is for 3.1 or 3.0.09 | ||
| 509 | (defconst ispell-required-versions '("3.1." "3.0.09") | ||
| 510 | "Ispell versions with which this version of ispell.el is known to work.") | ||
| 511 | |||
| 512 | (defun ispell-get-casechars () | ||
| 513 | (nth 1 (assoc ispell-dictionary ispell-dictionary-alist))) | ||
| 514 | (defun ispell-get-not-casechars () | ||
| 515 | (nth 2 (assoc ispell-dictionary ispell-dictionary-alist))) | ||
| 516 | (defun ispell-get-otherchars () | ||
| 517 | (nth 3 (assoc ispell-dictionary ispell-dictionary-alist))) | ||
| 518 | (defun ispell-get-many-otherchars-p () | ||
| 519 | (nth 4 (assoc ispell-dictionary ispell-dictionary-alist))) | ||
| 520 | (defun ispell-get-ispell-args () | ||
| 521 | (nth 5 (assoc ispell-dictionary ispell-dictionary-alist))) | ||
| 522 | (defun ispell-get-extended-character-mode () | ||
| 523 | (nth 6 (assoc ispell-dictionary ispell-dictionary-alist))) | ||
| 524 | |||
| 525 | (defvar ispell-process nil | ||
| 526 | "Holds the process object for 'ispell'") | ||
| 527 | |||
| 528 | (defvar ispell-pdict-modified-p nil | ||
| 529 | "T when the personal dictionary has modifications that need to be written.") | ||
| 530 | |||
| 531 | ;;; If you want to save the dictionary when quitting, must do so explicitly. | ||
| 532 | (defvar ispell-quit nil | ||
| 533 | "Set to t or point when user wants to abort ispell session.") | ||
| 534 | |||
| 535 | (defvar ispell-filter nil | ||
| 536 | "Output filter from piped calls to ispell.") | ||
| 537 | |||
| 538 | (defvar ispell-filter-continue nil | ||
| 539 | "Control variable for ispell filter function.") | ||
| 540 | |||
| 541 | (defvar ispell-process-directory nil | ||
| 542 | "The directory where ispell-process was started.") | ||
| 543 | |||
| 544 | (defvar ispell-query-replace-marker (make-marker) | ||
| 545 | "Marker for query-replace processing.") | ||
| 546 | |||
| 547 | (defvar ispell-checking-message nil | ||
| 548 | "Non-nil when we're checking a mail message") | ||
| 549 | |||
| 550 | (defconst ispell-choices-buffer "*Choices*") | ||
| 551 | |||
| 552 | (defvar ispell-overlay nil "overlay variable for ispell") | ||
| 553 | |||
| 554 | ;;; *** Buffer Local Definitions *** | ||
| 555 | |||
| 556 | ;;; This is the local dictionary to use. When nil the default dictionary will | ||
| 557 | ;;; be used. Do not redefine default value or it will override the global! | ||
| 558 | (defvar ispell-local-dictionary nil | ||
| 559 | "A buffer local variable. If non-nil, a dictionary to be used when running | ||
| 560 | an ispell-command in this buffer. Setting ispell-local-dictionary to a value | ||
| 561 | has the same effect as calling \\[ispell-change-dictionary] with that value. | ||
| 562 | This variable is automatically set when defined in the file with either | ||
| 563 | ispell-dictionary-keyword or the Local Variable syntax. | ||
| 564 | If using Local Variable syntax, the dictionary must be a string.") | ||
| 565 | |||
| 566 | (make-variable-buffer-local 'ispell-local-dictionary) | ||
| 567 | |||
| 568 | ;; Use default directory, unless locally set. | ||
| 569 | (set-default 'ispell-local-dictionary nil) | ||
| 570 | |||
| 571 | (defconst ispell-words-keyword "LocalWords: " | ||
| 572 | "The keyword for local oddly-spelled words to accept. | ||
| 573 | The keyword will be followed by any number of local word spellings. | ||
| 574 | There can be multiple of these keywords in the file.") | ||
| 575 | |||
| 576 | (defconst ispell-dictionary-keyword "Local IspellDict: " | ||
| 577 | "The keyword for local dictionary definitions. | ||
| 578 | There should be only one dictionary keyword definition per file, and it | ||
| 579 | should be followed by a correct dictionary name in ispell-dictionary-alist.") | ||
| 580 | |||
| 581 | (defconst ispell-parsing-keyword "Local IspellParsing: " | ||
| 582 | "The keyword for overriding default ispell parsing as determined by | ||
| 583 | the buffer's major mode and extended-character mode as determined by the | ||
| 584 | default dictionary. | ||
| 585 | |||
| 586 | The above keyword string should be followed by `latex-mode' or | ||
| 587 | `nroff-mode' to put the current buffer into the desired parsing mode. | ||
| 588 | |||
| 589 | Extended character mode can be changed for this buffer by placing | ||
| 590 | a `~' followed by an extended-character mode -- such as `~.tex'.") | ||
| 591 | |||
| 592 | (defvar ispell-local-pdict ispell-personal-dictionary | ||
| 593 | "A buffer local variable. If a personal dictionary is specified for | ||
| 594 | the current buffer which is different from the current personal dictionary, | ||
| 595 | the effect will be similar to calling \\[ispell-change-dictionary]. | ||
| 596 | This variable is automatically set when defined in the file with either | ||
| 597 | ispell-pdict-keyword or the local variable syntax. | ||
| 598 | If using Local variable syntax, the dictionary must be nil or a string.") | ||
| 599 | |||
| 600 | (make-variable-buffer-local 'ispell-local-pdict) | ||
| 601 | |||
| 602 | (defconst ispell-pdict-keyword "Local IspellPersDict: " | ||
| 603 | "The keyword for defining buffer local dictionaries.") | ||
| 604 | |||
| 605 | (defvar ispell-buffer-local-name nil | ||
| 606 | "Contains the buffer name if local word definitions were used. | ||
| 607 | Ispell is then restarted because the local words could conflict.") | ||
| 608 | |||
| 609 | (defvar ispell-parser 'use-mode-name | ||
| 610 | "*Indicates whether ispell should parse the current buffer as TeX Code. | ||
| 611 | Special value 'use-mode-name tries to guess using the name of major-mode. | ||
| 612 | Default parser is 'nroff. | ||
| 613 | Currently the only other valid parser is 'tex. | ||
| 614 | |||
| 615 | You can set this variable in hooks in your init file -- eg: | ||
| 616 | |||
| 617 | (add-hook 'tex-mode-hook (function (lambda () (setq ispell-parser 'tex))))") | ||
| 618 | |||
| 619 | (defvar ispell-region-end (make-marker) | ||
| 620 | "Marker that allows spelling continuations.") | ||
| 621 | |||
| 622 | |||
| 623 | ;;; ********************************************************************** | ||
| 624 | ;;; ********************************************************************** | ||
| 625 | |||
| 626 | |||
| 627 | ;;;###autoload | ||
| 628 | (defun ispell-word (&optional following quietly) | ||
| 629 | "Check spelling of word under or before the cursor. | ||
| 630 | If word not found in dictionary, display possible corrections in a window | ||
| 631 | and let user select. | ||
| 632 | If optional argument FOLLOWING is non-nil or if ispell-following-word | ||
| 633 | is non-nil when called interactively, then the following word | ||
| 634 | \(rather than preceding\) will be checked when the cursor is not over a word. | ||
| 635 | When the optional argument QUIETLY is non-nil or ispell-quietly is non-nil | ||
| 636 | when called interactively, non-corrective messages are suppressed. | ||
| 637 | |||
| 638 | Word syntax described by ispell-dictionary-alist (which see). | ||
| 639 | |||
| 640 | This will check or reload the dictionary. Use \\[ispell-change-dictionary] | ||
| 641 | or \\[ispell-region] to update the ispell process." | ||
| 642 | (interactive) | ||
| 643 | (if (interactive-p) | ||
| 644 | (setq following ispell-following-word | ||
| 645 | quietly ispell-quietly)) | ||
| 646 | (ispell-buffer-local-dict) ; use the correct dictionary | ||
| 647 | (let ((cursor-location (point)) ; retain cursor location | ||
| 648 | ispell-keep-choices-win ; override global to force creation | ||
| 649 | (word (ispell-get-word following)) | ||
| 650 | start end poss replace) | ||
| 651 | ;; destructure return word info list. | ||
| 652 | (setq start (car (cdr word)) | ||
| 653 | end (car (cdr (cdr word))) | ||
| 654 | word (car word)) | ||
| 655 | |||
| 656 | ;; now check spelling of word. | ||
| 657 | (or quietly | ||
| 658 | (message "Checking spelling of %s..." | ||
| 659 | (funcall ispell-format-word word))) | ||
| 660 | (ispell-init-process) ; erases ispell output buffer | ||
| 661 | (process-send-string ispell-process "%\n") ;put in verbose mode | ||
| 662 | (process-send-string ispell-process (concat "^" word "\n")) | ||
| 663 | ;; wait until ispell has processed word | ||
| 664 | (while (progn | ||
| 665 | (accept-process-output ispell-process) | ||
| 666 | (not (string= "" (car ispell-filter))))) | ||
| 667 | ;;(process-send-string ispell-process "!\n") ;back to terse mode. | ||
| 668 | (setq ispell-filter (cdr ispell-filter)) | ||
| 669 | (if (listp ispell-filter) | ||
| 670 | (setq poss (ispell-parse-output (car ispell-filter)))) | ||
| 671 | (cond ((eq poss t) | ||
| 672 | (or quietly | ||
| 673 | (message "%s is correct." (funcall ispell-format-word word)))) | ||
| 674 | ((stringp poss) | ||
| 675 | (or quietly | ||
| 676 | (message "%s is correct because of root %s" | ||
| 677 | (funcall ispell-format-word word) | ||
| 678 | (funcall ispell-format-word poss)))) | ||
| 679 | ((null poss) (message "Error in ispell process")) | ||
| 680 | (t ; prompt for correct word. | ||
| 681 | (unwind-protect | ||
| 682 | (progn | ||
| 683 | (if ispell-highlight-p | ||
| 684 | (highlight-spelling-error start end t)) ; highlight word | ||
| 685 | (setq replace (ispell-command-loop | ||
| 686 | (car (cdr (cdr poss))) | ||
| 687 | (car (cdr (cdr (cdr poss)))) | ||
| 688 | (car poss)))) | ||
| 689 | ;; protected | ||
| 690 | (if ispell-highlight-p ; clear highlight | ||
| 691 | (highlight-spelling-error start end))) | ||
| 692 | (cond ((equal 0 replace) | ||
| 693 | (ispell-add-per-file-word-list (car poss))) | ||
| 694 | (replace | ||
| 695 | (delete-region start end) | ||
| 696 | (setq word (if (atom replace) replace (car replace)) | ||
| 697 | cursor-location (+ (- (length word) (- end start)) | ||
| 698 | cursor-location)) | ||
| 699 | (insert word) | ||
| 700 | (if (not (atom replace)) ; recheck spelling of replacement | ||
| 701 | (progn | ||
| 702 | (goto-char cursor-location) | ||
| 703 | (ispell-word following quietly))))) | ||
| 704 | (if (get-buffer ispell-choices-buffer) | ||
| 705 | (kill-buffer ispell-choices-buffer)))) | ||
| 706 | (goto-char cursor-location) ; return to original location | ||
| 707 | (ispell-pdict-save ispell-silently-savep) | ||
| 708 | (if ispell-quit (setq ispell-quit nil)))) | ||
| 709 | |||
| 710 | |||
| 711 | (defun ispell-get-word (following &optional extra-otherchars) | ||
| 712 | "Return the word for spell-checking according to ispell syntax. | ||
| 713 | If optional argument FOLLOWING is non-nil or if ispell-following-word | ||
| 714 | is non-nil when called interactively, then the following word | ||
| 715 | \(rather than preceeding\) will be checked when the cursor is not over a word. | ||
| 716 | Optional second argument contains otherchars that can be included in word | ||
| 717 | many times. | ||
| 718 | |||
| 719 | Word syntax described by ispell-dictionary-alist (which see)." | ||
| 720 | (let* ((ispell-casechars (ispell-get-casechars)) | ||
| 721 | (ispell-not-casechars (ispell-get-not-casechars)) | ||
| 722 | (ispell-otherchars (ispell-get-otherchars)) | ||
| 723 | (ispell-many-otherchars-p (ispell-get-many-otherchars-p)) | ||
| 724 | (word-regexp (concat ispell-casechars | ||
| 725 | "+\\(" | ||
| 726 | ispell-otherchars | ||
| 727 | "?" | ||
| 728 | (if extra-otherchars | ||
| 729 | (concat extra-otherchars "?")) | ||
| 730 | ispell-casechars | ||
| 731 | "+\\)" | ||
| 732 | (if (or ispell-many-otherchars-p | ||
| 733 | extra-otherchars) | ||
| 734 | "*" "?"))) | ||
| 735 | did-it-once | ||
| 736 | start end word) | ||
| 737 | ;; find the word | ||
| 738 | (if (not (looking-at ispell-casechars)) | ||
| 739 | (if following | ||
| 740 | (re-search-forward ispell-casechars (point-max) t) | ||
| 741 | (re-search-backward ispell-casechars (point-min) t))) | ||
| 742 | ;; move to front of word | ||
| 743 | (re-search-backward ispell-not-casechars (point-min) 'start) | ||
| 744 | (while (and (or (looking-at ispell-otherchars) | ||
| 745 | (and extra-otherchars (looking-at extra-otherchars))) | ||
| 746 | (not (bobp)) | ||
| 747 | (or (not did-it-once) | ||
| 748 | ispell-many-otherchars-p)) | ||
| 749 | (if (and extra-otherchars (looking-at extra-otherchars)) | ||
| 750 | (progn | ||
| 751 | (backward-char 1) | ||
| 752 | (if (looking-at ispell-casechars) | ||
| 753 | (re-search-backward ispell-not-casechars (point-min) 'move))) | ||
| 754 | (setq did-it-once t) | ||
| 755 | (backward-char 1) | ||
| 756 | (if (looking-at ispell-casechars) | ||
| 757 | (re-search-backward ispell-not-casechars (point-min) 'move) | ||
| 758 | (backward-char -1)))) | ||
| 759 | ;; Now mark the word and save to string. | ||
| 760 | (or (re-search-forward word-regexp (point-max) t) | ||
| 761 | (error "No word found to check!")) | ||
| 762 | (setq start (match-beginning 0) | ||
| 763 | end (point) | ||
| 764 | word (buffer-substring start end)) | ||
| 765 | (list word start end))) | ||
| 766 | |||
| 767 | |||
| 768 | ;;; Global ispell-pdict-modified-p is set by ispell-command-loop and | ||
| 769 | ;;; tracks changes in the dictionary. The global may either be | ||
| 770 | ;;; a value or a list, whose value is the state of whether the | ||
| 771 | ;;; dictionary needs to be saved. | ||
| 772 | |||
| 773 | (defun ispell-pdict-save (&optional no-query force-save) | ||
| 774 | "Check to see if the personal dictionary has been modified. | ||
| 775 | If so, ask if it needs to be saved." | ||
| 776 | (interactive (list ispell-silently-savep t)) | ||
| 777 | (if (and ispell-pdict-modified-p (listp ispell-pdict-modified-p)) | ||
| 778 | (setq ispell-pdict-modified-p (car ispell-pdict-modified-p))) | ||
| 779 | (if (or ispell-pdict-modified-p force-save) | ||
| 780 | (if (or no-query (y-or-n-p "Personal dictionary modified. Save? ")) | ||
| 781 | (process-send-string ispell-process "#\n"))) | ||
| 782 | ;; unassert variable, even if not saved to avoid questioning. | ||
| 783 | (setq ispell-pdict-modified-p nil)) | ||
| 784 | |||
| 785 | |||
| 786 | (defun ispell-command-loop (miss guess word) | ||
| 787 | "Display possible corrections from list MISS. | ||
| 788 | GUESS lists possibly valid affix construction of WORD. | ||
| 789 | Returns nil to keep word. | ||
| 790 | 0 to insert locally into buffer-local dictionary. | ||
| 791 | string for new chosen word. | ||
| 792 | list for new replacement word (will be rechecked). | ||
| 793 | Optional second argument means replace misspelling in | ||
| 794 | the rest of the region. | ||
| 795 | Global ispell-pdict-modified-p becomes a list where the only value | ||
| 796 | indicates whether the dictionary has been modified when option a or i is | ||
| 797 | used." | ||
| 798 | (unwind-protect | ||
| 799 | (save-window-excursion | ||
| 800 | (let ((count ?0) | ||
| 801 | (line 2) | ||
| 802 | (max-lines (- (window-height) 4)) ; assure 4 context lines. | ||
| 803 | (choices miss) | ||
| 804 | (window-min-height (min window-min-height | ||
| 805 | ispell-choices-win-default-height)) | ||
| 806 | (command-characters '( ? ?i ?a ?A ?r ?R ?? ?x ?X ?q ?l ?u ?m )) | ||
| 807 | (skipped 0) | ||
| 808 | char num result) | ||
| 809 | (save-excursion | ||
| 810 | (if ispell-keep-choices-win | ||
| 811 | (select-window (previous-window)) | ||
| 812 | (set-buffer (get-buffer-create ispell-choices-buffer)) | ||
| 813 | (setq mode-line-format "-- %b --")) | ||
| 814 | (if (equal (get-buffer ispell-choices-buffer) (current-buffer)) | ||
| 815 | (erase-buffer) | ||
| 816 | (error "Bogus, dude! I should be in the *Choices* buffer, but I'm not!")) | ||
| 817 | (if guess | ||
| 818 | (progn | ||
| 819 | (insert | ||
| 820 | "Affix rules generate and capitalize this word as shown below:\n\t") | ||
| 821 | (while guess | ||
| 822 | (if (> (+ 4 (current-column) (length (car guess))) | ||
| 823 | (window-width)) | ||
| 824 | (progn | ||
| 825 | (insert "\n\t") | ||
| 826 | (setq line (1+ line)))) | ||
| 827 | (insert (car guess) " ") | ||
| 828 | (setq guess (cdr guess))) | ||
| 829 | (insert "\nUse option \"i\" if this is a correct composition from the derivative root.\n") | ||
| 830 | (setq line (+ line (if choices 3 2))))) | ||
| 831 | (while (and choices | ||
| 832 | (< (if (> (+ 7 (current-column) (length (car choices)) | ||
| 833 | (if (> count ?~) 3 0)) | ||
| 834 | (window-width)) | ||
| 835 | (progn | ||
| 836 | (insert "\n") | ||
| 837 | (setq line (1+ line))) | ||
| 838 | line) | ||
| 839 | max-lines)) | ||
| 840 | ;; not so good if there are over 20 or 30 options, but then, if | ||
| 841 | ;; there are that many you don't want to have to scan them all anyway... | ||
| 842 | (while (memq count command-characters) ; skip command characters. | ||
| 843 | (setq count (1+ count) | ||
| 844 | skipped (1+ skipped))) | ||
| 845 | (insert "(" count ") " (car choices) " ") | ||
| 846 | (setq choices (cdr choices) | ||
| 847 | count (1+ count))) | ||
| 848 | (setq count (- count ?0 skipped))) | ||
| 849 | |||
| 850 | (if ispell-keep-choices-win | ||
| 851 | (if (> line ispell-keep-choices-win) | ||
| 852 | (progn | ||
| 853 | (switch-to-buffer ispell-choices-buffer) | ||
| 854 | (select-window (next-window)) | ||
| 855 | (save-excursion | ||
| 856 | (let ((cur-point (point))) | ||
| 857 | (move-to-window-line (- line ispell-keep-choices-win)) | ||
| 858 | (if (<= (point) cur-point) | ||
| 859 | (set-window-start (selected-window) (point))))) | ||
| 860 | (select-window (previous-window)) | ||
| 861 | (enlarge-window (- line ispell-keep-choices-win)) | ||
| 862 | (goto-char (point-min)))) | ||
| 863 | (ispell-overlay-window (max line ispell-choices-win-default-height))) | ||
| 864 | (switch-to-buffer ispell-choices-buffer) | ||
| 865 | (goto-char (point-min)) | ||
| 866 | (select-window (next-window)) | ||
| 867 | (while | ||
| 868 | (eq | ||
| 869 | t | ||
| 870 | (setq | ||
| 871 | result | ||
| 872 | (progn | ||
| 873 | (undo-boundary) | ||
| 874 | (message "C-h or ? for more options; SPC to leave unchanged, Character to replace word") | ||
| 875 | (setq char (read-char) | ||
| 876 | skipped 0) | ||
| 877 | ;; Adjust num to array offset skipping command characters. | ||
| 878 | (let ((com-chars command-characters)) | ||
| 879 | (while com-chars | ||
| 880 | (if (and (> (car com-chars) ?0) (< (car com-chars) char)) | ||
| 881 | (setq skipped (1+ skipped))) | ||
| 882 | (setq com-chars (cdr com-chars))) | ||
| 883 | (setq num (- char ?0 skipped))) | ||
| 884 | |||
| 885 | (cond | ||
| 886 | ((= char ? ) nil) ; accept word this time only | ||
| 887 | ((= char ?i) ; accept and insert word into pers dict | ||
| 888 | (process-send-string ispell-process (concat "*" word "\n")) | ||
| 889 | (setq ispell-pdict-modified-p '(t)) ; dictionary was modified! | ||
| 890 | nil) | ||
| 891 | ((or (= char ?a) (= char ?A)) ; accept word, don't insert in dict | ||
| 892 | (process-send-string ispell-process (concat "@" word "\n")) | ||
| 893 | (if (null ispell-pdict-modified-p) | ||
| 894 | (setq ispell-pdict-modified-p | ||
| 895 | (list ispell-pdict-modified-p))) | ||
| 896 | (if (= char ?A) 0)) ; return 0 for ispell-add buffer-local | ||
| 897 | ((or (= char ?r) (= char ?R)) ; type in replacement | ||
| 898 | (if (or (= char ?R) ispell-query-replace-choices) | ||
| 899 | (list (read-string "Query-replacement for: " word) t) | ||
| 900 | (cons (read-string "Replacement for: " word) nil))) | ||
| 901 | ((or (= char ??) (= char help-char) (= char ?\C-h)) | ||
| 902 | (ispell-help) | ||
| 903 | t) | ||
| 904 | ;; quit or quit and stay at this point. | ||
| 905 | ((or (= char ?x) (= char ?X)) ; quit. | ||
| 906 | (ispell-pdict-save ispell-silently-savep) | ||
| 907 | (message "exited ispell") | ||
| 908 | (setq ispell-quit (if (= char ?X) (point) t)) | ||
| 909 | nil) | ||
| 910 | ((or (= char ?q) | ||
| 911 | (= char (nth 3 (current-input-mode)))) ; C-g | ||
| 912 | (if (y-or-n-p "Really quit ignoring changes? ") | ||
| 913 | (progn | ||
| 914 | (ispell-kill-ispell t) ; terminate process. | ||
| 915 | (setq ispell-quit t | ||
| 916 | ispell-pdict-modified-p nil)) | ||
| 917 | t)) ; continue if they don't quit. | ||
| 918 | ((= char ?l) | ||
| 919 | (let ((new-word (read-string "Lookup string ('*' is wildcard): " | ||
| 920 | word)) | ||
| 921 | (new-line 2)) | ||
| 922 | (if new-word | ||
| 923 | (progn | ||
| 924 | (save-excursion | ||
| 925 | (set-buffer (get-buffer-create ispell-choices-buffer)) | ||
| 926 | (erase-buffer) | ||
| 927 | (setq count ?0 | ||
| 928 | skipped 0 | ||
| 929 | mode-line-format "-- %b --" | ||
| 930 | miss (lookup-words new-word) | ||
| 931 | choices miss) | ||
| 932 | (while (and choices ; adjust choices window. | ||
| 933 | (< (if (> (+ 7 (current-column) | ||
| 934 | (length (car choices)) | ||
| 935 | (if (> count ?~) 3 0)) | ||
| 936 | (window-width)) | ||
| 937 | (progn | ||
| 938 | (insert "\n") | ||
| 939 | (setq new-line (1+ new-line))) | ||
| 940 | new-line) | ||
| 941 | max-lines)) | ||
| 942 | (while (memq count command-characters) | ||
| 943 | (setq count (1+ count) | ||
| 944 | skipped (1+ skipped))) | ||
| 945 | (insert "(" count ") " (car choices) " ") | ||
| 946 | (setq choices (cdr choices) | ||
| 947 | count (1+ count))) | ||
| 948 | (setq count (- count ?0 skipped))) | ||
| 949 | (select-window (previous-window)) | ||
| 950 | (if (/= new-line line) | ||
| 951 | (progn | ||
| 952 | (if (> new-line line) | ||
| 953 | (enlarge-window (- new-line line)) | ||
| 954 | (shrink-window (- line new-line))) | ||
| 955 | (setq line new-line))) | ||
| 956 | (select-window (next-window))))) | ||
| 957 | t) ; reselect from new choices | ||
| 958 | ((= char ?u) | ||
| 959 | (process-send-string ispell-process | ||
| 960 | (concat "*" (downcase word) "\n")) | ||
| 961 | (setq ispell-pdict-modified-p '(t)) ; dictionary was modified! | ||
| 962 | nil) | ||
| 963 | ((= char ?m) ; type in what to insert | ||
| 964 | (process-send-string | ||
| 965 | ispell-process (concat "*" (read-string "Insert: " word) "\n")) | ||
| 966 | (setq ispell-pdict-modified-p '(t)) | ||
| 967 | (cons word nil)) | ||
| 968 | ((and (>= num 0) (< num count)) | ||
| 969 | (if ispell-query-replace-choices ; Query replace when flag set. | ||
| 970 | (list (nth num miss) 'query-replace) | ||
| 971 | (nth num miss))) | ||
| 972 | ((= char ?\C-l) | ||
| 973 | (redraw-display) t) | ||
| 974 | ((= char ?\C-r) | ||
| 975 | (save-window-excursion (recursive-edit)) t) | ||
| 976 | ((= char ?\C-z) | ||
| 977 | (suspend-emacs) t) | ||
| 978 | (t (ding) t)))))) | ||
| 979 | result)) | ||
| 980 | (if (not ispell-keep-choices-win) (bury-buffer ispell-choices-buffer)))) | ||
| 981 | |||
| 982 | |||
| 983 | (defun ispell-help () | ||
| 984 | "This gives a list of the options available when a misspelling is encountered. | ||
| 985 | |||
| 986 | Selections are: | ||
| 987 | |||
| 988 | DIGIT: Replace the word with a digit offered in the *Choices* buffer. | ||
| 989 | ' ': Accept word this time. | ||
| 990 | 'i': Accept word and insert into private dictionary. | ||
| 991 | 'a': Accept word for this session. | ||
| 992 | 'A': Accept word and place in `buffer-local dictionary'. | ||
| 993 | 'r': Replace word with typed-in value. Rechecked. | ||
| 994 | 'R': Replace word with typed-in value. Query-replaced in buffer. Rechecked. | ||
| 995 | '?': Show these commands. | ||
| 996 | 'x': Exit spelling buffer. Move cursor to original point. | ||
| 997 | 'X': Exit spelling buffer. Leaves cursor at the current point, and permits | ||
| 998 | the aborted check to be completed later. | ||
| 999 | 'q': Quit spelling session (Kills ispell process). | ||
| 1000 | 'l': Look up typed-in replacement in alternate dictionary. Wildcards okay. | ||
| 1001 | 'u': Like 'i', but the word is lower-cased first. | ||
| 1002 | 'm': Like 'i', but allows one to include dictionary completion information. | ||
| 1003 | 'C-l': redraws screen | ||
| 1004 | 'C-r': recursive edit | ||
| 1005 | 'C-z': suspend emacs" | ||
| 1006 | |||
| 1007 | (let ((help-1 "[r/R]eplace word; [a/A]ccept for this session; [i]nsert into private dictionary") | ||
| 1008 | (help-2 "[l]ook a word up in alternate dictionary; e[x/X]it; [q]uit session") | ||
| 1009 | (help-3 "[u]ncapitalized insert into dictionary. Type 'C-h d ispell-help' for more help")) | ||
| 1010 | (save-window-excursion | ||
| 1011 | (if ispell-help-in-bufferp | ||
| 1012 | (progn | ||
| 1013 | (ispell-overlay-window 4) | ||
| 1014 | (switch-to-buffer (get-buffer-create "*Ispell Help*")) | ||
| 1015 | (insert (concat help-1 "\n" help-2 "\n" help-3)) | ||
| 1016 | (sit-for 5) | ||
| 1017 | (kill-buffer "*Ispell Help*")) | ||
| 1018 | (select-window (minibuffer-window)) | ||
| 1019 | (enlarge-window 2) | ||
| 1020 | (erase-buffer) | ||
| 1021 | (cond ((string-match "Lucid" emacs-version) | ||
| 1022 | (message help-3) | ||
| 1023 | (enlarge-window 1) | ||
| 1024 | (message help-2) | ||
| 1025 | (enlarge-window 1) | ||
| 1026 | (message help-1)) | ||
| 1027 | (t | ||
| 1028 | (if (string-match "^19\\." emacs-version) | ||
| 1029 | (message nil)) | ||
| 1030 | (enlarge-window 2) | ||
| 1031 | (insert (concat help-1 "\n" help-2 "\n" help-3)))) | ||
| 1032 | (sit-for 5) | ||
| 1033 | (erase-buffer))))) | ||
| 1034 | |||
| 1035 | |||
| 1036 | (defun lookup-words (word &optional lookup-dict) | ||
| 1037 | "Look up word in word-list dictionary. | ||
| 1038 | A '*' is used for wild cards. If no wild cards, 'look' is used if it exists. | ||
| 1039 | Otherwise the variable ispell-grep-command contains the command used to | ||
| 1040 | search for the words (usually egrep). | ||
| 1041 | Optional second argument contains the dictionary to use, the default is | ||
| 1042 | ispell-alternate-dictionary." | ||
| 1043 | ;; We don't use the filter for this function, rather the result is written | ||
| 1044 | ;; into a buffer. Hence there is no need to save the filter values. | ||
| 1045 | (if (null lookup-dict) | ||
| 1046 | (setq lookup-dict ispell-alternate-dictionary)) | ||
| 1047 | |||
| 1048 | (let* ((process-connection-type ispell-use-ptys-p) | ||
| 1049 | (wild-p (string-match "\\*" word)) | ||
| 1050 | (look-p (and ispell-look-p ; Only use look for an exact match. | ||
| 1051 | (or ispell-have-new-look (not wild-p)))) | ||
| 1052 | (ispell-grep-buffer (get-buffer-create "*Ispell-Temp*")) ; result buf | ||
| 1053 | (prog (if look-p ispell-look-command ispell-grep-command)) | ||
| 1054 | (args (if look-p ispell-look-options ispell-grep-options)) | ||
| 1055 | status results loc) | ||
| 1056 | (unwind-protect | ||
| 1057 | (save-window-excursion | ||
| 1058 | (message "Starting \"%s\" process..." (file-name-nondirectory prog)) | ||
| 1059 | (set-buffer ispell-grep-buffer) | ||
| 1060 | (if look-p | ||
| 1061 | nil | ||
| 1062 | ;; convert * to .* | ||
| 1063 | (insert "^" word "$") | ||
| 1064 | (while (search-backward "*" nil t) (insert ".")) | ||
| 1065 | (setq word (buffer-string)) | ||
| 1066 | (erase-buffer)) | ||
| 1067 | (setq status (call-process prog nil t nil args word lookup-dict)) | ||
| 1068 | ;; grep returns status 1 and no output when word not found, which | ||
| 1069 | ;; is a perfectly normal thing. | ||
| 1070 | (if (stringp status) | ||
| 1071 | (setq results (cons (format "error: %s exited with signal %s" | ||
| 1072 | (file-name-nondirectory prog) status) | ||
| 1073 | results)) | ||
| 1074 | ;; else collect words into `results' in FIFO order | ||
| 1075 | (goto-char (point-max)) | ||
| 1076 | ;; assure we've ended with \n | ||
| 1077 | (or (bobp) (= (preceding-char) ?\n) (insert ?\n)) | ||
| 1078 | (while (not (bobp)) | ||
| 1079 | (setq loc (point)) | ||
| 1080 | (forward-line -1) | ||
| 1081 | (setq results (cons (buffer-substring (point) (1- loc)) | ||
| 1082 | results))))) | ||
| 1083 | ;; protected | ||
| 1084 | (kill-buffer ispell-grep-buffer) | ||
| 1085 | (if (and results (string-match ".+: " (car results))) | ||
| 1086 | (error "%s error: %s" ispell-grep-command (car results)))) | ||
| 1087 | results)) | ||
| 1088 | |||
| 1089 | |||
| 1090 | ;;; "ispell-filter" is a list of output lines from the generating function. | ||
| 1091 | ;;; Each full line (ending with \n) is a separate item on the list. | ||
| 1092 | ;;; "output" can contain multiple lines, part of a line, or both. | ||
| 1093 | ;;; "start" and "end" are used to keep bounds on lines when "output" contains | ||
| 1094 | ;;; multiple lines. | ||
| 1095 | ;;; "ispell-filter-continue" is true when we have received only part of a | ||
| 1096 | ;;; line as output from a generating function ("output" did not end with \n) | ||
| 1097 | ;;; NOTE THAT THIS FUNCTION WILL FAIL IF THE PROCESS OUTPUT DOESNT END WITH \n! | ||
| 1098 | ;;; This is the case when a process dies or fails. The default behavior | ||
| 1099 | ;;; in this case treats the next input received as fresh input. | ||
| 1100 | |||
| 1101 | (defun ispell-filter (process output) | ||
| 1102 | "Output filter function for ispell, grep, and look." | ||
| 1103 | (let ((start 0) | ||
| 1104 | (continue t) | ||
| 1105 | end) | ||
| 1106 | (while continue | ||
| 1107 | (setq end (string-match "\n" output start)) ; get text up to the newline. | ||
| 1108 | ;; If we get out of sync and ispell-filter-continue is asserted when we | ||
| 1109 | ;; are not continuing, treat the next item as a separate list. When | ||
| 1110 | ;; ispell-filter-continue is asserted, ispell-filter *should* always be a | ||
| 1111 | ;; list! | ||
| 1112 | |||
| 1113 | ;; Continue with same line (item)? | ||
| 1114 | (if (and ispell-filter-continue ispell-filter (listp ispell-filter)) | ||
| 1115 | ;; Yes. Add it to the prev item | ||
| 1116 | (setcar ispell-filter | ||
| 1117 | (concat (car ispell-filter) (substring output start end))) | ||
| 1118 | ;; No. This is a new line and item. | ||
| 1119 | (setq ispell-filter | ||
| 1120 | (cons (substring output start end) ispell-filter))) | ||
| 1121 | (if (null end) | ||
| 1122 | ;; We've completed reading the output, but didn't finish the line. | ||
| 1123 | (setq ispell-filter-continue t continue nil) | ||
| 1124 | ;; skip over newline, this line complete. | ||
| 1125 | (setq ispell-filter-continue nil end (1+ end)) | ||
| 1126 | (if (= end (length output)) ; No more lines in output | ||
| 1127 | (setq continue nil) ; so we can exit the filter. | ||
| 1128 | (setq start end)))))) ; else move start to next line of input | ||
| 1129 | |||
| 1130 | |||
| 1131 | ;;; This function destroys the mark location if it is in the word being | ||
| 1132 | ;;; highlighted. | ||
| 1133 | (defun highlight-spelling-error-generic (start end &optional highlight) | ||
| 1134 | "Highlight the word from START to END by deleting and reinserting it | ||
| 1135 | while toggling the variable \"inverse-video\". When the optional | ||
| 1136 | third arg HIGHLIGHT is set, the word is highlighted otherwise it is | ||
| 1137 | displayed normally." | ||
| 1138 | (let ((modified (buffer-modified-p)) ; don't allow this fn to modify buffer | ||
| 1139 | (buffer-read-only nil) ; Allow highlighting read-only buffers. | ||
| 1140 | (text (buffer-substring start end)) ; Save highlight region | ||
| 1141 | (inhibit-quit t) ; inhibit interrupt processing here. | ||
| 1142 | (buffer-undo-list nil)) ; don't clutter the undo list. | ||
| 1143 | (delete-region start end) | ||
| 1144 | (insert-char ? (- end start)) ; mimimize amount of redisplay | ||
| 1145 | (sit-for 0) ; update display | ||
| 1146 | (if highlight (setq inverse-video (not inverse-video))) ; toggle video | ||
| 1147 | (delete-region start end) ; delete whitespace | ||
| 1148 | (insert text) ; insert text in inverse video. | ||
| 1149 | (sit-for 0) ; update display showing inverse video. | ||
| 1150 | (if highlight (setq inverse-video (not inverse-video))) ; toggle video | ||
| 1151 | (set-buffer-modified-p modified))) ; don't modify if flag not set. | ||
| 1152 | |||
| 1153 | |||
| 1154 | (defun highlight-spelling-error-lucid (start end &optional highlight) | ||
| 1155 | "Highlight the word from START to END using isearch-highlight. When | ||
| 1156 | the optional third arg HIGHLIGHT is set, the word is highlighted | ||
| 1157 | otherwise it is displayed normally." | ||
| 1158 | (if highlight | ||
| 1159 | (isearch-highlight start end) | ||
| 1160 | (isearch-dehighlight t)) | ||
| 1161 | ;;(sit-for 0) | ||
| 1162 | ) | ||
| 1163 | |||
| 1164 | |||
| 1165 | (defun highlight-spelling-error-overlay (start end &optional highlight) | ||
| 1166 | "Highlight the word from START to END using overlays. When the | ||
| 1167 | optional third arg HIGHLIGHT is set, the word is highlighted otherwise | ||
| 1168 | it is displayed normally. | ||
| 1169 | The variable ispell-highlight-face selects the face that will be used | ||
| 1170 | for highlighting." | ||
| 1171 | (if highlight | ||
| 1172 | (progn | ||
| 1173 | (setq ispell-overlay (make-overlay start end)) | ||
| 1174 | (overlay-put ispell-overlay 'face ispell-highlight-face)) | ||
| 1175 | (delete-overlay ispell-overlay))) | ||
| 1176 | |||
| 1177 | |||
| 1178 | ;;; Choose a highlight function at load time. | ||
| 1179 | (fset 'highlight-spelling-error | ||
| 1180 | (symbol-function | ||
| 1181 | (cond | ||
| 1182 | ((string-match "Lucid" emacs-version) 'highlight-spelling-error-lucid) | ||
| 1183 | ((and (string-match "^19\\." emacs-version) | ||
| 1184 | (featurep 'faces)) 'highlight-spelling-error-overlay) | ||
| 1185 | (t 'highlight-spelling-error-generic)))) | ||
| 1186 | |||
| 1187 | |||
| 1188 | (defun ispell-overlay-window (height) | ||
| 1189 | "Create a (usually small) window covering the top HEIGHT lines of the | ||
| 1190 | current window. Ensure that the line above point is still visible but | ||
| 1191 | otherwise avoid scrolling the current window. Should leave the old | ||
| 1192 | window selected." | ||
| 1193 | (save-excursion | ||
| 1194 | (let ((oldot (save-excursion (forward-line -1) (point))) | ||
| 1195 | (top (save-excursion (move-to-window-line height) (point)))) | ||
| 1196 | ;; If line above old point (line starting at olddot) would be | ||
| 1197 | ;; hidden by new window, scroll it to just below new win | ||
| 1198 | ;; otherwise set top line of other win so it doesn't scroll. | ||
| 1199 | (if (< oldot top) (setq top oldot)) | ||
| 1200 | (split-window nil height) | ||
| 1201 | (set-window-start (next-window) top)))) | ||
| 1202 | |||
| 1203 | |||
| 1204 | ;;; Should we add a compound word match return value? | ||
| 1205 | (defun ispell-parse-output (output) | ||
| 1206 | "Parse the OUTPUT string of 'ispell' and return: | ||
| 1207 | 1: T for an exact match. | ||
| 1208 | 2: A string containing the root word for a match via suffix removal. | ||
| 1209 | 3: A list of possible correct spellings of the format: | ||
| 1210 | '(\"original-word\" offset miss-list guess-list) | ||
| 1211 | original-word is a string of the possibly misspelled word. | ||
| 1212 | offset is an integer giving the line offset of the word. | ||
| 1213 | miss-list and guess-list are possibly null lists of guesses and misses." | ||
| 1214 | (cond | ||
| 1215 | ((string= output "") t) ; for startup with pipes... | ||
| 1216 | ((string= output "*") t) ; exact match | ||
| 1217 | ((string= output "-") t) ; compound word match | ||
| 1218 | ((string= (substring output 0 1) "+") ; found cuz of root word | ||
| 1219 | (substring output 2)) ; return root word | ||
| 1220 | (t ; need to process &, ?, and #'s | ||
| 1221 | (let ((type (substring output 0 1)) ; &, ?, or # | ||
| 1222 | (original-word (substring output 2 (string-match " " output 2))) | ||
| 1223 | (cur-count 0) ; contains number of misses + guesses | ||
| 1224 | count miss-list guess-list offset) | ||
| 1225 | (setq output (substring output (match-end 0))) ; skip over misspelling | ||
| 1226 | (if (string= type "#") | ||
| 1227 | (setq count 0) ; no misses for type # | ||
| 1228 | (setq count (string-to-int output) ; get number of misses. | ||
| 1229 | output (substring output (1+ (string-match " " output 1))))) | ||
| 1230 | (setq offset (string-to-int output)) | ||
| 1231 | (if (string= type "#") ; No miss or guess list. | ||
| 1232 | (setq output nil) | ||
| 1233 | (setq output (substring output (1+ (string-match " " output 1))))) | ||
| 1234 | (while output | ||
| 1235 | (let ((end (string-match ", \\|\\($\\)" output))) ; end of miss/guess. | ||
| 1236 | (setq cur-count (1+ cur-count)) | ||
| 1237 | (if (> cur-count count) | ||
| 1238 | (setq guess-list (cons (substring output 0 end) guess-list)) | ||
| 1239 | (setq miss-list (cons (substring output 0 end) miss-list))) | ||
| 1240 | (if (match-end 1) ; True only when at end of line. | ||
| 1241 | (setq output nil) ; no more misses or guesses | ||
| 1242 | (setq output (substring output (+ end 2)))))) | ||
| 1243 | (list original-word offset miss-list guess-list))))) | ||
| 1244 | |||
| 1245 | |||
| 1246 | (defun check-ispell-version () | ||
| 1247 | ;; This is a little wasteful as we actually launch ispell twice: once | ||
| 1248 | ;; to make sure it's the right version, and once for real. But people | ||
| 1249 | ;; get confused by version mismatches *all* the time (and I've got the | ||
| 1250 | ;; email to prove it) so I think this is worthwhile. And the -v[ersion] | ||
| 1251 | ;; option is the only way I can think of to do this that works with | ||
| 1252 | ;; all versions, since versions earlier than 3.0.09 didn't identify | ||
| 1253 | ;; themselves on startup. | ||
| 1254 | ;; | ||
| 1255 | ;; If the ispell.el file ever supports more than one version of the | ||
| 1256 | ;; external ispell program, then this should be reworked to accept more | ||
| 1257 | ;; than one version, but until that happens, doing so would be false | ||
| 1258 | ;; generality. | ||
| 1259 | ;; | ||
| 1260 | (save-excursion | ||
| 1261 | (set-buffer (get-buffer-create " *ispell-tmp*")) | ||
| 1262 | (erase-buffer) | ||
| 1263 | (let ((status (call-process ispell-program-name nil t nil "-v")) | ||
| 1264 | (case-fold-search t)) | ||
| 1265 | (goto-char (point-min)) | ||
| 1266 | (cond ((not (memq status '(0 nil))) | ||
| 1267 | (error "%s exited with %s %s" ispell-program-name | ||
| 1268 | (if (stringp status) "signal" "code") status)) | ||
| 1269 | ((not (re-search-forward | ||
| 1270 | (concat "\\b\\(" | ||
| 1271 | (mapconcat 'regexp-quote | ||
| 1272 | ispell-required-versions | ||
| 1273 | "\\|") | ||
| 1274 | "\\)\\b") | ||
| 1275 | nil t)) | ||
| 1276 | (error "version mismatch: ispell.el is for %s, %s is %s" | ||
| 1277 | (car ispell-required-versions) | ||
| 1278 | ispell-program-name | ||
| 1279 | (if (re-search-forward "version \\([0-9][0-9.]+\\)\\b" | ||
| 1280 | nil t) | ||
| 1281 | (buffer-substring (match-beginning 1) (match-end 1)) | ||
| 1282 | "an unknown version")))) | ||
| 1283 | (kill-buffer (current-buffer))))) | ||
| 1284 | |||
| 1285 | |||
| 1286 | (defun ispell-init-process () | ||
| 1287 | "Check status of 'ispell' process and start if necessary." | ||
| 1288 | (if (and ispell-process | ||
| 1289 | (eq (process-status ispell-process) 'run) | ||
| 1290 | ;; If we're using a personal dictionary, assure | ||
| 1291 | ;; we're in the same default directory! | ||
| 1292 | (or (not ispell-personal-dictionary) | ||
| 1293 | (equal ispell-process-directory default-directory))) | ||
| 1294 | (setq ispell-filter nil ispell-filter-continue nil) | ||
| 1295 | ;; may need to restart to select new personal dictionary. | ||
| 1296 | (ispell-kill-ispell t) | ||
| 1297 | (message "Starting new ispell process...") | ||
| 1298 | (sit-for 0) | ||
| 1299 | (check-ispell-version) | ||
| 1300 | (setq ispell-process | ||
| 1301 | (let ((process-connection-type ispell-use-ptys-p)) | ||
| 1302 | (apply 'start-process | ||
| 1303 | "ispell" nil ispell-program-name | ||
| 1304 | "-a" ; accept single input lines | ||
| 1305 | "-m" ; make root/affix combos not in dict | ||
| 1306 | (let (args) | ||
| 1307 | ;; Local dictionary becomes the global dictionary in use. | ||
| 1308 | (if ispell-local-dictionary | ||
| 1309 | (setq ispell-dictionary ispell-local-dictionary)) | ||
| 1310 | (setq args (ispell-get-ispell-args)) | ||
| 1311 | (if ispell-dictionary ; use specified dictionary | ||
| 1312 | (setq args | ||
| 1313 | (append (list "-d" ispell-dictionary) args))) | ||
| 1314 | (if ispell-personal-dictionary ; use specified pers dict | ||
| 1315 | (setq args | ||
| 1316 | (append args | ||
| 1317 | (list "-p" | ||
| 1318 | (expand-file-name | ||
| 1319 | ispell-personal-dictionary))))) | ||
| 1320 | args))) | ||
| 1321 | ispell-filter nil | ||
| 1322 | ispell-filter-continue nil | ||
| 1323 | ispell-process-directory default-directory) | ||
| 1324 | (set-process-filter ispell-process 'ispell-filter) | ||
| 1325 | (accept-process-output ispell-process) ; Get version ID line | ||
| 1326 | (cond ((null ispell-filter) | ||
| 1327 | (error "%s did not output version line")) | ||
| 1328 | ((and (null (cdr ispell-filter)) | ||
| 1329 | (stringp (car ispell-filter)) | ||
| 1330 | (string-match "^@(#) " (car ispell-filter))) | ||
| 1331 | ;; got the version line as expected (we already know it's the right | ||
| 1332 | ;; version, so don't bother checking again.) | ||
| 1333 | nil) | ||
| 1334 | (t | ||
| 1335 | ;; Otherwise, it must be an error message. Show the user. | ||
| 1336 | ;; But first wait to see if some more output is going to arrive. | ||
| 1337 | ;; Otherwise we get cool errors like "Can't open ". | ||
| 1338 | (sleep-for 1) | ||
| 1339 | (accept-process-output) | ||
| 1340 | (error "%s" (mapconcat 'identity ispell-filter "\n")))) | ||
| 1341 | (setq ispell-filter nil) ; Discard version ID line | ||
| 1342 | (let ((extended-char-mode (ispell-get-extended-character-mode))) | ||
| 1343 | (if extended-char-mode | ||
| 1344 | (process-send-string ispell-process | ||
| 1345 | (concat extended-char-mode "\n")))) | ||
| 1346 | (process-kill-without-query ispell-process))) | ||
| 1347 | |||
| 1348 | |||
| 1349 | (defun ispell-kill-ispell (&optional no-error) | ||
| 1350 | "Kill current ispell process (so that you may start a fresh one). | ||
| 1351 | With NO-ERROR, just return non-nil if there was no ispell running." | ||
| 1352 | (interactive) | ||
| 1353 | (if (not (and ispell-process | ||
| 1354 | (eq (process-status ispell-process) 'run))) | ||
| 1355 | (or no-error | ||
| 1356 | (error "There is no ispell process running!")) | ||
| 1357 | (kill-process ispell-process) | ||
| 1358 | (setq ispell-process nil) | ||
| 1359 | (message "Killed ispell process.") | ||
| 1360 | nil)) | ||
| 1361 | |||
| 1362 | |||
| 1363 | ;;;###autoload | ||
| 1364 | (defun ispell-change-dictionary (dict &optional arg) | ||
| 1365 | "Change ispell-dictionary (q.v.) and kill old ispell process. | ||
| 1366 | A new one will be started as soon as necessary. | ||
| 1367 | |||
| 1368 | By just answering RET you can find out what the current dictionary is. | ||
| 1369 | |||
| 1370 | With prefix argument, set the default directory." | ||
| 1371 | (interactive | ||
| 1372 | (list (completing-read | ||
| 1373 | "Use new dictionary (RET for current, SPC to complete): " | ||
| 1374 | (cons (cons "default" nil) ispell-dictionary-alist) nil t) | ||
| 1375 | current-prefix-arg)) | ||
| 1376 | (if (equal dict "default") (setq dict nil)) | ||
| 1377 | ;; This relies on completing-read's bug of returning "" for no match | ||
| 1378 | (cond ((equal dict "") | ||
| 1379 | (message "Using %s dictionary" | ||
| 1380 | (or ispell-local-dictionary ispell-dictionary "default"))) | ||
| 1381 | ((and (equal dict ispell-dictionary) | ||
| 1382 | (equal dict ispell-local-dictionary)) | ||
| 1383 | ;; Specified dictionary is the default already. No-op | ||
| 1384 | (message "No change, using %s dictionary" (or dict "default"))) | ||
| 1385 | (t ; reset dictionary! | ||
| 1386 | (if (assoc dict ispell-dictionary-alist) | ||
| 1387 | (progn | ||
| 1388 | (if (or arg (null dict)) ; set default dictionary | ||
| 1389 | (setq ispell-dictionary dict)) | ||
| 1390 | (if (null arg) ; set local dictionary | ||
| 1391 | (setq ispell-local-dictionary dict))) | ||
| 1392 | (error "Illegal dictionary: %s" dict)) | ||
| 1393 | (ispell-kill-ispell t) | ||
| 1394 | (message "(Next %sispell command will use %s dictionary)" | ||
| 1395 | (cond ((equal ispell-local-dictionary ispell-dictionary) | ||
| 1396 | "") | ||
| 1397 | (arg "global ") | ||
| 1398 | (t "local ")) | ||
| 1399 | (or (if (or (equal ispell-local-dictionary ispell-dictionary) | ||
| 1400 | (null arg)) | ||
| 1401 | ispell-local-dictionary | ||
| 1402 | ispell-dictionary) | ||
| 1403 | "default"))))) | ||
| 1404 | |||
| 1405 | |||
| 1406 | ;;; Spelling of comments are checked when ispell-check-comments is non-nil. | ||
| 1407 | |||
| 1408 | ;;;###autoload | ||
| 1409 | (defun ispell-region (reg-start reg-end) | ||
| 1410 | "Interactively check a region for spelling errors." | ||
| 1411 | (interactive "r") ; Don't flag errors on read-only bufs. | ||
| 1412 | (ispell-accept-buffer-local-defs) ; set up dictionary, local words, etc. | ||
| 1413 | (unwind-protect | ||
| 1414 | (save-excursion | ||
| 1415 | (message "Spelling %s..." | ||
| 1416 | (if (and (= reg-start (point-min)) (= reg-end (point-max))) | ||
| 1417 | (buffer-name) "region")) | ||
| 1418 | (sit-for 0) | ||
| 1419 | ;; must be top level now, not inside ispell-command-loop for keeping window. | ||
| 1420 | (save-window-excursion | ||
| 1421 | (if ispell-keep-choices-win | ||
| 1422 | (let ((window-min-height ispell-choices-win-default-height)) | ||
| 1423 | ;; This keeps the default window size when choices window saved. | ||
| 1424 | (setq ispell-keep-choices-win ispell-choices-win-default-height) | ||
| 1425 | (ispell-overlay-window ispell-choices-win-default-height) | ||
| 1426 | (switch-to-buffer (get-buffer-create ispell-choices-buffer)) | ||
| 1427 | (setq mode-line-format "-- %b --") | ||
| 1428 | (erase-buffer) | ||
| 1429 | (select-window (next-window)) | ||
| 1430 | (sit-for 0))) | ||
| 1431 | (goto-char reg-start) | ||
| 1432 | (let ((transient-mark-mode nil)) | ||
| 1433 | (while (and (not ispell-quit) (< (point) reg-end)) | ||
| 1434 | (let ((start (point)) | ||
| 1435 | (offset-change 0) | ||
| 1436 | (end (save-excursion (end-of-line) (min (point) reg-end))) | ||
| 1437 | (ispell-casechars (ispell-get-casechars)) | ||
| 1438 | string) | ||
| 1439 | (cond ; LOOK AT THIS LINE AND SKIP OR PROCESS | ||
| 1440 | ((eolp) ; END OF LINE, just go to next line. | ||
| 1441 | (forward-char 1)) | ||
| 1442 | ((and (null ispell-check-comments) ; SKIPING COMMENTS | ||
| 1443 | comment-start ; skip comments that start on the line. | ||
| 1444 | (search-forward comment-start end t)) ; a comment is on this line. | ||
| 1445 | (if (= (- (point) start) (length comment-start)) | ||
| 1446 | ;; comment starts the line. We can skip the entire line or region | ||
| 1447 | (if (string= "" comment-end) ; skip to next line over comment | ||
| 1448 | (beginning-of-line 2) | ||
| 1449 | (search-forward comment-end reg-end 'limit)) ; jmp to comment end | ||
| 1450 | ;; Comment starts later on line. Check for spelling before comment. | ||
| 1451 | (let ((limit (- (point) (length comment-start)))) | ||
| 1452 | (goto-char (1- limit)) | ||
| 1453 | (if (looking-at "\\\\") ; "quoted" comment, don't skip | ||
| 1454 | ;; quoted comment. Skip over comment-start and continue. | ||
| 1455 | (if (= start (1- limit)) | ||
| 1456 | (setq limit (+ limit (length comment-start))) | ||
| 1457 | (setq limit (1- limit)))) | ||
| 1458 | (goto-char start) | ||
| 1459 | ;; Only check if there are "casechars" or math chars before comment | ||
| 1460 | (if (or (re-search-forward ispell-casechars limit t) | ||
| 1461 | (re-search-forward "[][()$]" limit t)) | ||
| 1462 | (setq string (concat "^" (buffer-substring start limit) "\n"))) | ||
| 1463 | (goto-char limit)))) | ||
| 1464 | ((and ispell-skip-tib ; SKIP TIB REFERENCES! | ||
| 1465 | (re-search-forward ispell-tib-ref-beginning end t)) | ||
| 1466 | (if (= (- (point) 2) start) ; tib ref is 2 chars. | ||
| 1467 | ;; Skip to end of tib ref, not necessarily on this line. | ||
| 1468 | ;; Return an error if tib ref not found | ||
| 1469 | (if (not (re-search-forward ispell-tib-ref-end reg-end t)) | ||
| 1470 | (progn | ||
| 1471 | (ispell-pdict-save ispell-silently-savep) | ||
| 1472 | (ding) | ||
| 1473 | (message "Open tib reference. Set ispell-skip-tib to nil to avoid this error.") | ||
| 1474 | (setq ispell-quit (- (point) 2)))) ; leave dot at error loc. | ||
| 1475 | ;; tib ref starts later on line. Check spelling before tib. | ||
| 1476 | (let ((limit (- (point) 2))) | ||
| 1477 | (goto-char start) | ||
| 1478 | (if (or (re-search-forward ispell-casechars limit t) | ||
| 1479 | (re-search-forward "[][()$]" limit t)) | ||
| 1480 | (setq string (concat "^" (buffer-substring start limit) "\n"))) | ||
| 1481 | (goto-char limit)))) | ||
| 1482 | ((looking-at "[---#@*+!%~^]") ; SKIP SPECIAL ISPELL CHARACTERS | ||
| 1483 | (forward-char 1)) | ||
| 1484 | ((or (re-search-forward ispell-casechars end t) ; TEXT EXISTS... | ||
| 1485 | (re-search-forward "[][()$]" end t)) ; or MATH COMMANDS... | ||
| 1486 | (setq string (concat "^" (buffer-substring start end) "\n")) | ||
| 1487 | (goto-char end)) | ||
| 1488 | (t (beginning-of-line 2))) ; EMPTY LINE, skip it. | ||
| 1489 | |||
| 1490 | (setq end (point)) ; "end" tracks end of region to check. | ||
| 1491 | |||
| 1492 | (if string ; there is something to spell! | ||
| 1493 | (let (poss) | ||
| 1494 | ;; send string to spell process and get input. | ||
| 1495 | (process-send-string ispell-process string) | ||
| 1496 | (while (progn | ||
| 1497 | (accept-process-output ispell-process) | ||
| 1498 | ;; Last item of output contains a blank line. | ||
| 1499 | (not (string= "" (car ispell-filter))))) | ||
| 1500 | ;; parse all inputs from the stream one word at a time. | ||
| 1501 | ;; Place in FIFO order and remove the blank item. | ||
| 1502 | (setq ispell-filter (nreverse (cdr ispell-filter))) | ||
| 1503 | (while (and (not ispell-quit) ispell-filter) | ||
| 1504 | (setq poss (ispell-parse-output (car ispell-filter))) | ||
| 1505 | (if (listp poss) ; spelling error occurred. | ||
| 1506 | (let* ((word-start (+ start offset-change (car (cdr poss)))) | ||
| 1507 | (word-end (+ word-start (length (car poss)))) | ||
| 1508 | replace) | ||
| 1509 | (goto-char word-start) | ||
| 1510 | ;; The following lines adjust the horizontal scroll & point | ||
| 1511 | (horiz-scroll) | ||
| 1512 | (goto-char word-end) | ||
| 1513 | (horiz-scroll) | ||
| 1514 | (goto-char word-start) | ||
| 1515 | (horiz-scroll) | ||
| 1516 | (if (/= word-end (progn | ||
| 1517 | (search-forward (car poss) word-end t) | ||
| 1518 | (point))) | ||
| 1519 | ;; This usually occurs due to filter pipe problems | ||
| 1520 | (error "***ispell misalignment: word \"%s\" point %d; please retry." | ||
| 1521 | (car poss) word-start)) | ||
| 1522 | (unwind-protect | ||
| 1523 | (progn | ||
| 1524 | (if ispell-highlight-p | ||
| 1525 | (highlight-spelling-error word-start word-end t)) | ||
| 1526 | (sit-for 0) ; update screen display | ||
| 1527 | (setq replace (ispell-command-loop | ||
| 1528 | (car (cdr (cdr poss))) | ||
| 1529 | (car (cdr (cdr (cdr poss)))) | ||
| 1530 | (car poss)))) | ||
| 1531 | ;; protected | ||
| 1532 | (if ispell-highlight-p | ||
| 1533 | (highlight-spelling-error word-start word-end))) | ||
| 1534 | (cond | ||
| 1535 | ((and replace (listp replace)) | ||
| 1536 | ;; REPLACEMENT WORD entered. Recheck line starting with | ||
| 1537 | ;; the replacement word. | ||
| 1538 | (setq ispell-filter nil | ||
| 1539 | string (buffer-substring word-start word-end)) | ||
| 1540 | (let ((change (- (length (car replace)) ; adjust | ||
| 1541 | (length (car poss))))) ; regions | ||
| 1542 | (setq reg-end (+ reg-end change) | ||
| 1543 | offset-change (+ offset-change change))) | ||
| 1544 | (delete-region word-start word-end) | ||
| 1545 | (insert (car replace)) | ||
| 1546 | ;; I only need to recheck typed-in replacements. | ||
| 1547 | (if (not (eq 'query-replace (car (cdr replace)))) | ||
| 1548 | (backward-char (length (car replace)))) | ||
| 1549 | (setq end (point)) ; reposition in region to recheck | ||
| 1550 | ;; when second arg exists, query-replace, saving regions | ||
| 1551 | (if (car (cdr replace)) | ||
| 1552 | (unwind-protect | ||
| 1553 | (save-window-excursion ; save if help is called. | ||
| 1554 | (set-marker ispell-query-replace-marker reg-end) | ||
| 1555 | ;; Assume case-replace & case-fold-search correct? | ||
| 1556 | (query-replace string (car replace) t)) | ||
| 1557 | ;; protected | ||
| 1558 | (setq reg-end (marker-position | ||
| 1559 | ispell-query-replace-marker)) | ||
| 1560 | (set-marker ispell-query-replace-marker nil)))) | ||
| 1561 | ((or (null replace) (equal 0 replace)) ; ACCEPT/INSERT | ||
| 1562 | (if (equal 0 replace) ; BUFFER-LOCAL DICTIONARY ADD | ||
| 1563 | (setq reg-end (ispell-add-per-file-word-list | ||
| 1564 | (car poss) reg-end))) | ||
| 1565 | ;; This prevents us from pointing out the word that was | ||
| 1566 | ;; just accepted (via 'i' or 'a') if it follows on the | ||
| 1567 | ;; same line. (The drawback of processing entire lines.) | ||
| 1568 | ;; Redo check following the accepted word. | ||
| 1569 | (if (and ispell-pdict-modified-p | ||
| 1570 | (listp ispell-pdict-modified-p)) | ||
| 1571 | ;; We have accepted or inserted a word. Re-check line | ||
| 1572 | (setq ispell-pdict-modified-p ; fix update flag | ||
| 1573 | (car ispell-pdict-modified-p) | ||
| 1574 | ispell-filter nil ; don't continue check. | ||
| 1575 | end word-start))) ; reposition continue loc | ||
| 1576 | (replace ; STRING REPLACEMENT for this word. | ||
| 1577 | (delete-region word-start word-end) | ||
| 1578 | (insert replace) | ||
| 1579 | (let ((change (- (length replace) (length (car poss))))) | ||
| 1580 | (setq reg-end (+ reg-end change) | ||
| 1581 | offset-change (+ offset-change change) | ||
| 1582 | end (+ end change))))) | ||
| 1583 | (if (not ispell-quit) | ||
| 1584 | (message "continuing spelling check...")) | ||
| 1585 | (sit-for 0))) | ||
| 1586 | (setq ispell-filter (cdr ispell-filter))))) ; finished with line | ||
| 1587 | (goto-char end))))) | ||
| 1588 | (not ispell-quit)) | ||
| 1589 | ;; protected | ||
| 1590 | (if (get-buffer ispell-choices-buffer) | ||
| 1591 | (kill-buffer ispell-choices-buffer)) | ||
| 1592 | (if ispell-quit | ||
| 1593 | (progn | ||
| 1594 | ;; preserve or clear the region for ispell-continue. | ||
| 1595 | (if (not (numberp ispell-quit)) | ||
| 1596 | (set-marker ispell-region-end nil) | ||
| 1597 | ;; Enable ispell-continue. | ||
| 1598 | (set-marker ispell-region-end reg-end) | ||
| 1599 | (goto-char ispell-quit)) | ||
| 1600 | ;; Check for aborting | ||
| 1601 | (if (and ispell-checking-message (numberp ispell-quit)) | ||
| 1602 | (progn | ||
| 1603 | (setq ispell-quit nil) | ||
| 1604 | (error "Message send aborted."))) | ||
| 1605 | (setq ispell-quit nil)) | ||
| 1606 | (set-marker ispell-region-end nil) | ||
| 1607 | ;; Only save if successful exit. | ||
| 1608 | (ispell-pdict-save ispell-silently-savep) | ||
| 1609 | (message "Spell done.")))) | ||
| 1610 | |||
| 1611 | |||
| 1612 | |||
| 1613 | ;;;###autoload | ||
| 1614 | (defun ispell-buffer () | ||
| 1615 | "Check the current buffer for spelling errors interactively." | ||
| 1616 | (interactive) | ||
| 1617 | (ispell-region (point-min) (point-max))) | ||
| 1618 | |||
| 1619 | |||
| 1620 | (defun ispell-continue () | ||
| 1621 | (interactive) | ||
| 1622 | "Continue a spelling session after making some changes." | ||
| 1623 | (if (not (marker-position ispell-region-end)) | ||
| 1624 | (message "No session to continue. Use 'X' command when checking!") | ||
| 1625 | (if (not (equal (marker-buffer ispell-region-end) (current-buffer))) | ||
| 1626 | (message "Must continue ispell from buffer %s" | ||
| 1627 | (buffer-name (marker-buffer ispell-region-end))) | ||
| 1628 | (ispell-region (point) (marker-position ispell-region-end))))) | ||
| 1629 | |||
| 1630 | |||
| 1631 | ;;; Horizontal scrolling | ||
| 1632 | (defun horiz-scroll () | ||
| 1633 | "This function checks if the point is within the horizontal | ||
| 1634 | visibility of its window area." | ||
| 1635 | (if truncate-lines ; display truncating lines? | ||
| 1636 | ;; See if display needs to be scrolled. | ||
| 1637 | (let ((column (- (current-column) (max (window-hscroll) 1)))) | ||
| 1638 | (if (and (< column 0) (> (window-hscroll) 0)) | ||
| 1639 | (scroll-right (max (- column) 10)) | ||
| 1640 | (if (>= column (- (window-width) 2)) | ||
| 1641 | (scroll-left (max (- column (window-width) -3) 10))))))) | ||
| 1642 | |||
| 1643 | |||
| 1644 | ;;; Interactive word completion. | ||
| 1645 | ;;; Forces "previous-word" processing. Do we want to make this selectable? | ||
| 1646 | |||
| 1647 | ;;;###autoload | ||
| 1648 | (defun ispell-complete-word (&optional interior-frag) | ||
| 1649 | "Look up word before or under point in dictionary (see lookup-words command) | ||
| 1650 | and try to complete it. If optional INTERIOR-FRAG is non-nil then the word | ||
| 1651 | may be a character sequence inside of a word. | ||
| 1652 | |||
| 1653 | Standard ispell choices are then available." | ||
| 1654 | (interactive "P") | ||
| 1655 | (let ((cursor-location (point)) | ||
| 1656 | ispell-keep-choices-win | ||
| 1657 | (word (ispell-get-word nil "\\*")) ; force "previous-word" processing. | ||
| 1658 | start end possibilities replacement) | ||
| 1659 | (setq start (car (cdr word)) | ||
| 1660 | end (car (cdr (cdr word))) | ||
| 1661 | word (car word) | ||
| 1662 | possibilities | ||
| 1663 | (or (string= word "") ; Will give you every word | ||
| 1664 | (lookup-words (concat (if interior-frag "*") word "*") | ||
| 1665 | ispell-complete-word-dict))) | ||
| 1666 | (cond ((eq possibilities t) | ||
| 1667 | (message "No word to complete")) | ||
| 1668 | ((null possibilities) | ||
| 1669 | (message "No match for \"%s\"" word)) | ||
| 1670 | (t ; There is a modification... | ||
| 1671 | (unwind-protect | ||
| 1672 | (progn | ||
| 1673 | (if ispell-highlight-p | ||
| 1674 | (highlight-spelling-error start end t)) ; highlight word | ||
| 1675 | (setq replacement (ispell-command-loop possibilities nil word))) | ||
| 1676 | ;; protected | ||
| 1677 | (if ispell-highlight-p | ||
| 1678 | (highlight-spelling-error start end))) ; un-highlight | ||
| 1679 | (cond | ||
| 1680 | ((equal 0 replacement) ; BUFFER-LOCAL ADDITION | ||
| 1681 | (ispell-add-per-file-word-list word)) | ||
| 1682 | (replacement ; REPLACEMENT WORD | ||
| 1683 | (delete-region start end) | ||
| 1684 | (setq word (if (atom replacement) replacement (car replacement)) | ||
| 1685 | cursor-location (+ (- (length word) (- end start)) | ||
| 1686 | cursor-location)) | ||
| 1687 | (insert word) | ||
| 1688 | (if (not (atom replacement)) ; recheck spelling of replacement. | ||
| 1689 | (progn | ||
| 1690 | (goto-char cursor-location) | ||
| 1691 | (ispell-word nil t))))) | ||
| 1692 | (if (get-buffer ispell-choices-buffer) | ||
| 1693 | (kill-buffer ispell-choices-buffer)))) | ||
| 1694 | (ispell-pdict-save ispell-silently-savep) | ||
| 1695 | (goto-char cursor-location))) | ||
| 1696 | |||
| 1697 | |||
| 1698 | ;;;###autoload | ||
| 1699 | (defun ispell-complete-word-interior-frag () | ||
| 1700 | "Runs `ispell-complete-word' assuming that the word is a character sequence | ||
| 1701 | inside of a word." | ||
| 1702 | (interactive) | ||
| 1703 | (ispell-complete-word t)) | ||
| 1704 | |||
| 1705 | |||
| 1706 | ;;; ********************************************************************** | ||
| 1707 | ;;; Ispell Message | ||
| 1708 | ;;; ********************************************************************** | ||
| 1709 | ;;; Original from Daniel Quinlan, Ethan Bradford, and Alon Albert | ||
| 1710 | |||
| 1711 | |||
| 1712 | ;;;###autoload | ||
| 1713 | (defun ispell-message () | ||
| 1714 | "Check the spelling of a mail message or news post. | ||
| 1715 | Don't check spelling of message headers except the Subject field. | ||
| 1716 | Don't check included messages. | ||
| 1717 | |||
| 1718 | To abort spell checking of a message REGION and send the message anyway, | ||
| 1719 | use the 'x' or 'q' command. (Any subsequent regions will be checked.) | ||
| 1720 | The 'X' command aborts the message send so that you can edit the buffer. | ||
| 1721 | |||
| 1722 | To spell-check whenever a message is sent, include the appropriate lines | ||
| 1723 | in your .emacs file: | ||
| 1724 | (add-hook 'news-inews-hook 'ispell-message) | ||
| 1725 | (add-hook 'mail-send-hook 'ispell-message) | ||
| 1726 | (add-hook 'mh-before-send-letter-hook 'ispell-message) | ||
| 1727 | |||
| 1728 | Or you can bind the function C-c i in gnus or mail by setting | ||
| 1729 | news-reply-mode-hook or mail-mode-hook to the following lambda expression: | ||
| 1730 | (function (lambda () (local-set-key \"\\C-ci\" 'ispell-message)))" | ||
| 1731 | (interactive) | ||
| 1732 | (let* ((internal-messagep (save-excursion | ||
| 1733 | (search-forward mail-header-separator nil t))) | ||
| 1734 | (cite-regexp ;Prefix of inserted text | ||
| 1735 | (cond | ||
| 1736 | ((featurep 'supercite) ; sc 3.0 | ||
| 1737 | (concat "\\(" (sc-cite-regexp) "\\)" "\\|" | ||
| 1738 | (ispell-non-empty-string sc-reference-tag-string))) | ||
| 1739 | ((featurep 'sc) ; sc 2.3 | ||
| 1740 | (concat "\\(" sc-cite-regexp "\\)" "\\|" | ||
| 1741 | (ispell-non-empty-string sc-reference-tag-string))) | ||
| 1742 | ((equal major-mode 'news-reply-mode) ;Gnus | ||
| 1743 | (concat "In article <" "\\|" | ||
| 1744 | (if mail-yank-prefix | ||
| 1745 | (ispell-non-empty-string mail-yank-prefix) | ||
| 1746 | "^ \\|^\t"))) | ||
| 1747 | ((equal major-mode 'mh-letter-mode) ; mh mail message | ||
| 1748 | (ispell-non-empty-string mh-ins-buf-prefix)) | ||
| 1749 | ((not internal-messagep) ; Assume n sent us this message. | ||
| 1750 | (concat "In [a-zA-Z.]+ you write:" "\\|" | ||
| 1751 | "In <[^,;&+=]+> [^,;&+=]+ writes:" "\\|" | ||
| 1752 | " *> *")) | ||
| 1753 | ((boundp 'vm-included-text-prefix) ; VM mail message | ||
| 1754 | (concat "[^,;&+=]+ writes:" "\\|" | ||
| 1755 | (ispell-non-empty-string vm-included-text-prefix))) | ||
| 1756 | (mail-yank-prefix ; vanilla mail message. | ||
| 1757 | (ispell-non-empty-string mail-yank-prefix)) | ||
| 1758 | (t "^ \\|^\t"))) | ||
| 1759 | (cite-regexp-start (concat "^[ \t]*$\\|" cite-regexp)) | ||
| 1760 | (cite-regexp-end (concat "^\\(" cite-regexp "\\)")) | ||
| 1761 | (old-case-fold-search case-fold-search) | ||
| 1762 | (case-fold-search t) | ||
| 1763 | (ispell-checking-message t)) | ||
| 1764 | (save-excursion | ||
| 1765 | (beginning-of-buffer) | ||
| 1766 | ;; Skip header fields except Subject: without Re:'s | ||
| 1767 | ;;(search-forward mail-header-separator nil t) | ||
| 1768 | (while (if internal-messagep | ||
| 1769 | (< (point) internal-messagep) | ||
| 1770 | (and (looking-at "[a-zA-Z---]+:\\|\t\\| ") | ||
| 1771 | (not (eobp)))) | ||
| 1772 | (if (and (not (looking-at "Subject: .*Re:")) | ||
| 1773 | (not (looking-at "Subject: +\\[")) | ||
| 1774 | (looking-at "Subject:")) ; last so (match-end 0) works right. | ||
| 1775 | ;; spell check Subject: field without Re:'s. | ||
| 1776 | (let ((case-fold-search old-case-fold-search)) | ||
| 1777 | (end-of-line) | ||
| 1778 | (ispell-region (match-end 0) (point)))) | ||
| 1779 | (forward-line 1)) | ||
| 1780 | (setq case-fold-search nil) | ||
| 1781 | ;; Skip mail header, particularly for non-english languages. | ||
| 1782 | (if (looking-at mail-header-separator) | ||
| 1783 | (forward-line 1)) | ||
| 1784 | (while (not (eobp)) | ||
| 1785 | ;; Skip across text cited from other messages. | ||
| 1786 | (while (and (looking-at cite-regexp-start) | ||
| 1787 | (not (eobp))) | ||
| 1788 | (forward-line 1)) | ||
| 1789 | (if (not (eobp)) | ||
| 1790 | ;; Check the next batch of lines that *aren't* cited. | ||
| 1791 | (let ((end (save-excursion | ||
| 1792 | (if (re-search-forward cite-regexp-end nil 'end) | ||
| 1793 | (beginning-of-line)) | ||
| 1794 | (point)))) | ||
| 1795 | (ispell-region (point) end) | ||
| 1796 | (goto-char end))))))) | ||
| 1797 | |||
| 1798 | (defun ispell-non-empty-string (string) | ||
| 1799 | (if (or (not string) (string-equal string "")) | ||
| 1800 | "\\'\\`" ; An unmatchable string if string is null. | ||
| 1801 | (regexp-quote string))) | ||
| 1802 | |||
| 1803 | |||
| 1804 | ;;; ********************************************************************** | ||
| 1805 | ;;; Buffer Local Functions | ||
| 1806 | ;;; ********************************************************************** | ||
| 1807 | |||
| 1808 | |||
| 1809 | (defun ispell-accept-buffer-local-defs () | ||
| 1810 | "Loads all buffer-local information, restarting ispell when necessary." | ||
| 1811 | (ispell-buffer-local-dict) ; May kill ispell-process. | ||
| 1812 | (ispell-buffer-local-words) ; Will initialize ispell-process. | ||
| 1813 | (ispell-buffer-local-parsing)) | ||
| 1814 | |||
| 1815 | |||
| 1816 | ;;; Currently ispell version 3.0.09 (beta) doesn't fully support the "~" | ||
| 1817 | ;;; pipe mode command. Should be fixed in the next release. | ||
| 1818 | |||
| 1819 | (defun ispell-buffer-local-parsing () | ||
| 1820 | "Places ispell into parsing mode for this buffer. | ||
| 1821 | This overrides the default parsing mode. | ||
| 1822 | This includes latex/nroff modes and extended character mode." | ||
| 1823 | ;; (ispell-init-process) must already be called. | ||
| 1824 | (process-send-string ispell-process "!\n") ; Put process in terse mode. | ||
| 1825 | ;; We assume all major modes with "tex-mode" in them should use latex parsing | ||
| 1826 | (if (or (and (eq ispell-parser 'use-mode-name) | ||
| 1827 | (string-match "[Tt][Ee][Xx]-mode" (symbol-name major-mode))) | ||
| 1828 | (eq ispell-parser 'tex)) | ||
| 1829 | (process-send-string ispell-process "+\n") ; set ispell mode to tex | ||
| 1830 | (process-send-string ispell-process "-\n")) ; set mode to normal (nroff) | ||
| 1831 | ;; Set default extended character mode for given buffer, if any. | ||
| 1832 | (let ((extended-char-mode (ispell-get-extended-character-mode))) | ||
| 1833 | (if extended-char-mode | ||
| 1834 | (process-send-string ispell-process (concat extended-char-mode "\n")))) | ||
| 1835 | ;; Set buffer-local parsing mode and extended charater mode, if specified. | ||
| 1836 | (save-excursion | ||
| 1837 | (goto-char (point-min)) | ||
| 1838 | ;; Uses last valid definition | ||
| 1839 | (while (search-forward ispell-parsing-keyword nil t) | ||
| 1840 | (let ((end (save-excursion (end-of-line) (point))) | ||
| 1841 | (case-fold-search t) | ||
| 1842 | string) | ||
| 1843 | (while (re-search-forward " *\\([^ \"]+\\)" end t) | ||
| 1844 | ;; space separated definitions. | ||
| 1845 | (setq string (buffer-substring (match-beginning 1) (match-end 1))) | ||
| 1846 | (cond ((string-match "latex-mode" string) | ||
| 1847 | (process-send-string ispell-process "+\n")) | ||
| 1848 | ((string-match "nroff-mode" string) | ||
| 1849 | (process-send-string ispell-process "-\n")) | ||
| 1850 | ((string-match "~" string) ; Set extended character mode. | ||
| 1851 | (process-send-string ispell-process (concat string "\n"))) | ||
| 1852 | (t (message "Illegal Ispell Parsing argument!") | ||
| 1853 | (sit-for 2)))))))) | ||
| 1854 | |||
| 1855 | |||
| 1856 | ;;; Can kill the current ispell process | ||
| 1857 | |||
| 1858 | (defun ispell-buffer-local-dict () | ||
| 1859 | "Does necessary local dictionary initialization. | ||
| 1860 | When a dictionary is defined in the buffer (see variable | ||
| 1861 | ispell-dictionary-keyword), it will override the local setting | ||
| 1862 | from \\[ispell-change-dictionary]. | ||
| 1863 | Both should not be used to define a buffer-local dictionary." | ||
| 1864 | (save-excursion | ||
| 1865 | (goto-char (point-min)) | ||
| 1866 | (let (end) | ||
| 1867 | ;; Override the local variable definition. | ||
| 1868 | ;; Uses last valid definition. | ||
| 1869 | (while (search-forward ispell-dictionary-keyword nil t) | ||
| 1870 | (setq end (save-excursion (end-of-line) (point))) | ||
| 1871 | (if (re-search-forward " *\\([^ \"]+\\)" end t) | ||
| 1872 | (setq ispell-local-dictionary | ||
| 1873 | (buffer-substring (match-beginning 1) (match-end 1))))) | ||
| 1874 | (goto-char (point-min)) | ||
| 1875 | (while (search-forward ispell-pdict-keyword nil t) | ||
| 1876 | (setq end (save-excursion (end-of-line) (point))) | ||
| 1877 | (if (re-search-forward " *\\([^ \"]+\\)" end t) | ||
| 1878 | (setq ispell-local-pdict | ||
| 1879 | (buffer-substring (match-beginning 1) (match-end 1))))))) | ||
| 1880 | ;; Reload if new personal dictionary defined. | ||
| 1881 | (if (and ispell-local-pdict | ||
| 1882 | (not (equal ispell-local-pdict ispell-personal-dictionary))) | ||
| 1883 | (progn | ||
| 1884 | (ispell-kill-ispell t) | ||
| 1885 | (setq ispell-personal-dictionary ispell-local-pdict))) | ||
| 1886 | ;; Reload if new dictionary defined. | ||
| 1887 | (if (and ispell-local-dictionary | ||
| 1888 | (not (equal ispell-local-dictionary ispell-dictionary))) | ||
| 1889 | (ispell-change-dictionary ispell-local-dictionary))) | ||
| 1890 | |||
| 1891 | |||
| 1892 | (defun ispell-buffer-local-words () | ||
| 1893 | "Loads the buffer-local \"dictionary\" in the current buffer." | ||
| 1894 | (if (and ispell-buffer-local-name | ||
| 1895 | (not (equal ispell-buffer-local-name (buffer-name)))) | ||
| 1896 | (progn | ||
| 1897 | (ispell-kill-ispell t) | ||
| 1898 | (setq ispell-buffer-local-name nil))) | ||
| 1899 | (ispell-init-process) | ||
| 1900 | (save-excursion | ||
| 1901 | (goto-char (point-min)) | ||
| 1902 | (while (search-forward ispell-words-keyword nil t) | ||
| 1903 | (or ispell-buffer-local-name | ||
| 1904 | (setq ispell-buffer-local-name (buffer-name))) | ||
| 1905 | (let ((end (save-excursion (end-of-line) (point))) | ||
| 1906 | string) | ||
| 1907 | (while (re-search-forward " *\\([^ \"]+\\)" end t) | ||
| 1908 | (setq string (buffer-substring (match-beginning 1) (match-end 1))) | ||
| 1909 | (process-send-string | ||
| 1910 | ispell-process (concat "@" (buffer-substring (match-beginning 1) | ||
| 1911 | (match-end 1)) | ||
| 1912 | "\n"))))))) | ||
| 1913 | |||
| 1914 | |||
| 1915 | ;;; returns optionally adjusted region-end-point. | ||
| 1916 | |||
| 1917 | (defun ispell-add-per-file-word-list (word &optional reg-end) | ||
| 1918 | "Adds new word to the per-file word list." | ||
| 1919 | (or ispell-buffer-local-name | ||
| 1920 | (setq ispell-buffer-local-name (buffer-name))) | ||
| 1921 | (if (null reg-end) | ||
| 1922 | (setq reg-end 0)) | ||
| 1923 | (save-excursion | ||
| 1924 | (goto-char (point-min)) | ||
| 1925 | (let ((case-fold-search nil) | ||
| 1926 | line-okay search done string) | ||
| 1927 | (while (not done) | ||
| 1928 | (setq search (search-forward ispell-words-keyword nil 'move) | ||
| 1929 | line-okay (< (+ (length word) 1 ; 1 for space after word.. | ||
| 1930 | (progn (end-of-line) (current-column))) | ||
| 1931 | 80)) | ||
| 1932 | (if (or (and search line-okay) | ||
| 1933 | (null search)) | ||
| 1934 | (progn | ||
| 1935 | (setq done t) | ||
| 1936 | (if (null search) | ||
| 1937 | (progn | ||
| 1938 | (open-line 1) | ||
| 1939 | (setq string (concat comment-start " " | ||
| 1940 | ispell-words-keyword)) | ||
| 1941 | ;; in case the keyword is in the middle of the file.... | ||
| 1942 | (if (> reg-end (point)) | ||
| 1943 | (setq reg-end (+ reg-end (length string)))) | ||
| 1944 | (insert string) | ||
| 1945 | (if (and comment-end (not (equal "" comment-end))) | ||
| 1946 | (save-excursion | ||
| 1947 | (open-line 1) | ||
| 1948 | (forward-line 1) | ||
| 1949 | (insert comment-end))))) | ||
| 1950 | (if (> reg-end (point)) | ||
| 1951 | (setq reg-end (+ 1 reg-end (length word)))) | ||
| 1952 | (insert (concat " " word))))))) | ||
| 1953 | reg-end) | ||
| 1954 | |||
| 1955 | |||
| 1956 | (defconst ispell-version "2.26 Tue Feb 15 16:11:14 MST 1994") | ||
| 1957 | |||
| 1958 | (provide 'ispell) | ||
| 1959 | |||
| 1960 | |||
| 1961 | ;;; LOCAL VARIABLES AND BUFFER-LOCAL VALUE EXAMPLES. | ||
| 1962 | |||
| 1963 | ;;; Local Variable options: | ||
| 1964 | ;;; mode: name(-mode) | ||
| 1965 | ;;; eval: expression | ||
| 1966 | ;;; local-variable: value | ||
| 1967 | |||
| 1968 | ;;; The following sets the buffer local dictionary to english! | ||
| 1969 | |||
| 1970 | ;;; Local Variables: | ||
| 1971 | ;;; mode: emacs-lisp | ||
| 1972 | ;;; comment-column: 40 | ||
| 1973 | ;;; ispell-local-dictionary: "english" | ||
| 1974 | ;;; End: | ||
| 1975 | |||
| 1976 | |||
| 1977 | ;;; MORE EXAMPLES OF ISPELL BUFFER-LOCAL VALUES | ||
| 1978 | |||
| 1979 | ;;; The following places this file in nroff parsing and extended char modes. | ||
| 1980 | ;;; Local IspellParsing: nroff-mode ~nroff | ||
| 1981 | ;;; Change IspellDict to IspellDict: to enable the following line. | ||
| 1982 | ;;; Local IspellDict english | ||
| 1983 | ;;; Change IspellPersDict to IspellPersDict: to enable the following line. | ||
| 1984 | ;;; Local IspellPersDict ~/.ispell_lisp | ||
| 1985 | ;;; The following were automatically generated by ispell using the 'A' command: | ||
| 1986 | ; LocalWords: ispell ispell-highlight-p ispell-check-comments query-replace | ||
| 1987 | ; LocalWords: ispell-query-replace-choices ispell-skip-tib non-nil tib | ||
| 1988 | ; LocalWords: regexps ispell-tib-ref-beginning ispell-tib-ref-end | ||
| 1989 | |||
| 1990 | ;; ispell.el ends here | ||