2

I need to check whether a string is spelled correctly from my ELisp code. This is what I am trying:

(ispell-start-process)
(ispell-send-string "Check this")
(ispell-accept-output)

The last call freezes, although an ispell process seems to be running, since (ispell-process-status) returns 'run and Fly-Spell is working properly (though in a different buffer). All I need is a boolean result showing whether a given string is spelled correctly or not. How do I achieve this?

1

The following is an adaption of ispell-word. It also allows to specify the dictionary for the spell checking of the string.

(require 'ispell)

(defun ispell-string (string &optional dictionary quietly)
  "Ispell STRING with DICTIONARY.
DICTIONARY defaults to `ispell-local-dictionary' if that is set in the current buffer
and to `ispell-dictionary' otherwise.
Non-nil QUIETLY supresses messages about correct and incorrect spelling."
  (interactive (list (read-string "String to be checked:")
             (completing-read
              "Use new dictionary (RET for current, SPC to complete): "
              (and (fboundp 'ispell-valid-dictionary-list)
               (mapcar 'list (ispell-valid-dictionary-list))))))
  (let ((ispell-local-dictionary (or (and (stringp dictionary)
                      (> (length dictionary) 0)
                      dictionary)
                     ispell-local-dictionary)))
    (ispell-set-spellchecker-params)  ; Initialize variables and dicts alists
    (ispell-accept-buffer-local-defs) ; Accepts ispell-local-dictionary.
    ;; ... Word extraction from `ispell-word' deleted.
    ;; At this point it used to ignore 2-letter words.
    ;; But that is silly; if the user asks for it, we should do it. - rms.
    (cl-every 'identity
     (mapcar
      (lambda (word)
    (ispell-init-process) ;< Additional to the stuff from `ispell-word'.
    (or quietly
        (message "Checking spelling of %s..."
             (funcall ispell-format-word-function word)))
    (ispell-send-string "%\n")  ; put in verbose mode
    (ispell-send-string (concat "^" word "\n"))
    ;; wait until ispell has processed word
    (while (progn
         (ispell-accept-output)
         (not (string= "" (car ispell-filter)))))
    ;;(ispell-send-string "!\n") ;back to terse mode.
    (setq ispell-filter (cdr ispell-filter)) ; remove extra \n
        (let (poss)
          (if (and ispell-filter (listp ispell-filter))
              (if (> (length ispell-filter) 1)
                  (error "Ispell and its process have different character maps")
                (setq poss (ispell-parse-output (car ispell-filter)))))
          (let ((ret (eq poss t)))
            (unless quietly
              (message "%s is %scorrect"
                       (funcall ispell-format-word-function word)
                       (or (and ret "") "in")))
            ret)))
        (split-string string "[^[:alpha:]]" t "[^[:alpha:]]")))))
  • Does it check the whole string or only the last word in the string (in which case the name of the function is misleading)? My answer would only check the last word and I don't see much difference in how the two answers operate. – AlwaysLearning Dec 16 '17 at 20:40
  • @AlwaysLearning You have a point. I've corrected the lisp code such that the whole string is checked. Thanks for the comment. – Tobias Dec 16 '17 at 21:02
0

Adapted from https://codegists.com/code/helm%20flyspell%20correct/, it prints OK when word is correct and wrong when word is incorrect:

(ispell-start-process)
(ispell-send-string "hello\n")

(while (progn
     (accept-process-output ispell-process)
     (not (string= "" (car ispell-filter)))))
;; Remove leading empty element
(setq ispell-filter (cdr ispell-filter))
;; ispell process should return something after word is sent.
;; Tag word as valid (i.e., skip) otherwise
(or ispell-filter
    (setq ispell-filter '(*)))
(if (consp ispell-filter)
    (setq poss (ispell-parse-output (car ispell-filter))))
(cond
 ((or (eq poss t) (stringp poss))
  ;; don't correct word
  (message "OK"))
 ((null poss)
  ;; ispell error
  (error "Ispell: error in Ispell process"))
 (t
  (error "wrong")))

EDIT:

Note that this not a function, this is just a piece of code. Replace hello\n with whatever you want.

  • I made this code into a function and called the function. First it correctly says "OK". Then I change the word to something wrong and re-evaluate. When I invoke the function it correctly errors "wrong". However, when I change it back to "hello\n" (and re-evaluate), it continues to say "wrong". That is, once this code errors "wrong" once, I cannot cause it to say "OK" anymore. – AlwaysLearning Dec 16 '17 at 19:03
  • Can you post the function's code? – Arkadiusz Drabczyk Dec 16 '17 at 19:05
  • I put this code into a new buffer, saved it, ran eval-buffer and it said OK, I replaced hello with helloo, saved it, ran eval-buffer again and it said wrong, I replaced helloo back to hello, saved it, ran eval-buffer and it said OK. Can you confirm it also works for you? – Arkadiusz Drabczyk Dec 16 '17 at 19:10
  • I did what you did, but it said wrong when I changed it back to hello... – AlwaysLearning Dec 16 '17 at 19:41
  • I have no clue. What emacs version do you have? What OS? – Arkadiusz Drabczyk Dec 16 '17 at 19:47
0

The code in the answer of @Arkadiusz Drabczyk is adapted from flyspell-correct-word-before-point. That function works, so I re-worked it into what I need:

(defun check-word(word)
  (let (poss ispell-filter)
    (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)
         (not (string= "" (car ispell-filter)))))
    ;; Remove leading empty element
    (setq ispell-filter (cdr ispell-filter))
    ;; ispell process should return something after word is sent.
    ;; Tag word as valid (i.e., skip) otherwise
    (or ispell-filter
    (setq ispell-filter '(*)))
    (if (consp ispell-filter)
    (setq poss (ispell-parse-output (car ispell-filter))))
    (cond
     ((or (eq poss t) (stringp poss))
      ;; The word is correct.
      t)
     ((null poss)
      ;; ispell error
      (error "Ispell: error in Ispell process"))
     (t
      ;; The word is incorrect.
      nil))))
  • I am glad it works for you. Please mark this answer as accepted for other users know your problem is solved. – Arkadiusz Drabczyk Dec 16 '17 at 20:21
  • The policy of having to wait for some 14 hours before accepting makes it difficult not to forget... – AlwaysLearning Dec 16 '17 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.