11

I was about to post the question but then I saw it on Stack Overflow while searching for auto-correct possibilities. The linked question has no answers, so I thought it'd have more luck on this site. Here's the text:

I wish there were a way so that when I mistype a word, flyspell could autocorrect it to the "most likely" correction. When I mistype a word and then hit OPTION-TAB to correct it, flyspell ALMOST ALWAYS picks the correct correction by default as the main suggestion.

However, I want flyspell to do this with every word I mistype, WITHOUT my having to hit OPTION-TAB. Just from hitting the SPACE bar and moving on to the next word.

Is this possible?

So basically something like auto-correct on mobile phones. Such a feature would be useful to have for modes like jabber and capture in org-mode


Edit:

I'd rather have this feature as a separate minor mode than overwriting the default fly-spell functionality. It could be activated in addition or instead of fly-spell when needed

6
  • 1
    I am certain it is possible (and probably not difficult to hack), but I feel obliged to say that IMHO that would be a very bad idea.
    – mbork
    Commented Oct 29, 2014 at 12:31
  • 1
    @mbork It would be a bad idea to change how fly-spell works, but what's wrong with having an additional minor mode that can be activated/deactivated on demand?
    – Tymric
    Commented Oct 29, 2014 at 12:43
  • I'm constantly annoyed by a similar feature on my phone. I don't like machines pretending that they are smarter than me, especially that they aren't;-): they vocabulary is very limited, especially that I sometimes want to type non-words (like some proper nouns).
    – mbork
    Commented Oct 29, 2014 at 14:42
  • @mbork True, but it also has advantages, like not having to worry about typing every '. I use a German keyboard, and my pinkies have to do the splits every time I reach for that key
    – Tymric
    Commented Oct 29, 2014 at 14:49
  • 1
    @mbork To solve the "non_words" issue, could we perhaps bind S-SPC to "leave-that-word-alone"?
    – Tymric
    Commented Oct 29, 2014 at 14:56

4 Answers 4

6

Let me refer you to my post on this.


I've found that abbrevs are the best way to do correction on SPC, you only need to define the corrections that you want. For that, I take the following approach:

  1. Add the code below to your init file.
  2. Whever you type something wrong, hit C-x C-i and choose one of the corrections offered.
  3. That's it! The correction will be automatically replaced there, and will automatically be performed every time you make this mistake from now on.

Here's the code

(define-key ctl-x-map "\C-i" 'endless/ispell-word-then-abbrev)

(defun endless/ispell-word-then-abbrev (p)
  "Call `ispell-word'. Then create an abbrev for the correction made.
With prefix P, create local abbrev. Otherwise it will be global."
  (interactive "P")
  (let ((bef (downcase (or (thing-at-point 'word) ""))) aft)
    (call-interactively 'ispell-word)
    (setq aft (downcase (or (thing-at-point 'word) "")))
    (unless (string= aft bef)
      (message "\"%s\" now expands to \"%s\" %sally"
               bef aft (if p "loc" "glob"))
      (define-abbrev
        (if p local-abbrev-table global-abbrev-table)
        bef aft))))

(setq save-abbrevs t)
(setq-default abbrev-mode t)

Manually, adding the corrections might sound cumbersome, but it's really not. You're just hitting a couple of keys, and you'll notice a few corrections will get you a long way.

Besides, the alternative (letting ispell choose the correction for you every time the word doesn't exist) will get you wrong corrections more often than not. So it's best to define your own anyway. It even solves the problem of when you actually want to type non-words.

3
  • I tried adding a substitution for dont to don't using C-x C-i 1 but it added the letter t instead ("dont" now expands to "t" globally). I don't think it handles apostrophes well. Is there a fix for that?
    – Tymric
    Commented Oct 29, 2014 at 16:12
  • @Timmy Is that in a programming mode? In text-mode that doesn't happen for me.
    – Malabarba
    Commented Oct 30, 2014 at 11:08
  • I tried it in a jabber conversation, but after your comment I tested it in text-mode and it worked globally. Thank you
    – Tymric
    Commented Oct 30, 2014 at 12:27
2

Here's a simple attempt:

(defun my-flyspell-correct-on-space ()
  (interactive)
  (when flyspell-mode
    (flyspell-auto-correct-word))
  (self-insert-command 1))
(local-set-key " " 'my-flyspell-correct-on-space)

It behaves strangely when you insert more than one space in a row, and sometimes it splits off part of the word being corrected. Thus this post is community wiki; feel free to improve it.

1
  • 6
    I'd rather leave the space key alone, and instead use post-self-insert-hook to track the insertion of spaces and act accordingly. That's safer and more efficient.
    – user227
    Commented Oct 29, 2014 at 12:35
1

Late answer inspired by another question about autocorrect and @legoscia's answer. Here's a quick minor mode that will autocorrect on the fly, using flyspell. It is, in effect, "global" in that it advises self-insert-command, but only fires in buffers that have flyspell-mode turned on.

(defun flyspell-ac-word (&optional arg)
  "Autocorrect a word when entering a non-word character."
  (when flyspell-mode
    (unless (eq ?w (char-syntax (string-to-char (this-command-keys))))
      (when (or (bobp)
                (eq ?w (char-syntax (char-before))))
        (flyspell-auto-correct-word)))))

(define-minor-mode flyspell-autocorrect-mode
  "Toggle `flyspell-autocorrect-mode'.  Fires flyspell on a
just-completed word.  Only operates when `flyspell-mode' is on."
  :init-value nil
  :lighter (" AC")
  (if flyspell-autocorrect-mode
      (progn 
        (require 'flyspell)
        (advice-add #'self-insert-command :before #'flyspell-ac-word))
    (advice-remove #'self-insert-command #'flyspell-ac-word)))
0

The previous answer are very interesting but IMHO fail to satisfyingly answer the initial question:

  • @Malabarba's answer requires a manual action to insert word, which I did not want;
  • @legocia's answer is a good start but weirdly behaves with pointer jumping from place to place;
  • @Dan's answer fails with a wrong number of arguments on my setup and I failed to debug it (I'm new to emacs-lisp programming) but I liked the minor-mode mechanism.

The main problem with @legocia's answer is that calling flyspell-auto-correct-word sometimes moves the Emacs point within the word, hence the weird split. The trick is thus to carefully save the position before making the correction and also before inserting the space character that triggered the auto-correction. Finally, auto-correction should also be triggered on comma and point.

So here is a new proposal:

(defun  flyspell-ac-word ()
  "Autocorrect a word when entering a non-word character."
  (interactive)
  (setq p (point-marker)) ;; save the current position
  (self-insert-command 1) ;; insert a space/comma/point/...
  (setq q (point-marker)) ;; save the current position
  (goto-char (marker-position p)) ;; get back to our initial position
  (flyspell-auto-correct-word)    ;; Auto-correct the word at point
  (goto-char (marker-position q)) ;; jump to the space/comma/point
  )

(define-minor-mode flyspell-autocorrect-mode
  "Toggle `flyspell-autocorrect-mode'.  Fires flyspell on a just-completed word.  Only operates when `flyspell-mode' is on."
  :init-value nil
  :lighter (" AC")
  (if flyspell-autocorrect-mode
      (progn 
        (require 'flyspell)
        (keymap-local-set "SPC" 'flyspell-ac-word())
        (keymap-local-set "," 'flyspell-ac-word())
        (keymap-local-set "." 'flyspell-ac-word())
      )
      (progn
        (keymap-local-unset "SPC")
        (keymap-local-unset ",")
        (keymap-local-unset ".")
      )))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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