I write a lot of text in German and English and I'm getting tired of switching the dictionary of my spell-checker all the time. In true Emacs spirit, I decided to do something about this and dusted off my grandpa's parentheses. The code I wrote guesses the language of the current paragraph and then changes the language in ispell and typo-mode. It also reruns flyspell on the current paragraph, but only on that paragraph because sometimes I also write documents in multiple languages.

All this is working really nicely and I will publish this code after some more testing, so other people can use it, too. However, I want the process of switching languages to be fully automatic so I don't have to think about it at all. This means that my function should run every once in a while during text editing. Perhaps it's overkill to run it on every key stroke but I thought it might be good to run it every time I start a new word, i.e., when I enter a space or newline. Alternatively, it might also be enough to run it only when I enter punctuation marks.

My question: How can I fire off the function when certain characters are inserted in the buffer? Is there a hook for that? Thanks for your help.

FYI: Here is my code: https://github.com/tmalsburg/guess-language.el

  • 1
    post-self-insert-hook fires after every insert, but could be made to work by doing the check for the character in the hook. – wasamasa Jan 31 '17 at 21:03
  • @wasamasa But how do I know which character was inserted? – tmalsburg Jan 31 '17 at 21:05
  • Oh, it's simply the character at point I guess. That was too easy for me ;-) – tmalsburg Jan 31 '17 at 21:06
  • 1
    Not a direct answer but another approach might be to run on a timer, or whenever Emacs is idle for a few seconds. See run-with-idle-timer and run-with-timer. – glucas Jan 31 '17 at 21:19

Here's a simple function that you can use to check if the character you just entered should set off your do-my-awesome-thing function:

(defun do-awesome-thing-maybe ()
  (when (memq (char-before) '(?\  ?\t))
    (message "You should do-my-awesome-thing now")))

Here, it checks if the character you just entered was either a space or a tab (which seems like a reasonable compromise between doing it after every character, which is probably overkill, and doing it on a timer, which would require you to stop typing for a while). If so, you would do-my-awesome-thing. You can then add it to the hook:

(add-hook 'post-self-insert-hook #'do-awesome-thing-maybe)
  • It works, very nice. Unfortunately, it turns out that running flyspell-region on the paragraph every time a space is entered is a little too slow. I can also see the cursor running through the paragraph which is distracting. Probably also drains the battery of my notebook. Hm ... – tmalsburg Jan 31 '17 at 21:28
  • 2
    I see that flyspell has a flyspell-incorrect-hook. If you're already using flyspell to find errors on the fly, maybe you could use that hook to check (and possibly change) the language when flyspell finds an incorrect word? – glucas Jan 31 '17 at 21:30
  • 2
    @tmalsburg: it might make sense to post a new question along the lines of "I need to run an expensive function every once in a while, how do I do it?" It'll get more views (and hopefully help!) than these comments will get. Plus, that question will probably be useful to others as well. – Dan Jan 31 '17 at 21:55
  • 1
    @tmalsburg You may be able to prevent the recursive loop by keeping some additional state. Basically, you want a flyspell error to trigger your custom function unless it is already running. So you might check some buffer-local variable; if it is false, set it to true and schedule your custom function to do its thing and reset the flag when it is done. (Something along those lines...) :-) – glucas Feb 1 '17 at 19:18
  • 1
    @glucas Thank you. I solved it by removing the hook for temporarily and then reinserting it after flyspell is finished. – tmalsburg Feb 2 '17 at 16:08

Your Answer

