changeset 28563:7d8ea470609b

(ispell-menu-map): Menu items rearranged and converted to the new menu-item format, names silightly changed, help strings added. Support for spelling without async subprocesses: (ispell-cmd-args, ispell-output-buffer) (ispell-session-buffer): New variables. (ispell-start-process, ispell-process-status, ispell-accept-output, ispell-send-string): New functions, for Ispell invocation when async subprocesses aren't supported. (ispell-word, ispell-pdict-save, ispell-command-loop, ispell-process-line, ispell-buffer-local-parsing): Replace calls to process-send-string with calls to ispell-send-string, and accept-process-output with ispell-accept-output. (ispell-init-process): Call ispell-process-status instead of process-status with. (ispell-init-process): Call ispell-start-process. Call ispell-accept-output and ispell-send-string. Don't call process-kill-without-query and kill-process if they are unbound. (ispell-async-processp): New function.
author Eli Zaretskii <eliz@gnu.org>
date Thu, 13 Apr 2000 14:01:10 +0000
parents 374cbdbde9bd
children e79438733ef2
files lisp/textmodes/ispell.el
diffstat 1 files changed, 315 insertions(+), 138 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/textmodes/ispell.el	Thu Apr 13 10:17:16 2000 +0000
+++ b/lisp/textmodes/ispell.el	Thu Apr 13 14:01:10 2000 +0000
@@ -1,10 +1,10 @@
 ;;; ispell.el --- Interface to International Ispell Versions 3.1 and 3.2
 
-;; Copyright (C) 1994, 1995, 1997, 1998, 1999 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
 
 ;; Authors         : Ken Stevens <k.stevens@ieee.org>
-;; Stevens Mod Date: Mon 29 Nov 11:38:34 PST 1999
-;; Stevens Revision: 3.3
+;; Stevens Mod Date: Fri Jan 28 17:16:58 PST 2000
+;; Stevens Revision: 3.4 beta
 ;; Status          : Release with 3.1.12+ and 3.2.0+ ispell.
 ;; Bug Reports     : ispell-el-bugs@itcorp.com
 ;; Web Site        : http://kdstevens.com/~stevens/ispell-page.html
@@ -127,6 +127,10 @@
 
 ;; Modifications made in latest versions:
 
+;; Revision 3.4 beta 2000/1/28 17:16:58	kss
+;; one arg always for xemacs sleep-for (gunnar Evermann)
+;; support for synchronous processes (Eli Zaretskii)
+
 ;; Revision 3.3  1999/11/29 11:38:34     kss
 ;; Only word replacements entered in from the keyboard are rechecked.
 ;; This fixes a bug in tex parsing and misalignment.
@@ -183,19 +187,27 @@
 	"User variables for emacs ispell interface."
 	:group 'applications)))
 
+(if (not (fboundp 'buffer-substring-no-properties))
+    (defun buffer-substring-no-properties (start end)
+      (buffer-substring start end)))
 
 ;;;###autoload
-(defconst ispell-xemacsp (string-match "Lucid\\|XEmacs" emacs-version)
+(defconst xemacsp (string-match "Lucid\\|XEmacs" emacs-version)
   "Non nil if using XEmacs.")
 
 ;;;###autoload
-(defconst ispell-version18p (string-match "18\\.[0-9]+\\.[0-9]+" emacs-version)
+(defconst version18p (string-match "18\\.[0-9]+\\.[0-9]+" emacs-version)
   "Non nil if using emacs version 18.")
 
 ;;;###autoload
-(defconst ispell-version20p (string-match "20\\.[0-9]+\\.[0-9]+" emacs-version)
+(defconst version20p (string-match "20\\.[0-9]+\\.[0-9]+" emacs-version)
   "Non nil if using emacs version 20.")
 
+(and (not version18p)
+     (not (boundp 'epoch::version))
+     (defalias 'ispell 'ispell-buffer)
+     (defalias 'ispell-check-version 'check-ispell-version))
+
 
 ;;; **********************************************************************
 ;;; The following variables should be set according to personal preference
@@ -258,7 +270,7 @@
   :type 'boolean
   :group 'ispell)
 
-(defcustom ispell-choices-win-default-height (if ispell-xemacsp 3 2)
+(defcustom ispell-choices-win-default-height (if xemacsp 3 2)
   "*The default size of the `*Choices*' window, including mode line.
 Must be greater than 1.
 XEmacs modeline is thicker than a line of text, so it partially covers the
@@ -429,6 +441,17 @@
   :group 'ispell)
 
 
+
+(defcustom ispell-skip-sgml 'use-mode-name
+  "*Indicates whether ispell should skip spell checking of SGML markup.
+If t, always skip SGML markup; if nil, never skip; if non-t and non-nil,
+guess whether SGML markup should be skipped according to the name of the
+buffer's major mode."
+  :type '(choice (const :tag "always" t) (const :tag "never" nil)
+		 (const :tag "use-mode-name" use-mode-name))
+  :group 'ispell)
+
+
 ;;; Define definitions here only for personal dictionaries.
 ;;;###autoload
 (defcustom ispell-local-dictionary-alist nil
@@ -465,7 +488,7 @@
     "[A-Za-z]" "[^A-Za-z]" "[']" nil ("-B") nil iso-8859-1)
    ("american"				; Yankee English
     "[A-Za-z]" "[^A-Za-z]" "[']" nil ("-B") nil iso-8859-1)
-   ("brasiliano"			; Brazilian mode
+   ("brasileiro"			; Brazilian mode
     "[A-Z\301\311\315\323\332\300\310\314\322\331\303\325\307\334\302\312\324a-z\341\351\355\363\372\340\350\354\362\371\343\365\347\374\342\352\364]"
     "[^A-Z\301\311\315\323\332\300\310\314\322\331\303\325\307\334\302\312\324a-z\341\351\355\363\372\340\350\354\362\371\343\365\347\374\342\352\364]"
     "[']" nil ("-d" "brasileiro") nil iso-8859-1)
@@ -652,9 +675,13 @@
 	      ispell-dictionary-alist-3 ispell-dictionary-alist-4
 	      ispell-dictionary-alist-5 ispell-dictionary-alist-6))
 
-;;; The preparation of the menu bar menu must be autoloaded
-;;; because otherwise this file gets autoloaded every time Emacs starts
-;;; so that it can set up the menus and determine keyboard equivalents.
+
+
+
+;;; **********************************************************************
+;;; The following are used by ispell, and should not be changed.
+;;; **********************************************************************
+
 
 
 ;;; The version must be 3.1 or greater for this version of ispell.el
@@ -664,7 +691,7 @@
 (defvar ispell-offset -1
   "Offset that maps protocol differences between ispell 3.1 versions.")
 
-(defconst ispell-version "ispell.el 3.3 -- Mon 29 Nov 11:38:34 PST 1999")
+(defconst ispell-version "ispell.el 3.4 beta -- Fri Jan 28 17:16:58 PST 2000")
 
 
 (defun check-ispell-version (&optional interactivep)
@@ -731,6 +758,12 @@
     result))
 
 
+
+;;; The preparation of the menu bar menu must be autoloaded
+;;; because otherwise this file gets autoloaded every time Emacs starts
+;;; so that it can set up the menus and determine keyboard equivalents.
+
+
 ;;;###autoload
 (defvar ispell-menu-map nil "Key map for ispell menu.")
 ;;; redo menu when loading ispell to get dictionary modifications
@@ -750,8 +783,8 @@
 (defvar ispell-menu-map-needed
   ;; only needed when not version 18 and not XEmacs.
   (and (not ispell-menu-map)
-       (not ispell-version18p)
-       (not ispell-xemacsp)
+       (not version18p)
+       (not xemacsp)
        'reload))
 
 (defvar ispell-library-path (check-ispell-version)
@@ -773,8 +806,10 @@
 	(cond ((not (stringp name))
 	       (define-key ispell-menu-map (vector 'default)
 		 (cons "Select Default Dict"
-		       (list 'lambda () '(interactive)
-			     (list 'ispell-change-dictionary "default")))))
+		       (cons "Dictionary for which Ispell was configured"
+			     (list 'lambda () '(interactive)
+				   (list
+				    'ispell-change-dictionary "default"))))))
 	      ((or (not path)		; load all if library dir not defined
 		   (file-exists-p (concat path "/" name ".hash"))
 		   (file-exists-p (concat path "/" name ".has"))
@@ -782,7 +817,7 @@
 			(or (file-exists-p(concat path "/" load-dict ".hash"))
 			    (file-exists-p(concat path "/" load-dict ".has")))))
 	       (define-key ispell-menu-map (vector (intern name))
-		 (cons (concat "Select " (capitalize name))
+		 (cons (concat "Select " (capitalize name) " Dict")
 		       (list 'lambda () '(interactive)
 			     (list 'ispell-change-dictionary name)))))))))
 
@@ -792,44 +827,63 @@
 (if ispell-menu-map-needed
     (progn
       (define-key ispell-menu-map [ispell-change-dictionary]
-	'("Change Dictionary" . ispell-change-dictionary))
+	'(menu-item "Change Dictionary..." ispell-change-dictionary
+		    :help "Supply explicit path to dictionary"))
       (define-key ispell-menu-map [ispell-kill-ispell]
-	'("Kill Process" . ispell-kill-ispell))
+	'(menu-item "Kill Process" ispell-kill-ispell
+		    :enable (and ispell-process
+				 (eq (ispell-process-status) 'run))
+		    :help "Terminate Ispell subprocess"))
       (define-key ispell-menu-map [ispell-pdict-save]
-	'("Save Dictionary" . (lambda () (interactive) (ispell-pdict-save t t))))
+	'(menu-item "Save Dictionary"
+	  (lambda ()(interactive) (ispell-pdict-save t t))
+	  :help "Save personal dictionary"))
+      (define-key ispell-menu-map [ispell-help]
+	;; use (x-popup-menu last-nonmenu-event(list "" ispell-help-list)) ?
+	'(menu-item
+	  "Help"
+	  (lambda () (interactive) (describe-function 'ispell-help))
+	  :help "Show standard Ispell keybindings and commands"))
       (define-key ispell-menu-map [ispell-complete-word]
-	'("Complete Word" . ispell-complete-word))
+	'(menu-item "Complete Word" ispell-complete-word
+		    :help "Complete word at cursor using dictionary"))
       (define-key ispell-menu-map [ispell-complete-word-interior-frag]
-	'("Complete Word Frag" . ispell-complete-word-interior-frag))))
+	'(menu-item "Complete Word Fragment" ispell-complete-word-interior-frag
+		    :help "Complete word fragment at cursor"))))
 
 ;;;###autoload
 (if ispell-menu-map-needed
     (progn
       (define-key ispell-menu-map [ispell-continue]
-	'("Continue Check" . ispell-continue))
+	'(menu-item "Continue Spell-Checking" ispell-continue
+		    :enable (and (boundp 'ispell-region-end)
+				 (marker-position ispell-region-end)
+				 (equal (marker-buffer ispell-region-end)
+						       (current-buffer)))))
       (define-key ispell-menu-map [ispell-word]
-	'("Check Word" . ispell-word))
+	'(menu-item "Spell-Check Word" ispell-word
+		    :help "Spell-check word at cursor"))
       (define-key ispell-menu-map [ispell-comments-and-strings]
-	'("Check Comments" . ispell-comments-and-strings))
-      (define-key ispell-menu-map [ispell-region]
-	'("Check Region" . ispell-region))
-      (define-key ispell-menu-map [ispell-buffer]
-	'("Check Buffer" . ispell-buffer))))
+	'(menu-item "Spell-Check Comments" ispell-comments-and-strings
+		    :help "Spell-check only comments and strings"))))
 
 ;;;###autoload
 (if ispell-menu-map-needed
     (progn
+      (define-key ispell-menu-map [ispell-region]
+	'(menu-item "Spell-Check Region" ispell-region
+		    :enable mark-active
+		    :help "Spell-check text in marked region"))
       (define-key ispell-menu-map [ispell-message]
-	'("Check Message" . ispell-message))
-      (define-key ispell-menu-map [ispell-help]
-	;; use (x-popup-menu last-nonmenu-event(list "" ispell-help-list)) ?
-	'("Help" . (lambda () (interactive) (describe-function 'ispell-help))))
-      (put 'ispell-region 'menu-enable 'mark-active)
+	'(menu-item "Spell-Check Message" ispell-message
+		    :help "Skip headers and included message text"))
+      (define-key ispell-menu-map [ispell-buffer]
+	'(menu-item "Spell-Check Buffer" ispell-buffer))
       (fset 'ispell-menu-map (symbol-value 'ispell-menu-map))))
 
 ;;; XEmacs versions 19 & 20
-(if (and ispell-xemacsp
-	 (not ispell-version18p)
+(if (and xemacsp
+	 (not version18p)
 	 (featurep 'menubar)
 	 (null ispell-menu-xemacs)
 	 (not (and (boundp 'infodock-version) infodock-version)))
@@ -880,7 +934,7 @@
 	    (add-menu '("Edit") "Spell" ispell-menu-xemacs)))))
 
 ;;; Allow incrementing characters as integers in XEmacs 20
-(if (and ispell-xemacsp
+(if (and xemacsp
 	 (fboundp 'int-char))
     (fset 'ispell-int-char 'int-char)
   ;; Emacs and XEmacs 19 or earlier
@@ -888,8 +942,6 @@
 
 
 ;;; **********************************************************************
-;;; The following are used by ispell, and should not be changed.
-;;; **********************************************************************
 
 
 ;;; This variable contains the current dictionary being used if the ispell
@@ -905,7 +957,7 @@
 (defun ispell-decode-string (str)
   "Decodes multibyte character strings.
 Protects against bogus binding of `enable-multibyte-characters' in XEmacs."
-  (if (and (or ispell-xemacsp
+  (if (and (or xemacsp
 	       (and (boundp 'enable-multibyte-characters)
 		    enable-multibyte-characters))
 	   (fboundp 'decode-coding-string)
@@ -934,6 +986,15 @@
 (defvar ispell-process nil
   "The process object for Ispell.")
 
+(defvar ispell-async-processp (and (fboundp 'kill-process)
+				   (fboundp 'process-send-string)
+				   (fboundp 'accept-process-output)
+				   ;;(fboundp 'start-process)
+				   ;;(fboundp 'set-process-filter)
+				   ;;(fboundp 'process-kill-without-query)
+				   )
+  "Non-nil means that the OS supports asynchronous processes.")
+
 (defvar ispell-pdict-modified-p nil
   "Non-nil means personal dictionary has modifications to be saved.")
 
@@ -942,14 +1003,23 @@
 ;;; When numeric, contains cursor location in buffer, and cursor remains there.
 (defvar ispell-quit nil)
 
+(defvar ispell-process-directory nil
+  "The directory where `ispell-process' was started.")
+
 (defvar ispell-filter nil
   "Output filter from piped calls to Ispell.")
 
 (defvar ispell-filter-continue nil
   "Control variable for Ispell filter function.")
 
-(defvar ispell-process-directory nil
-  "The directory where `ispell-process' was started.")
+(defvar ispell-output-buffer nil
+  "Buffer used for reading output of a synchronous Ispell subprocess.")
+
+(defvar ispell-session-buffer nil
+  "Buffer used for passing input to a synchronous Ispell subprocess.")
+
+(defvar ispell-cmd-args nil
+  "Command-line arguments to pass to a synchronous Ispell subprocess.")
 
 (defvar ispell-query-replace-marker (make-marker)
   "Marker for `query-replace' processing.")
@@ -1048,15 +1118,6 @@
 for skipping in latex mode.")
 
 
-(defcustom ispell-skip-sgml 'use-mode-name
-  "*Indicates whether ispell should skip spell checking of SGML markup.
-If t, always skip SGML markup; if nil, never skip; if non-t and non-nil,
-guess whether SGML markup should be skipped according to the name of the
-buffer's major mode."
-  :type '(choice (const :tag "always" t) (const :tag "never" nil)
-		 (const :tag "use-mode-name" use-mode-name))
-  :group 'ispell)
-
 (defvar ispell-local-pdict ispell-personal-dictionary
   "A buffer local variable containing the current personal dictionary.
 If non-nil, the value must be a string, which is a file name.
@@ -1095,19 +1156,109 @@
 
 
 
-(and (not ispell-version18p)
-     (not (boundp 'epoch::version))
-     (defalias 'ispell 'ispell-buffer)
-     (defalias 'ispell-check-version 'check-ispell-version))
-
-
-(if (not (fboundp 'buffer-substring-no-properties))
-    (defun buffer-substring-no-properties (start end)
-      (buffer-substring start end)))
-
 ;;;###autoload
 (define-key esc-map "$" 'ispell-word)
 
+
+(defun ispell-accept-output (&optional timeout-secs timeout-msecs)
+  "Wait for output from ispell process, or TIMEOUT-SECS and TIMEOUT-MSECS.
+If asynchronous subprocesses are not supported, call `ispell-filter' and
+pass it the output of the last ispell invocation."
+  (if ispell-async-processp
+      (accept-process-output ispell-process timeout-secs timeout-msecs)
+    (if (null ispell-process)
+	(error "No Ispell process to read output from!")
+      (let ((buf ispell-output-buffer)
+	    ispell-output)
+	(if (not (bufferp buf))
+	    (setq ispell-filter nil)
+	  (save-excursion
+	    (set-buffer buf)
+	    (setq ispell-output (buffer-substring-no-properties
+				 (point-min) (point-max))))
+	  (ispell-filter t ispell-output)
+	  (save-excursion
+	    (set-buffer buf)
+	    (erase-buffer)))))))
+
+
+(defun ispell-send-string (string)
+  "Send the string STRING to the Ispell process."
+  (if ispell-async-processp
+      (process-send-string ispell-process string)
+    ;; Asynchronous subprocesses aren't supported on this losing system.
+    ;; We keep all the directives passed to Ispell during the entire
+    ;; session in a buffer, and pass them anew each time we invoke
+    ;; Ispell to process another chunk of text.  (Yes, I know this is a
+    ;; terrible kludge, and it's a bit slow, but it does get the work done.)
+    (let ((cmd (aref string 0))
+	  ;; The following commands are not passed to Ispell until
+	  ;; we have a *reall* reason to invoke it.
+	  (cmds-to-defer '(?* ?@ ?~ ?+ ?- ?! ?%))
+	  (default-major-mode 'fundamental-mode)
+	  (session-buf ispell-session-buffer)
+	  (output-buf ispell-output-buffer)
+	  (ispell-args ispell-cmd-args)
+	  (defdir ispell-process-directory)
+	  prev-pos)
+      (save-excursion
+	(set-buffer session-buf)
+	(setq prev-pos (point))
+	(setq default-directory defdir)
+	(insert string)
+	(if (not (memq cmd cmds-to-defer))
+	    (let (coding-system-for-read coding-system-for-write status)
+	      (if (or xemacsp
+		      (and (boundp 'enable-multibyte-characters)
+			   enable-multibyte-characters))
+		  (setq coding-system-for-read (ispell-get-coding-system)
+			coding-system-for-write (ispell-get-coding-system)))
+	      (set-buffer output-buf)
+	      (erase-buffer)
+	      (set-buffer session-buf)
+	      (setq status
+		    (apply 'call-process-region (point-min) (point-max)
+			   ispell-program-name nil
+			   output-buf nil
+			   "-a" "-m" ispell-args))
+	      (set-buffer output-buf)
+	      (goto-char (point-min))
+	      (save-match-data
+		(if (not (looking-at "@(#) "))
+		    (error "Ispell error: %s"
+			   (buffer-substring-no-properties
+			    (point) (progn (end-of-line) (point)))))
+		;; If STRING is "^Z\n", we just started Ispell and need
+		;; to retain its version ID line in the output buffer.
+		;; Otherwise, remove the ID line, as it will confuse
+		;; `ispell-filter'.
+		(or (string= string "\032\n")
+		    (progn
+		      (forward-line)
+		      (delete-region (point-min) (point))))
+		;; If STRING begins with ^ or any normal character, we need
+		;; to remove the last line from the session buffer, since it
+		;; was just spell-checked, and we don't want to check it again.
+		;; The same goes for the # command, since Ispell already saved
+		;; the personal dictionary.
+		(set-buffer session-buf)
+		(delete-region prev-pos (point))
+		;; Ispell run synchronously saves the personal dictionary
+		;; after each successful command.  So we can remove any
+		;; lines in the session buffer that insert words into the
+		;; dictionary.
+		(if (memq status '(0 nil))
+		    (let ((more-lines t))
+		      (goto-char (point-min))
+		      (while more-lines
+			(if (looking-at "^\\*")
+			    (let ((start (point)))
+			      (forward-line)
+			      (delete-region start (point)))
+			  (setq more-lines (= 0 (forward-line))))))))))))))
+
+
+
 ;;;###autoload
 (defun ispell-word (&optional following quietly continue)
   "Check spelling of word under or before the cursor.
@@ -1156,13 +1307,13 @@
 	(or quietly
 	    (message "Checking spelling of %s..."
 		     (funcall ispell-format-word word)))
-	(process-send-string ispell-process "%\n") ;put in verbose mode
-	(process-send-string ispell-process (concat "^" word "\n"))
+	(ispell-send-string "%\n")	; put in verbose mode
+	(ispell-send-string (concat "^" word "\n"))
 	;; wait until ispell has processed word
 	(while (progn
-		 (accept-process-output ispell-process)
+		 (ispell-accept-output)
 		 (not (string= "" (car ispell-filter)))))
-	;;(process-send-string ispell-process "!\n") ;back to terse mode.
+	;;(ispell-send-string "!\n") ;back to terse mode.
 	(setq ispell-filter (cdr ispell-filter)) ; remove extra \n
 	(if (and ispell-filter (listp ispell-filter))
 	    (if (> (length ispell-filter) 1)
@@ -1296,7 +1447,7 @@
   (if (or ispell-pdict-modified-p force-save)
       (if (or no-query (y-or-n-p "Personal dictionary modified.  Save? "))
 	  (progn
-	    (process-send-string ispell-process "#\n") ; save dictionary
+	    (ispell-send-string "#\n")	; save dictionary
 	    (message "Personal dictionary saved."))))
   ;; unassert variable, even if not saved to avoid questioning.
   (setq ispell-pdict-modified-p nil))
@@ -1369,7 +1520,7 @@
 	      count (ispell-int-char (1+ count))))
       (setq count (ispell-int-char (- count ?0 skipped))))
 
-    ;; Assure word is visible
+    ;; ensure word is visible
     (if (not (pos-visible-in-window-p end))
 	(sit-for 0))
     
@@ -1418,11 +1569,11 @@
 		  (cond
 		   ((= char ? ) nil)	; accept word this time only
 		   ((= char ?i)		; accept and insert word into pers dict
-		    (process-send-string ispell-process (concat "*" word "\n"))
+		    (ispell-send-string (concat "*" word "\n"))
 		    (setq ispell-pdict-modified-p '(t)) ; dictionary modified!
 		    nil)
 		   ((or (= char ?a) (= char ?A)) ; accept word without insert
-		    (process-send-string ispell-process (concat "@" word "\n"))
+		    (ispell-send-string (concat "@" word "\n"))
 		    (if (null ispell-pdict-modified-p)
 			(setq ispell-pdict-modified-p
 			      (list ispell-pdict-modified-p)))
@@ -1518,14 +1669,12 @@
 							  'block))
 		    t)			; reselect from new choices
 		   ((= char ?u)		; insert lowercase into dictionary
-		    (process-send-string ispell-process
-					 (concat "*" (downcase word) "\n"))
+		    (ispell-send-string (concat "*" (downcase word) "\n"))
 		    (setq ispell-pdict-modified-p '(t)) ; dictionary modified!
 		    nil)
 		   ((= char ?m)		; type in what to insert
-		    (process-send-string
-		     ispell-process (concat "*" (read-string "Insert: " word)
-					    "\n"))
+		    (ispell-send-string
+		     (concat "*" (read-string "Insert: " word) "\n"))
 		    (setq ispell-pdict-modified-p '(t))
 		    (cons word nil))
 		   ((and (>= num 0) (< num count))
@@ -1681,14 +1830,14 @@
       (save-window-excursion
 	(if ispell-help-in-bufferp
 	    (progn
-	      (ispell-overlay-window (if ispell-xemacsp 5 4))
+	      (ispell-overlay-window (if xemacsp 5 4))
 	      (switch-to-buffer (get-buffer-create "*Ispell Help*"))
 	      (insert (concat help-1 "\n" help-2 "\n" help-3))
 	      (sit-for 5)
 	      (kill-buffer "*Ispell Help*"))
 	  (select-window (minibuffer-window))
 	  (erase-buffer)
-	  (if (not ispell-version18p) (message nil))
+	  (if (not version18p) (message nil))
 	  ;;(set-minibuffer-window (selected-window))
 	  (enlarge-window 2)
 	  (insert (concat help-1 "\n" help-2 "\n" help-3))
@@ -1856,9 +2005,9 @@
 
 (defun ispell-highlight-spelling-error (start end &optional highlight refresh)
   (cond
-   (ispell-xemacsp
+   (xemacsp
     (ispell-highlight-spelling-error-xemacs start end highlight))
-   ((and (not ispell-version18p)
+   ((and (not version18p)
 	 (featurep 'faces) window-system)
     (ispell-highlight-spelling-error-overlay start end highlight))
    (t (ispell-highlight-spelling-error-generic start end highlight refresh))))
@@ -1942,10 +2091,51 @@
 	      (nreverse miss-list) (nreverse guess-list)))))))
 
 
+(defun ispell-process-status ()
+  "Return the status of the Ispell process.
+When asynchronous processes are not supported, `run' is always returned."
+  (if ispell-async-processp
+      (process-status ispell-process)
+    (and ispell-process 'run)))
+
+
+(defun ispell-start-process ()
+  "Start the ispell process, with support for no asynchronous processes.
+Keeps argument list for future ispell invocations for no async support."
+  (let (args)
+    ;; Local dictionary becomes the global dictionary in use.
+    (if ispell-local-dictionary
+	(setq ispell-dictionary ispell-local-dictionary))
+    (setq args (ispell-get-ispell-args))
+    (if ispell-dictionary		; use specified dictionary
+	(setq args
+	      (append (list "-d" ispell-dictionary) args)))
+    (if ispell-personal-dictionary	; use specified pers dict
+	(setq args
+	      (append args
+		      (list "-p"
+			    (expand-file-name ispell-personal-dictionary)))))
+    (setq args (append args ispell-extra-args))
+
+    (if ispell-async-processp
+	(let ((process-connection-type ispell-use-ptys-p))
+	  (apply 'start-process
+		 "ispell" nil ispell-program-name
+		 "-a"			; accept single input lines
+		 "-m"			; make root/affix combos not in dict
+		 args))
+      (setq ispell-cmd-args args
+	    ispell-output-buffer (generate-new-buffer " *ispell-output*")
+	    ispell-session-buffer (generate-new-buffer " *ispell-session*"))
+      (ispell-send-string "\032\n")	; so Ispell prints version and exits
+      t)))
+
+
+
 (defun ispell-init-process ()
   "Check status of Ispell process and start if necessary."
   (if (and ispell-process
-	   (eq (process-status ispell-process) 'run)
+	   (eq (ispell-process-status) 'run)
 	   ;; If we're using a personal dictionary, assure
 	   ;; we're in the same default directory!
 	   (or (not ispell-personal-dictionary)
@@ -1956,54 +2146,34 @@
     (message "Starting new Ispell process...")
     (sit-for 0)
     (check-ispell-version)
-    (setq ispell-process
-	  (let ((process-connection-type ispell-use-ptys-p))
-	    (apply 'start-process
-		   "ispell" nil ispell-program-name
-		   "-a"			; accept single input lines
-		   "-m"			; make root/affix combos not in dict
-		   (let (args)
-		     ;; Local dictionary becomes the global dictionary in use.
-		     (if ispell-local-dictionary
-			 (setq ispell-dictionary ispell-local-dictionary))
-		     (setq args (ispell-get-ispell-args))
-		     (if ispell-dictionary ; use specified dictionary
-			 (setq args
-			       (append (list "-d" ispell-dictionary) args)))
-		     (if ispell-personal-dictionary ; use specified pers dict
-			 (setq args
-			       (append args
-				       (list "-p"
-					     (expand-file-name
-					      ispell-personal-dictionary)))))
-		     (setq args (append args ispell-extra-args))
-		     args)))
+    (setq ispell-process-directory default-directory
+	  ispell-process (ispell-start-process)
 	  ispell-filter nil
-	  ispell-filter-continue nil
-	  ispell-process-directory default-directory)
-    (set-process-filter ispell-process 'ispell-filter)
+	  ispell-filter-continue nil)
+    (if ispell-async-processp
+	(set-process-filter ispell-process 'ispell-filter))
     ;; protect against bogus binding of `enable-multibyte-characters' in XEmacs
-    (if (and (or ispell-xemacsp
+    (if (and (or xemacsp
 		 (and (boundp 'enable-multibyte-characters)
 		      enable-multibyte-characters))
 	     (fboundp 'set-process-coding-system))
 	(set-process-coding-system ispell-process (ispell-get-coding-system)
 				   (ispell-get-coding-system)))
     ;; Get version ID line
-    (if (not ispell-version18p)
-	(accept-process-output ispell-process 3)
-      (accept-process-output ispell-process))
+    (if (not version18p)
+	(ispell-accept-output 3)
+      (ispell-accept-output))
     ;; get more output if filter empty?
-    (if (null ispell-filter) (accept-process-output ispell-process 3))
+    (if (null ispell-filter) (ispell-accept-output 3))
     (cond ((null ispell-filter)
 	   (error "%s did not output version line" ispell-program-name))
 	  ((and
 	    (stringp (car ispell-filter))
 	    (if (string-match "warning: " (car ispell-filter))
 		(progn
-		  (if (not ispell-version18p)
-		      (accept-process-output ispell-process 3) ; was warn msg.
-		    (accept-process-output ispell-process))
+		  (if (not version18p)
+		      (ispell-accept-output 3) ; was warn msg.
+		    (ispell-accept-output))
 		  (stringp (car ispell-filter)))
 	      (null (cdr ispell-filter)))
 	    (string-match "^@(#) " (car ispell-filter)))
@@ -2015,14 +2185,14 @@
 	   ;; But first wait to see if some more output is going to arrive.
 	   ;; Otherwise we get cool errors like "Can't open ".
 	   (sleep-for 1)
-	   (accept-process-output ispell-process 3)
+	   (ispell-accept-output 3)
 	   (error "%s" (mapconcat 'identity ispell-filter "\n"))))
     (setq ispell-filter nil)		; Discard version ID line
     (let ((extended-char-mode (ispell-get-extended-character-mode)))
       (if extended-char-mode		; ~ extended character mode
-	  (process-send-string ispell-process
-			       (concat extended-char-mode "\n"))))
-    (process-kill-without-query ispell-process)))
+	  (ispell-send-string (concat extended-char-mode "\n"))))
+    (if ispell-async-processp
+	(process-kill-without-query ispell-process))))
 
 ;;;###autoload
 (defun ispell-kill-ispell (&optional no-error)
@@ -2030,18 +2200,26 @@
 With NO-ERROR, just return non-nil if there was no Ispell running."
   (interactive)
   (if (not (and ispell-process
-		(eq (process-status ispell-process) 'run)))
+		(eq (ispell-process-status) 'run)))
       (or no-error
 	  (error "There is no ispell process running!"))
-    (process-send-eof ispell-process)
-    (if (eq (process-status ispell-process) 'run)
-	(accept-process-output ispell-process 1))
-    (if (eq (process-status ispell-process) 'run)
-	(kill-process ispell-process))
-    (while (not (or (eq (process-status ispell-process) 'exit)
-		    (eq (process-status ispell-process) 'signal)))
-      (if ispell-version20p (sleep-for 0.25)
-	(sleep-for 0 250)))
+    (if ispell-async-processp
+	(progn
+	  (process-send-eof ispell-process)
+	  (if (eq (ispell-process-status) 'run)
+	      (ispell-accept-output 1))
+	  (if (eq (ispell-process-status) 'run)
+	      (kill-process ispell-process))
+	  (while (not (or (eq (ispell-process-status) 'exit)
+			  (eq (ispell-process-status) 'signal)))
+	    (if (or xemacsp version20p) (sleep-for 0.25)
+	      (sleep-for 0 250))))
+      ;; synchronous processes
+      (ispell-send-string "\n")		; make sure side effects occurred.
+      (kill-buffer ispell-output-buffer)
+      (kill-buffer ispell-session-buffer)
+      (setq ispell-output-buffer nil
+	    ispell-session-buffer nil))
     (setq ispell-process nil)
     (message "Ispell process killed")
     nil))
@@ -2356,9 +2534,9 @@
     (if (not (numberp shift))
 	(setq shift 0))
     ;; send string to spell process and get input.
-    (process-send-string ispell-process string)
+    (ispell-send-string string)
     (while (progn
-	     (accept-process-output ispell-process)
+	     (ispell-accept-output)
 	     ;; Last item of output contains a blank line.
 	     (not (string= "" (car ispell-filter)))))
     ;; parse all inputs from the stream one word at a time.
@@ -2426,7 +2604,7 @@
 		  (set-marker line-end (point))
 		  (setq ispell-filter nil
 			recheck-region t)))
-				       
+
 	    ;; insert correction if needed
 	    (cond
 	     ((or (null replace)
@@ -2852,7 +3030,7 @@
 Overrides the default parsing mode.
 Includes Latex/Nroff modes and extended character mode."
   ;; (ispell-init-process) must already be called.
-  (process-send-string ispell-process "!\n") ; Put process in terse mode.
+  (ispell-send-string "!\n")		; Put process in terse mode.
   ;; We assume all major modes with "tex-mode" in them should use latex parsing
   ;; When exclusively checking comments, set to raw text mode (nroff).
   (if (and (not (eq 'exclusive ispell-check-comments))
@@ -2861,10 +3039,10 @@
 				  (symbol-name major-mode)))
 	       (eq ispell-parser 'tex)))
       (progn
-	(process-send-string ispell-process "+\n") ; set ispell mode to tex
+	(ispell-send-string "+\n")	; set ispell mode to tex
 	(if (not (eq ispell-parser 'tex))
 	    (set (make-local-variable 'ispell-parser) 'tex)))
-    (process-send-string ispell-process "-\n"))	; set mode to normal (nroff)
+    (ispell-send-string "-\n"))		; set mode to normal (nroff)
   ;; If needed, test for SGML & HTML modes and set a buffer local nil/t value.
   (if (and ispell-skip-sgml (not (eq ispell-skip-sgml t)))
       (set (make-local-variable 'ispell-skip-sgml)
@@ -2873,7 +3051,7 @@
   ;; Set default extended character mode for given buffer, if any.
   (let ((extended-char-mode (ispell-get-extended-character-mode)))
     (if extended-char-mode
-	(process-send-string ispell-process (concat extended-char-mode "\n"))))
+	(ispell-send-string (concat extended-char-mode "\n"))))
   ;; Set buffer-local parsing mode and extended character mode, if specified.
   (save-excursion
     (goto-char (point-max))
@@ -2888,11 +3066,11 @@
 				    (match-beginning 1) (match-end 1))))
 	    (cond ((and (string-match "latex-mode" string)
 			(not (eq 'exclusive ispell-check-comments)))
-		   (process-send-string ispell-process "+\n~tex\n"))
+		   (ispell-send-string "+\n~tex\n"))
 		  ((string-match "nroff-mode" string)
-		   (process-send-string ispell-process "-\n~nroff\n"))
+		   (ispell-send-string "-\n~nroff\n"))
 		  ((string-match "~" string) ; Set extended character mode.
-		   (process-send-string ispell-process (concat string "\n")))
+		   (ispell-send-string (concat string "\n")))
 		  (t (message "Invalid Ispell Parsing argument!")
 		     (sit-for 2))))))))
 
@@ -2965,8 +3143,7 @@
 	  ;; Error handling needs to be added between ispell and emacs.
 	  (if (and (< 1 (length string))
 		   (equal 0 (string-match ispell-casechars string)))
-	      (process-send-string ispell-process
-				   (concat "@" string "\n"))))))))
+	      (ispell-send-string (concat "@" string "\n"))))))))
 
 
 ;;; returns optionally adjusted region-end-point.