Emacs Config Gems - Part 5

Being a text editor (among other things), Emacs has quite a few tricks up its sleeve for making writing not just easier but also fun and seemingly magical. I call this section in my config “Wordcraft.”

Emacs Dictionary

When we need a dictionary, Emacs got us covered and then some. After version 28, Emacs connects to a dictionary as a two-step process by default:

  1. It tries to connect to a local host.
  2. If it fails, it next connects to an online dictionary at www.dict.org,

This workflow remains in place as long as dictionary-server is nil, which is the default. It’s a bit confusing (to me anyway), since “nil” might indicate that no dictionary is set up, but here it means we simply didn’t introduce any configuration to it.

The online version at dict.org contains the Webster dictionary from 1913, which (if you follow the footnote) will start sounding like an excellent resource. What I didn’t know up until now however is that dict.org contains more than just this wonderful dictionary.

When you search for something like “US” with Emacs’ built-in dictionary, it checks this database and gives you results from:

  1. The Collaborative International Dictionary of English
  2. WordNet
  3. V.E.R.A. – Virtual Entity of Relevant Acronyms
  4. The Free Online Dictionary of Computing (it has an entry as an ASCII character)

There are others, like the CIA Factbook and the Bible, among others. All of those are at your fingertips, inside Emacs, from a simple quick search.

The problem is that it’s an online dictionary. No internet, no dictionary. On my MacBook this can happen as I take it with me when I travel. Meanwhile, on Linux, I’m always online (desktop, wired connection).

Follow the footnote, and you will learn how to get that Webster dictionary (but just that, not the database at dict.org) working offline. As for me, I don’t want to set up an offline dictionary because macOS’s dictionary app (which works fine offline) is good enough — a quick copy-paste and I’m done. So I configured my dictionary-server to point directly to dict.org, so Emacs doesn’t even search for a local one first.

Here is the setting itself, including the localhost option as a reference and a reminder:

;; (set dictionary-server nil) default, search localhost and then dict.org
;; (setq dictionary-server "localhost") local only, no online search
  (setq dictionary-server "dict.org")

Hippie Expand

I learned about hippie-expand through Mastering Emacs. It’s one of those things that make Emacs magic. It uses different expansion functions (not to be confused with completion functions, which we will learn more about in a minute) to guess which word should come next in our text as we write, depending on which buffer we are in.

Following Mickey’s advice (linked above), I rebound this to M-/, which is bound to dabbrev-expand by default. It’s similar, but not as powerful (essentially it’s more basic; hippie-expand takes the functions that dabbrev-expand uses and builds on top of those with additional ones). Keep pressing M-/ to flip through suggestions.

The catch is that you need to open the buffers you want it to look through. For example, if I want it to pull words from my personal journal while writing this post, I need to have my journal buffer open somewhere. If you’re one of the people who don’t turn off Emacs often, this is not a problem — just keep that in mind when you use it.

Turning it on (by replacing the command, using the same binding):

(global-set-key [remap dabbrev-expand] 'hippie-expand)

We also want to change the order in which it searches for things so it works better for us. For me, as a person who does less coding and more writing, I prefer it to look at Lisp-related functions toward the end. The same logic applies to global (all-buffers) lists vs those that operate on the visible buffer only. So our first M-/ will give us suggestions from our current buffer, and as we keep pressing M-/ and exhaust those, it will search all the other buffers we have open. for other suggestions.

(setq hippie-expand-try-functions-list
      '(try-expand-dabbrev
        try-expand-dabbrev-all-buffers
        try-expand-dabbrev-from-kill
        try-expand-line
        try-expand-line-all-buffers
        try-expand-list
        try-expand-list-all-buffers
        try-complete-file-name-partially
        try-complete-file-name
        try-expand-all-abbrevs
        try-complete-lisp-symbol-partially
        try-complete-lisp-symbol))

ispell

ispell is one of those things I set around the time I started using Emacs and never looked at again. I’ve made a mistake: I bound ispell-region to M-$. Those of you who use ispell often are probably perking an eyebrow: “huh? Why would you do that for? ispell does it by default!”

But somehow I didn’t know this. For years I highlighted whatever I needed to spell check, even single words. The default keybinding attributes M-$ to ispell-word, which checks the word at the marker, but if you have a region selected, it spellchecks the region. I should have given Emacs more credit; today I know better.

Another really handy thing I did not know about ispell is its ability to complete words I’m unsure of. But before we go on, please note that word completion (and completion functions) in Emacs is a big topic that I just spent a whole week on, and what I’m going to discuss here is just the tip of the iceberg.

First, the useful built-in completion built into ispell itself: l for lookup. Say you forgot how to write “psychiatry”. You type what you know — “psy” — and then call ispell, and as the suggestions show up, press l. ispell will ask you what to complete, along with a wildcard, so add * and then y so you have “psy*y”. ispell will show you what words start with psy and have whatever letters after but end with y. Useful!

Another thing I didn’t know: use R for query replace. This is good when you make the same mistake across several words. For example, when I wrote this post, I originally capitalized every ispell as Ispell. No problem. Stand on one of those, call ispell, press R to replace, and change it to ispell. Now you are prompted if you want to change all of them one by one, or, just hit ! and get it over with in one swoop.

With those quick tips, now back to completion functions.

Years ago, when I started using Emacs, I installed company with its minimal default settings and called it a day. It’s been working OK, and up until I started writing this post, I didn’t realize how much about Emacs completion-at-point functions (capf). Prot has a good video about this, which I’m still chewing through, but basically for ispell the magic happens when you stand on a word you don’t know how to finish and ask Emacs to suggest completions.

To understand how this works, Let’s say we don’t know if water is written as watter or watar, as a simple example.

  1. We write “wate” and we ask Emacs to complete the word by calling completion with ispell with M-C i. Because the only word that exists (in English anyway) that starts with “wate” is water, Emacs will complete it for us to “water” automatically.
  2. Now, while standing on the word “water,” we call completion again. Emacs informs us: complete, but not unique. In other words: the word water is real and complete (we have it spelled right) but there are other words that start with water.
  3. While still standing on “water”, we call complete yet again. Emacs goes “OK. So you know it’s a word that exists, and you also know there are other words that start with water, so if you’re calling complete again, you probably want to see the other words that start with water.”

Bam, we have a buffer full of words that start with water, like waterboard or watermelon. We can select a word from this menu, even though it’s a bit weird — by going down or up with M-⇡ and M-⇣, then insert the word we want with M-Ret.

This is nice, but usually you want to complete words that you already know, or kind of know. If I type “psych,” I don’t need a whole buffer of words if I’m looking for “psychology”; I just slowly add letters until I find what I need — and this is exactly what packages like company or corfu do.

Harper, languagetool and abbrevs

Let me just remind you of those for now and finish up this post. We will dig into those more next time.

  1. This post from irreal is a good place to get a bit more understanding of how to use a local dictionary, a copy of the online one, and why. If you read it, you may find your way into Irreal’s older post and then this wonderful gem he found: You’re probably using the wrong dictionary. The way these posts are written, I feel it makes more sense to read them in the reverse order I presented here, inviting more exploration as you go — however, if you’re short on time or patience, I recommend you read at least that last one, especially if you enjoy writing.
  2. As I was learning this, this next question popped into my mind: can we then look for a definition in Wikipedia and the Urban Dictionary as well? The straight answer: yes (it’s Emacs, duh). The full answer: it’s complicated. We can’t integrate it into the results buffer from dictionary-search directly, but what I can do is have it inside a “wrapper” buffer that will contain the dict.org definition with the Wikipedia and Urban Dictionary below it. For now, I’m fine with just using eww-search-words which initiates a search with Duck Duck Go, which already pulls Wikipedia search results near the top (Wikipedia itself forces JavaScript usage, which blocks Eww)
  3. By the way, something fun I discovered while researching: we can call the macOS dictionary using dict:// (as a URL link), and we can build a function in Emacs for it if we want. Further — we could create something like this for offline situations only, but this is not needed at least in my case. Worth mentioning: there’s also the osx-dictionary package, which bridges Emacs and the built-in dictionary app on macOS. But why, when you have a different (and arguably better) version built in?
  4. hippie-expand doesn’t really have a help file that lists all the functions, though I think I’ve listed most of those if not all above. Check out the package directly if you want to read more about the functions; they are described in comments at the top of the code. Online, it’s here, or you can navigate your way to the package inside Emacs with C-hkM-/, and then go from there to the package.
  5. Turns out you don’t have to do it this way: you can switch to the completion buffer, and then you can move around with arrows, including up and down, and select what you want with Enter like a normal human being. You could also add (setq completion-auto-select t) to your init for this switch to happen automatically whenever you press C-M-i.
  6. As mentioned earlier, these packages and their functions go beyond what I’ll write in this post, but a few things are worth mentioning: company is much older then corfu, which came into existence after Emacs implemented completion-at-point functions; as a result, corfu is based on capf, and doesn’t come with anything “extra” out of the box besides a few option to display completion in a dynamic matter. Company, on the other hand, is a much bigger package that has a whole backend to it, complete with a lot of additional functions. I ended up installing and trying corfu, with Emacs’ native functions, and then installed cape (completion at point extensions) makes more functions available in a buffer than you’d usually have. What does that mean? Well, say you’re writing something in org-mode. the cap functions you have available do not include, for example, file names and paths, which you might want; these functions will be available to you when you are in a shell buffer (usually) — it’s Emacs being Emacs and trying to be useful. So with cape, you can ask for that function to be available in org-mode as well.
添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论