Posts tagged with "Coding"

become.el v1.4.0

2 min read; 9 GFI

In the last month or so, as I've mentioned a few times before, I've been trying to tidy up some of my older personal Emacs Lisp packages. I thought I'd updated all the ones I commonly use, but it turns out I hadn't. Somehow I'd missed become.el.

This is another one of those packages whose content started out as ad-hoc commands, added to the ~/.emacs that first started to emerge as I got to know Emacs on OS/2 and then GNU/Linux back in the mid-1990s. I think it was back in 20161, when I did a big revamp of my Emacs environment, that I moved all of those roughly-related commands out into their own file.

Honestly, I think I can dump most of them now. There's stuff in there for quickly and easily converting buffers between "DOS format" and "Unix format" (from back when I was still working a lot on Windows machines, and sometimes even in MS-DOS-based virtual machines, and often using the DJGPP-built version of Emacs).

One command I still use all the time is become-free-of-trailing-whitespace, because I have that set up as part of a before-save-hook:

(use-package become
  :ensure t
  :defer t
  :vc (:url "https://github.com/davep/become.el" :rev :newest)
  :commands become-free-of-trailing-whitespace
  :init
  (unless noninteractive
    (add-hook 'before-save-hook #'become-free-of-trailing-whitespace))
  :bind
  ("<f12> <tab>" . become-freshly-indented-no-tabs))

While I know that there are better ways of handling the trailing space issue these days, this is one I rolled for myself a couple of decades ago and it's yet to fail me. You can see just how dated it is from this:

(cl-flet ((is-sig-line ()
                       (save-excursion
                         (beginning-of-line)
                         (looking-at "^-- $")))
          (markdown-br-p ()
                         (save-excursion
                           (beginning-of-line)
                           (and (eq major-mode 'markdown-mode)
                                (looking-at "^.+[^ ]  $")))))
; ...body removed
)

If you know, you'll know why is-sig-line is there2.

I do still use become-freshly-indented-no-tabs on occasion too, and have it bound to an easy-to-remember and obvious (to me) key.

And so, despite the fact that most of the content of become.el is probably obsolete at this point, despite the fact that there are probably far better and more idiomatic ways of doing these things these days... it's my little personal package that has grown with me in the 3 (and a bit) decades I've had Emacs under my fingertips. I'm going to keep it around just a little longer.


  1. The header for become.el says 2017, but I think the header itself came a little later when I did some more work on my config

  2. And if you don't know, now you do

blogmore.el v5.3.0

1 min read; 5 GFI

I've released blogmore.el v5.3.0. This is a pretty small release but adds a command I realised I'd forgotten to add a couple of releases ago.

Now that BlogMore has the concept of a post series, and now that blogmore.el lets you add and remove a series from a post, it makes sense that I'd want to link to a series in a post from time to time, like I can and do with categories and tags.

So v5.3.0 adds a blogmore-link-series command. It can also be found in the transient menu.

Getting on with Antigravity

2 min read; 10 GFI

It's been a wee while now since I stopped using GitHub Copilot and switched to doing everything locally (in a tool sense, not a model sense) with the Antigravity CLI, so I thought I'd jot down how it's been going. Simply put, it's been going well.

I've found the CLI itself easy enough to work with (I've not really attempted to use the GUI application), and the default model choice has done a lot of work for me on BlogMore without issue. I think it's fair to say that, at this point, I'm finding it far more consistent than I was finding Copilot+Claude.

As for the initial confusion and concerns about quotas: I've found that that's calmed down, with me never obviously coming close to hitting my limit while working on any change to BlogMore. The worst I've seen is getting down to about 20% of the 5-hour rolling window, and even then that's been when I've pretty much finished the work I was doing.

The actual display of quotas has changed too, I noticed just this morning. Now, rather than showing progress bars per model, it's more like this:

The new Antigravity quota display

While I suspect the weekly quota display will cause a smidge of anxiety to start with, mostly I appreciate that being added, and being so clear. Given the level of work I'm using this for, I can't see myself coming close to using it all up and having to wait. The quota does come with an explanation in the CLI too:

Within each group, models share a weekly limit and a 5-hour limit. Quota is consumed proportionally to the cost of the tokens. Thus, limits will last longer with shorter tasks or using more cost-effective models. The 5-hour limit smooths out aggregate demand to fairly distribute global capacity across all users, while your weekly limit is tied directly to your individual tier.

Digging a little deeper, I see there's a /credits command and, quite quickly, I can go from that to this in my browser:

I can buy more credits

I'm not sure exactly how much work 2,500 credits might represent, or what impact it would have or could have on the weekly quota; confusingly, if I follow the links from the CLI to see my usage, I see a message that says:

AI credits included with your plan have been replaced by product-based usage limits

So which is it? Do I have usage limits? Do I have a hard cap for a week? Can I extend it or not? Do I extend it using credits or not? I sense the messaging around this is all still a little mixed up. I do know that if I turn on credit fallback in /settings, I get a handy display of the credits I have left:

AI Credits: 1000

So this weirdly reads like I can and am using credits as a fallback to the quota, but also not.

Schrödinger’s Quota?

I'll dig around some more and see if I can find a definitive answer.

All that said: barring any changes that might upset things (which, let's be honest, is something that's highly likely given the state of the AI/agentic coding world), I think I'm happy with how this is going. For now, at least, BlogMore's primary development tool will carry on being Antigravity.

And me, of course.

blogmore.el v5.2.0

1 min read; 10 GFI

Another quick update to blogmore.el, again to fix an issue I've run into with the new frontmatter-handling code. This time it's to address an actual crash that could happen if a property was available but empty. For example, if a post had frontmatter that looked like this:

title: "blogmore.el v5.2.0"
date: "2026-06-12 08:31:15+0100"
category: Emacs
tags:

And I then went to use blogmore-add-tag, I'd get a crash saying:

Wrong type argument: sequencep, :null

The reason being that tags was being parsed with a value of :null, rather than (as before) having a value of nil (which of course meant I had a nice empty list to do things with). It was an easy enough fix.

At this point I think I've managed to shake out any serious issues with the proper YAML-parsing approach to frontmatter, as I've used it to write a handful of posts now.

blogmore.el v5.1.0

1 min read; 12 GFI

A quick little update to blogmore.el to fix a couple of issues introduced by the new YAML-parsing approach to reading frontmatter; both pretty much stemming from how falsy values are handled.

Simply put, both boolean false values, and also empty values (something that could commonly happen with tags and series) would end up showing up in the frontmatter as null. This release handles that situation.

Also, under the hood, I cleaned up some repeated boilerplate related to how the cached dump calls to BlogMore took place. The code for categories, tags and series data was almost exactly the same, save for the actual name of the thing being dumped. So I turned it all into a macro:

(defmacro blogmore--cache-dump (dump-name)
  "Generate a function to get DUMP-NAME from BlogMore, with caching."
  (let ((cache-name (intern (format "blogmore--current-%s-cache" dump-name)))
        (getter-name (intern (format "blogmore--current-%s" dump-name))))
    `(progn
       (defvar ,cache-name nil
         ,(format "Cache for the list of %s from existing posts." dump-name))
       (defun ,getter-name ()
         ,(format "Get a list of %s from existing posts." dump-name)
         (or ,cache-name (setq ,cache-name (blogmore--list-of ,(symbol-name dump-name))))))))

and now the defvar that creates the variable that holds the cache, and the defun that creates the getter function for the data, are reduced to this for all three collections of values:

(blogmore--cache-dump categories)
(blogmore--cache-dump tags)
(blogmore--cache-dump series)

Sure, I probably could have done all of this in a single global, a central getter function, and a hash table, but the macro approach feels so much more elegant, and more... lispy.

BlogMore v2.43.0

1 min read; 12 GFI

After recently adding Mermaid and maths support to BlogMore, I got to thinking that it now has connections with a handful of third-party resources. While almost all of them are optional (only FontAwesome comes close to being a hard requirement), it does mean that there are resources the user doesn't directly supply or control, and for which the URLs are hard-coded in the source for BlogMore.

I wasn't keen on this. While it's my intention to keep an eye on things and, periodically, check on those libraries and see if they need an update, I felt it was important that the user could override them on their own, without waiting on me.

So v2.43.0 adds a third_party section to the configuration file to give full control over these resources. The full version of it looks like this:

third_party:
  mermaid:
    script_url: "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs"
  katex:
    css_url: "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css"
    js_url: "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"
  mathjax:
    js_url: "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"
  fontawesome:
    metadata_url: "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/6.7.2/metadata/icons.json"
    webfonts_base: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts"
    css_url: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css"
    woff2_url: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/webfonts/fa-brands-400.woff2"
  force_graph:
    js_url: "https://unpkg.com/force-graph"

Of course, it's not an all-or-nothing setting; you can just set one of the values. So if you wanted to override the force_graph value it's enough to do:

third_party:
  force_graph:
    js_url: "https://unpkg.com/force-graph"

Hopefully this adds some useful flexibility. As well as giving the option to use a different version of a resource, it also allows you to host your own copy and refer to that instead. Heck, it would even allow totally replacing a library with a different one that has the same API, should you ever find yourself in that situation.

blogmore.el v5.0.0

3 min read; 10 GFI

When I released blogmore.el v4.7.0 yesterday I finished off by saying that it was my intention, at some point, to rework the frontmatter-handling code so that it did proper YAML parsing. As often happens with these sorts of things, "some point" ended up being that evening.

I've rewritten everything to do with handling properties in the frontmatter so that it now uses yaml.el. This has a number of knock-on effects. The first and most obvious effect is that anything that is a list/array in the frontmatter is actually properly treated as a list. A good example here is tags. Now you can have your tags look like:

tags: [BlogMore, Emacs, "Emacs Lisp", Lisp, "blogmore.el", coding]

or:

tags:
  - BlogMore
  - Emacs
  - Emacs Lisp
  - Lisp
  - blogmore.el
  - coding

and blogmore.el will still handle things fine. The same holds for series too.

It should be noted, however, that because I'm now using actual YAML serialisation code, most other forms of a list will all end up being transformed into this kind:

tags: [BlogMore, Emacs, "Emacs Lisp", Lisp, "blogmore.el", coding]

So if you have a bare list:

tags: BlogMore, Emacs, "Emacs Lisp", Lisp, "blogmore.el", coding

and you make an edit to the tags via blogmore.el, it will end up as the version enclosed in []. BlogMore itself supports all three versions so this works fine.

There is a breaking change here too, which in part explains the reason I bumped the version to 5.0.0: because series can now be treated as a list I've removed the blogmore-set-series command and instead replaced it with blogmore-add-series and blogmore-remove-series. Both can of course be found in the transient menu.

Another big change in this release is the way that existing values are loaded up from your blog. Previously, when you went to add a category, tag or series, blogmore.el would use ripgrep (or a combination of find and grep if rg wasn't available) to pull out values to help populate a completion list. This worked fine as long as a) the frontmatter property was all on one line and b) the body of a post didn't contain something that looked like a frontmatter property. With this release of blogmore.el I've dropped this approach in favour of calling blogmore itself and using the dump command to get the actual lists of categories, tags and series.

This does mean that BlogMore needs to be installed in a location where blogmore.el can see it, and to help with this I've added a new defcustom called blogmore-command. By default this is set to call whatever version of blogmore can be found in your exec-path; if this results in unexpected behaviour you can set blogmore-command to point to a specific copy of blogmore.

There is, however, a small downside to this beneficial1 approach: calling on blogmore and parsing all posts to get the values is generally going to be slower. With this in mind I've built in a cache for these values. The first time you load up the categories, tags or series, the values are held on to so that subsequent prompts are instantaneous (meaning there is no further call to blogmore). To ensure this doesn't confuse things, when you switch blog (blogmore-work-on) the caches are cleared. In the unlikely event that there is a problem with this approach, I've also added a blogmore-clear-caches command to force the clearing of the caches.

There are some other small QoL changes under the hood and also to the interface. I've moved some things around in the transient menu, and also ensured that a couple of options are better-disabled depending on the context.

The current menu

All of this makes the package even more robust. Something that started as a quick hack back in March has turned into a tool I heavily lean on. Hopefully, for anyone who might happen to use BlogMore and GNU Emacs, it'll be a useful daily-driver for them too.


  1. The benefits being: only values in frontmatter appear, inconsistent casing is cleaned up, etc. 

blogmore.el v4.7.0

1 min read; 9 GFI

A quick update to blogmore.el. Having recently added series support to BlogMore it made sense that I then add a quick way of adding a post to a series in the package.

Selecting a series

You can, of course, set a new one too, but the idea here (as with categories and tags) is that you can quickly find back an existing series and add the current post to it.

Also, as with tags, the expectation is that either a single series is being used, or if more than one series is in play for a post they'll be listed as a comma-separated list. The issue here is that while BlogMore supports this:

series:
  - Some series of posts
  - Some other series of posts
  - Yet another series of posts

the frontmatter-handling code in blogmore.el isn't very sophisticated at all; it doesn't actually handle it as actual YAML, instead just treating it as a set of key/value pairs separated by a colon.

At some point soon I want to give blogmore.el a revamp and base all of the frontmatter-handling code on something like yaml.el. I did do some experimenting last night to drop it in and handle proper lists. It worked well enough, but I abandoned the work as I realised I really wanted to start again from scratch and build blogmore.el from the bottom up using that package.

Some time soon...

BlogMore v2.42.0

1 min read; 10 GFI

I've released BlogMore v2.42.0. This version is all about changes to the dump command.

When I first added it it simply dumped all of the data available about posts within a blog, meaning it was possible to do all sorts of things with the data outside of BlogMore itself. Having done this, and used the result to good effect (and also having seen at least one person also make use of it), I got to thinking that I should probably expose some other data that's going to be helpful.

Given that blogmore.el needs to dive into things like available categories and tags, and given that I'd also like to add support there for the recently-added series support, I realised that dumping those values as JSON would also be helpful.

So this release extends the dump command, adding a set of sub-commands:

  • posts: dumps the data about all posts in the blog (this is the default if you just run blogmore dump, so keeping the command backward-compatible).
  • categories: dumps all categories as slug/title pairs.
  • tags: dumps all tags as slug/title pairs.
  • series: dumps all series as slug/title pairs.

For example, getting all categories from this blog:

blogmore dump categories
[
  ["ai", "AI"],
  ["coding", "Coding"],
  ["creative", "Creative"],
  ["emacs", "Emacs"],
  ["gaming", "Gaming"],
  ["life", "Life"],
  ["meta", "Meta"],
  ["music", "Music"],
  ["python", "Python"],
  ["tech", "Tech"],
  ["til", "TIL"]
]

Or all the available series right now:

blogmore dump series
[
  ["agentic-afterthoughts", "Agentic Afterthoughts"],
  ["buying-the-steam-controller", "Buying the Steam Controller"],
  ["edinburgh-fringe-2023", "Edinburgh Fringe 2023"],
  ["reading-2bit-files-for-fun", "Reading 2bit files (for fun)"],
  ["swift-til", "Swift TIL"],
  ["the-great-github-copilot-meltdown-of-2026", "The Great GitHub Copilot Meltdown of 2026"],
  ["the-virgin-east-coast-saga", "The Virgin East Coast Saga"],
  ["emacs-d", "~/.emacs.d"]
]

While this data could have been gathered from the content of the dump of posts, this approach makes it far easier to work with and more accessible; simply put, it means there's less work for the user to do if they just want all the tags (for example). With this, and with a little bit of caching in the code (because this does require parsing all the posts every time), I think it will make for a better approach to category, tag and (when I add it) series completion while writing a post.

BlogMore v2.41.0

2 min read; 12 GFI

It's probably bad news if I have a Saturday afternoon and evening spare, a fully-charged laptop and a comfy sofa. It seems that when that happens, something like BlogMore v2.41.0 happens. This is a release where I've added two features that could be generally useful, but which I'm unlikely to use in my own blogs.

The first, which to be fair is one I might use (I've used it in documentation plenty of times over the years), is optional Mermaid support. This is off by default, so has no overhead if you don't turn it on. It is turned on by setting with_mermaid to true. Even with this enabled, the Mermaid third-party scripts only get included on pages that include a Mermaid diagram, reducing the overhead.

To include a Mermaid diagram you use a fenced codeblock with mermaid as the language identifier. For example:

```mermaid
graph TD
    A[Start] --> B[Process]
    B --> C{Decision}
    C -->|Yes| D[Success]
    C -->|No| E[Fail]
```

If Mermaid is enabled the resulting page will show this:

Example Mermaid diagram

There are, of course, all sorts of diagrams that can be used and I'm not going to go into them here, or in the BlogMore docs; Mermaid is well known enough and well-documented enough that anyone turning this on is likely to know what they're doing, or where to go to find out what to do.

The second new feature, which I am almost certainly never going to need to use on my blog, is LaTeX-style maths support. As with Mermaid, this is off by default and has no overhead if not used. Even when turned on with the with_maths setting, the external scripts will only be pulled into pages that include maths markup.

Two providers of rendering engines are supported and this can be configured with the maths_provider setting. The available options are katex (which is also the default) and mathjax.

To use either, when turned on, you use the usual $ or $$ convention for LaTeX-maths-in-Markdown:

You can make some fun images using:

$$
z_{n+1} = z_n^2 + c
$$

We can say $z_{n+1} = z_n^2 + c$ inline too.

The result of the above will be something like:

Maths markup in action

Note that some care has been taken to ensure that ordinary use of a $, in currency values for example, is left unaffected. This can't be guaranteed in every possible case, so keep this in mind when turning on with_maths. From what I have read this is a common issue when using such markup.

Both these features were fun to add, with me planning out the implementation with Antigravity, and having a back and forth a couple of times to address issues and get it all working "just so". I'm especially pleased with the fact that it's done in a way where there is no overhead, even when either feature is enabled, if a page isn't showing a diagram or maths markup.