Posts tagged with "Emacs Lisp"

kbdify.el v1.0.0

1 min read

When I'm writing documentation in Markdown I like, where possible, to mark up keys with the <kbd> tag. This was the reason for one of the updates to BlogMore: I'd not done any good default markup for <kbd> and the moment I realised, I knew I had to fix it.

Now that I'm writing more on this blog, and especially about coding, I'm mentioning keys pretty often (even more so given I'm doing a lot of tidying up of my Emacs Lisp packages). The thing is though: I find having to type out <kbd> and </kbd> kind of tedious, and it's something I mistype from time to time. I guess I could use some sort of HTML tag inserting tool or whatever, but I got to thinking that it would be handy if I could point an Emacs command at a particular sequence in a buffer and have it mark up the whole thing.

This resulted in a small bit of code I'm calling kbdify.el. It's pretty simple, if point is sat on some text that looks like this:

C-M-S-s-<up>

and I run kbdify I get this:

<kbd>C</kbd>-<kbd>M</kbd>-<kbd>S</kbd>-<kbd>s</kbd>-<kbd>&lt;up&gt;</kbd>

The result rendering as C-M-S-s-<up>.

I could probably take it a bit further, have it optionally work on a region and stuff like that, but even in its current simplistic form it's going to be loads quicker and a lot more accurate and will probably perfectly cover 99% of the times I need it. There is the issue that it's not going to handle something like M-x some-command RET in the way I might like, but then again some-command isn't a key. Like, does it make more sense to have:

M-x some-command RET

anyway? Personally I think this:

M-x some-command RET

probably makes more sense.

I think I'm good for now.

itch.el v1.3.0

1 min read

When I'm working in Emacs I use the *scratch* buffer quite a bit. I find it especially useful if I'm working on some Emacs Lisp code, but I also find it handy as a place to drop something I want to retrieve soon, or a quick note that I want to refer back to soon; sometimes I even paste some text there and copy it back just to strip the formatting from it before using it elsewhere1.

Because of this, for a long time, I carried a little function around that I had bound to M-s to quickly take me to the *scratch* buffer. Then, I think around the time I did the follow-up revamp of my Emacs configuration, I turned it into a little package for my own use called itch.el.

The command (itch-scratch-buffer) is simple enough: run it and I get switched to my *scratch* buffer. If I run it with a prefix argument it switches to *scratch* and resets the content back to the initial-scratch-message.

More recently I've found that I'm wanting a scratch buffer that is for writing Markdown. Like many folk I use it a lot for documentation, and of course I also use it for this blog. I also use it heavily for keeping notes in Obsidian2. So, often, I find myself switching to a temporary buffer (*foo* or something), setting it to markdown-mode, and then writing what I need.

So yesterday I finally cracked and added itch-markdown-scratch-buffer. It's just like itch-scratch-buffer, only it creates a *scratch: Markdown* buffer, using the same clear-if-prefix rule.

So now I've got this bound to M-S-s and I can faff around just a little less when I want a Markdown scratchpad.


  1. On macOS at least, I find the "paste without formatting" support of some applications to be really inconsistent; a quick layover in the *scratch* buffer does the trick every time. 

  2. Yes, I know, I should be using Org, but sadly it's just never clicked for me, and I also find good syncing and having a consistent application on mobile and desktop are important. 

unabbrev.el v1.0.0

3 min read

Back in the late 1990s, like plenty of people who were very online, I was a very avid user of Usenet. There were a few groups I was very active in, even a couple that I maintained a FAQ for. Being that active and wanting to help and answer questions, I was forever posting and pasting links to various resources. Given that I used Emacs to edit my posts1, I eventually realised that I should come up with a tool that let me call on common URLs quickly.

So back in 1998 handyurl.el was born. It was a simple idea: have a file of URLs that I commonly refer to and let me quickly pick from one and paste it. This made for a useful tool and also gave me something to build given I was learning Emacs Lisp at the time.

For reasons I can't quite recall, some time later (the next year, by the looks of things), I wrote quickurl.el as a successor to handyurl.el. I honestly can't remember why this happened, I can't remember why I didn't just keep extending handyurl.el. But, anyway, quickurl.el did more and was more flexible, with built-in URL-grabbing and editing and so on.

Not that long later I got an email from the FSF asking if I might be willing to hand over copyright so that quickurl.el could become part of Emacs itself. I was, of course, delighted to do so.

Eventually quickurl.el was declared obsolete and, while it seems to still be shipped with Emacs, it's not documented or easy to discover.

In the deprecation notice in NEWS the suggestion is that the user should switch to one or more of 3 alternatives:

** The quickurl.el library is now obsolete.
Use 'abbrev', 'skeleton' or 'tempo' instead.

abbrev I know, the other two I've never noticed and don't know anything about.

Obviously, between quickurl.el being pulled into Emacs, and it being made obsolete, my use of it fell right off. I eventually stopped posting to and reading Usenet, I also stopped using mutt+Emacs as my mail client of choice, and so found myself seldom writing things that needed lots of links, in Emacs.

Until recently.

At the moment I'm finding that I'm wanting to write on my blog more and more, and doing that means I often want to include some common links, and I write my posts in Emacs using markdown-mode and with a little help from blogmore.el; the need to have an easy-to-pick-from common menu of URLs is back.

Driven by this I've made a point of using abbrev to initially solve this problem. This works, but I do have a problem: I keep forgetting what the abbreviations are. I find myself wanting to have a key binding that lets me at the very least completing-read the desired abbrev. So yesterday I quickly knocked up unabbrev.el.

It's simple, straightforward, small and does the job I needed. Doubtless there's something else out there that can do this sort of thing too, but part of the fun of Emacs (for me) is that I find I have a need and I can hack together some Lisp and get that problem solved.

unabbrev in action

I suppose what I should do is revive either handyurl.el or quickurl.el and tweak and update whichever, at the very least adding some sort of insert formatting facility that is sensitive to the underlying mode (because links in Markdown need a format different from links in HTML, etc).

For now though unabbrev.el is going to help my failing memory when I want to link a common resource.

As an aside, all of this does have me wonder about one thing: is the Free Software Foundation the place that code goes to die? Like, sure, of course I can make changes to quickurl.el and do my own thing with it, as long as I don't misrepresent the copyright status and maintain a compatible licence, etc; but there is this thing where, if Emacs doesn't want that code any more, if the FSF don't want that code any more, wouldn't it be nice if they'd sign it back over again?

I am tempted to drop them a line and see what the deal is. I did tag-ask on Mastodon but got no reply. Unfortunately though that account looks like the FSF treat Mastodon as a write-only resource.


  1. But curiously never got into Gnus, my news client of choice was slrn and I composed posts in Emacs. 

expando.el v1.6

1 min read

Recently I've had an odd problem with Emacs: occasionally, and somewhat randomly, as I wrote code, and only when I wrote Emacs Lisp code, and only when working in emacs-lisp-mode, I'd find that the buffer I was working in would disappear. Not just fully disappear, but more like if I'd used quit-window. Worse still, once this started happening, it wouldn't go away unless I turned Emacs off and on again.

Very un-Emacs!

Normally this would happen when I'm in full flow on something, so I'd just restart Emacs and crack on with the thing I was writing; because of this I wasn't diagnosing what was actually going on.

Then, today, as I was writing require in some code, and kept seeing the buffer go away when I hit q, it dawned on me.

Recently, when I cleaned up expando.el, I added the ability to close the window with q.

--- a/expando.el
+++ b/expando.el
@@ -58,7 +58,8 @@ Pass LEVEL as 2 (or prefix a call with \\[universal-argument] and
   (let ((form (preceding-sexp)))
     (with-current-buffer-window "*Expando Macro*" nil nil
       (emacs-lisp-mode)
-      (pp (funcall (expando--expander level) form)))))
+      (local-set-key (kbd "q") #'quit-window)
+      (pp (funcall (expando--expander level) form)))))

 (provide 'expando)

So, after opening a window for the purposes of displaying the expanded macro, switch to emacs-lisp-mode, locally set the binding so q will call on quit-window, and I'm all good.

Except... not, as it turns out.

To quote from the documentation for local-set-key:

The binding goes in the current buffer’s local map, which in most cases is shared with all other buffers in the same major mode.

D'oh!

Point being, any time I used expando-macro, I was changing the meaning of q in the keyboard map for emacs-lisp-mode. :-/

And so v1.6 of expando.el is now a thing, in which I introduce a derived mode of emacs-lisp-mode and set q in its keyboard map. In fact, I keep the keyboard map nice and simple.

(defvar expando-view-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map (kbd "q") #'quit-window)
    map)
  "Mode map for `expando-view-mode'.")

(define-derived-mode expando-view-mode emacs-lisp-mode "expando"
  "Major mode for viewing expanded macros.

The key bindings for `expando-view-mode' are:

\\{expando-view-mode-map}")

From now on I should be able to code in full flow state without the worry that my window will disappear at any given moment...

blogmore.el v4.2

1 min read

Another wee update to blogmore.el, with a bump to v4.2.

After adding the webp helper command the other day, something about it has been bothering me. While the command is there as a simple helper if I want to change an individual image to webp -- so it's not intended to be a general-purpose tool -- it felt "wrong" that it did this one specific thing.

So I've changed it up and now, rather than being a command that changes an image's filename so that it has a webp extension, it now cycles through a small range of different image formats. Specifically it goes jpeg to png to gif to webp.

With this change in place I can position point on an image in the Markdown of a post and keep running the command to cycle the extension through the different options. I suppose at some point it might make sense to turn this into something that actually converts the image itself, but this is about going back and editing key posts when I change their image formats.

Another change is to the code that slugs the title of a post to make the Markdown file name. I ran into the motivating issue yesterday when posting some images on my photoblog. I had a title with an apostrophe in it, which meant that it went from something like Dave's Test (as the title) to dave-s-test (as the slug). While the slug doesn't really matter, this felt sort of messy; I would prefer that it came out as daves-test.

Given that wish, I modified blogmore-slug so that it strips ' and " before doing the conversion of non-alphanumeric characters to -. While doing this, for the sake of completeness, I did a simple attempt at removing accents from some characters too. So now the slugs come out a little tidier still.

(blogmore-slug "That's Café Ëmacs")
"thats-cafe-emacs"

The slug function has been the perfect use for an Emacs Lisp function I've never used before: thread-last. It's not like I've been avoiding it, it's just more a case of I've never quite felt it was worthwhile using until now. Thanks to it the body of blogmore-slug looks like this:

(thread-last
  title
  downcase
  ucs-normalize-NFKD-string
  (seq-filter (lambda (char) (or (< char #x300) (> char #x36F))))
  concat
  (replace-regexp-in-string (rx (+ (any "'\""))) "")
  (replace-regexp-in-string (rx (+ (not (any "0-9a-z")))) "-")
  (replace-regexp-in-string (rx (or (seq bol "-") (seq "-" eol))) ""))

rather than something like this:

(replace-regexp-in-string
 (rx (or (seq bol "-") (seq "-" eol))) ""
 (replace-regexp-in-string
  (rx (+ (not (any "0-9a-z")))) "-"
  (replace-regexp-in-string
   (rx (+ (any "'\""))) ""
   (concat
    (seq-filter
     (lambda (char)
       (or (< char #x300) (> char #x36F)))
     (ucs-normalize-NFKD-string
      (downcase title)))))))

Given that making the slug is very much a "pipeline" of functions, the former looks far more readable and feels more maintainable than the latter.

blogmore.el v4.1

1 min read

Following on from yesterday's experiment with webp I got to thinking that it might be handy to add a wee command to blogmore.el that can quickly swap an image's extension from whatever it is to webp.

So v4.1 has happened. The new command is simple enough, called blogmore-webpify-image-at-point; it just looks to see if there's a Markdown image on the current line and, if there is, replaces the file's extension with webp no matter what it was before.

If/when I decide to convert all the png files in the blog to webp I'll obviously use something very batch-oriented, but for now I'm still experimenting, so going back and quickly changing the odd image here and there is a nicely cautious approach.

I have, of course, added the command to the transient menu that is brought up by the blogmore command.

One other small change in v4.1 is that a newly created post is saved right away. This doesn't make a huge difference, but it does mean I start out with a saved post that will be seen by BlogMore when generating the site.

boxquote.el v2.4

2 min read

boxquote.el is another of my oldest Emacs Lisp packages. The original code itself was inspired by something I saw on Usenet, and writing my own version of it seemed like a great learning exercise; as noted in the thanks section in the commentary in the source:

Kai Grossjohann for inspiring the idea of boxquote. I wrote this code to mimic the "inclusion quoting" style in his Usenet posts. I could have hassled him for his code but it was far more fun to write it myself.

While I never used this package to quote text I was replying to in Usenet posts, I did use it a lot on Usenet, and in mailing lists, and similar places, to quote stuff.

The default use is to quote a body of text; often a paragraph, or a region, or perhaps even Emacs' idea of a defun.

,----
| `boxquote.el` provides a set of functions for using a text quoting style
| that partially boxes in the left hand side of an area of text, such a
| marking style might be used to show externally included text or example
| code.
`----

Where the package really turned into something fun and enduring, for me, was when I started to add the commands that grabbed information from elsewhere in Emacs and added a title to explain the content of the quote. For example, using boxquote-describe-function to quote the documentation for a function at someone, while also showing them how to get at that documentation:

,----[ C-h f boxquote-text RET ]
| boxquote-text is an autoloaded interactive native-comp-function in
| ‘boxquote.el’.
|
| (boxquote-text TEXT)
|
| Insert TEXT, boxquoted.
`----

Or perhaps getting help with a particular key combination:

,----[ C-h k C-c b ]
| C-c b runs the command boxquote (found in global-map), which is an
| interactive native-comp-function in ‘boxquote.el’.
|
| It is bound to C-c b.
|
| (boxquote)
|
| Show a transient for boxquote commands.
|
|   This function is for interactive use only.
|
| [back]
`----

Or figuring out where a particular command is and how to get at it:

,----[ C-h w fill-paragraph RET ]
| fill-paragraph is on fill-paragraph (M-q)
`----

While I seldom have use for this package these days (mainly because I don't write on Usenet or in mailing lists any more) I did keep carrying it around (always pulling it down from melpa) and had all the various commands bound to some key combination.

(use-package boxquote
  :ensure t
  :bind
  ("<f12> b i"   . boxquote-insert-file)
  ("<f12> b M-w" . boxquote-kill-ring-save)
  ("<f12> b y"   . boxquote-yank)
  ("<f12> b b"   . boxquote-region)
  ("<f12> b t"   . boxquote-title)
  ("<f12> b h f" . boxquote-describe-function)
  ("<f12> b h v" . boxquote-describe-variable)
  ("<f12> b h k" . boxquote-describe-key)
  ("<f12> b h w" . boxquote-where-is)
  ("<f12> b !"   . boxquote-shell-command))

Recently, with the creation of blogmore.el, I moved the boxquote commands off the b prefix (because I wanted that for blogging) and onto an x prefix. Even then... that's a lot of commands bound to a lot of keys that I almost never use but still can't let go of.

Then I got to thinking: I'd made good use of transient in blogmore.el, why not use it here too? So now boxquote.el has acquired a boxquote command which uses transient.

The boxquote transient in action

Now I can have:

(use-package boxquote
  :ensure t
  :bind
  ("C-c b" . boxquote))

and all the commands are still easy to get to and easy to (re)discover. I've also done my best to make them context-sensitive too, so only applicable commands should be usable at any given time.

slstats.el v1.11

1 min read

Yet another older Emacs Lisp package that has had a tidy up. This one is slstats.el, a wee package that can be used to look up various statistics about the Second Life grid. It's mainly a wrapper around the API provided by the Second Life grid survey.

When slstats is run, you get an overview of all of the information available.

An overview of the grid

There are also various commands for viewing individual details about the grid in the echo area:

  • slstats-signups - Display the Second Life sign-up count
  • slstats-exchange-rate - Display the L$ -> $ exchange rate
  • slstats-inworld - Display how many avatars are in-world in Second Life
  • slstats-concurrency - Display the latest-known concurrency stats for Second Life
  • slstats-grid-size - Display the grid size data for Second Life

There is also slstats-region-info which will show information and the object and terrain maps for a specific region.

Region information for Da Boom

As with a good few of my older packages: it's probably not that useful, but at the same time it was educational to write it to start with, and it can be an amusement from time to time.

wordcloud.el v1.4

1 min read

I think I'm mostly caught up with the collection of Emacs Lisp packages that need updating and tidying, which means yesterday evening's clean-up should be one of the last (although I would like to revisit a couple and actually improve and extend them at some point).

As for what I cleaned up yesterday: wordcloud.el. This is a package that, when run in a buffer, will count the frequency of words in that buffer and show the results in a fresh window, complete with the "word cloud" differing-font-size effect.

Word cloud in action

This package is about 10 years old at this point, and I'm struggling to remember why I wrote it now. I know I was doing something -- either writing something or reviewing it -- and the frequency of some words was important. I also remember this doing the job just fine and solving the problem I needed to solve.

Since then it's just sat around in my personal library of stuff I've written in Emacs Lisp, not really used. I imagine that's where it's going back to, but at least it's cleaned up and should be functional for a long time to come.

quiz.el v1.7

1 min read

I wondered yesterday:

...those question headers are displaying differently, with the background colour no longer spanning the width of the window. I'd like to understand why.

Turns out it was pretty straightforward:

diff --git a/quiz.el b/quiz.el
index 2dbe45d..c1ba255 100644
--- a/quiz.el
+++ b/quiz.el
@@ -40,7 +40,8 @@
 (defface quiz-question-number-face
   '((t :height 1.3
        :background "black"
-       :foreground "white"))
+       :foreground "white"
+       :extend t))
   "Face for the question number."
   :group 'quiz)

and so v1.7 has happened.

Quiz with reinstated header look

It looks like, perhaps, at some point in the past, :extend was t by default, but it no longer is? Either way, explicitly setting it to t has done the trick.