Helm provides so many great commands I am still discovering new gems in it, like
helm-regexp, which lets you build your regular expression pattern,
see the results of your search live in the Helm buffer, and optionally pass the
query-replace-regexp. So neat.
This is why I haven’t written a Helm command of my own until recently. To be fair, as I am going to show there is not even the need for this command to exist, but coding it has been a fun exercise anyway.
When it comes to spell-checking my buffers, I have been relying on mu-cycle-ispell-languages to change dictionaries and flyspell-correct-helm to pick the correct word I happened to misspell. Since I am already using Helm with Flyspell, then, why not using it to select the dictionary too?
First, the actual dictionaries.
(defvar mu-dictionaries '(("en_GB" . "English") ("it_IT" . "Italian")))
Note that I use
hunspell for spell-checking as I explained in Spell-checking
with Hunspell and flyspell-correct.
Next, my new command.
(defun mu-select-dictionary () "Select the dictionary for the spell-checker." (interactive) (helm :sources (helm-build-sync-source "Dictionaries" :candidates (map-values mu-dictionaries) :action (lambda (candidate) (let ((dict (car (rassoc candidate mu-dictionaries)))) (ispell-set-spellchecker-params) (setq ispell-dictionary dict ispell-local-dictionary dict ispell-local-dictionary-overridden t) (ispell-internal-change-dictionary) (setq ispell-buffer-session-localwords nil) (run-hooks 'ispell-change-dictionary-hook)))) :preselect (map-elt mu-dictionaries ispell-dictionary) :buffer "*helm select dictionary*") (flyspell-buffer))
I merely followed the guidelines on the Helm wiki, but let’s break it down.
(helm :source (helm-build-sync-source "Dictionaries"
The source of my Helm command comes from the simple
alist defined before
helm-build-sync-source is enough.
:candidates (map-values mu-dictionaries)
Here I am using the excellent map.el to get the clearer “English” and “Italian”
:candidates for the Helm buffer.
:action (lambda (candidate) (let ((dict (car (rassoc candidate mu-dictionaries)))) (ispell-set-spellchecker-params) (setq ispell-dictionary dict ispell-local-dictionary dict ispell-local-dictionary-overridden t) (ispell-internal-change-dictionary) (setq ispell-buffer-session-localwords nil) (run-hooks 'ispell-change-dictionary-hook)))
The anonymous function for
:action is a small version of
ispell-change-dictionary, containing only what I need for this operation to
complete successfully. Note the use of
rassoc: this is how I get the key
corresponding to the value of
mu-dictionaries. I didn’t find a
similar facility in
car get the job done.
:preselect (map-elt mu-dictionaries ispell-dictionary)
Here I am using the current dictionary as the preselected element in the Helm
buffer. I could use
:input to have it offered on the prompt, but I prefer to
have the prompt empty in this case.
If you look closely at
ispell-change-dictionary source code, you can understand
the triviality of
completing-read, so in my case it already pops up a Helm buffer. But I am still
happy with this solution, and not just because I prefer “Dictionaries” instead
of “ispell-change-dictionary” as the source name displayed in my Helm buffer.
(Yes, of course it’s mostly because of it.)
As a bonus, thanks to
flyspell-buffer the current buffer is spell-checked right
after the new dictionary is selected.