Posts in category "Emacs"

obfusurl.el v2.2

1 min read

This bit of Emacs Lisp absolutely comes from a more innocent time on the Internet. Looking at it, it seems I wrote the first version, at least as a proper package, back in 2001. It's very possible that I carried a non-package version of it around as part of dp-lib.el1 for some time before, so it might date from the late 1990s. While we weren't absolutely innocent back then, the idea of a slightly-risky-looking URL wasn't quite so bad as it is now.

So obfusurl.el came about from my time on Usenet, where sometimes you'd want to post a URL that would otherwise be a spoiler. This package was my solution to that. It's a simple idea: keep the protocol and domain and so on visible, just hide the remaining part. So rather than post:

https://blog.davep.org/about/

You'd post:

https://blog.davep.org/%61%62%6f%75%74/

I suppose this is still useful today, although I would expect a lot of people to be way less likely to want to attempt that click -- readable domain or not.

But, anyway, the code needed a tidy and cleanup for today's Emacs and Emacs Lisp. So obfusurl.el v2.2 now exists.


  1. For a good chunk of my first decade of using Emacs, I carried a lot of personal code around in a rather large "library" file. 

eg.el v1.2

1 min read

Okay, that's it then; this is turning into a thing I think. Second in an occasional series of posts where I tidy up some of my old Emacs packages. This time I dug out eg.el and cleaned up some of the frowned-upon behaviour.

For anyone who doesn't know it: eg.el is one of many Norton Guide readers I've written over the years. This particular one was possibly the most fun as it was the most unlikely one to write and also, I think it's fair to say, my most ambitious one as well. It also holds a special place for me in that the bulk of it was written on trains during multiple trips up to Scotland, before I finally moved here (on the MacBook Air I mentioned the other day).

As I look at it now, I sort of want to give it a proper revisit. I've written more Norton Guide code since (see AgiNG for example) and have learnt better ways to handle certain things, and I also have an even bigger Norton Guide collection to test against. All of this could make for an even better Emacs implementation.

I also suspect that, this time around, I can do a better job of handling the colour and retaining the original Norton Guide reader look and feel. But, for now, the code has been tidied up and should keep working for some time yet.

thinks.el v1.13

1 min read

Given the recent spate of hacking on some Emacs Lisp, I've got a real taste for hacking on some more. Or, more to the point, revisiting some of the packages I have in Melpa and tidying them up where necessary.

The main thing I'll need to address is cutting back on all my old setf ways. I liked that approach to doing things, it made lots of sense and felt elegant; sadly the Emacs maintainers didn't seem to agree.

So... kicking this off I've released v1.13 of thinks.el. This is a bit of nonsense I wrote back in the days when Usenet was still pretty busy and the place to be (well, okay, back in 2000 when I was still hanging out on Usenet). The package itself lets you quickly and easily...

. o O ( ...write some text and then mark it all and then run a command and )
      ( have it turned into something that looks a little like a thought   )
      ( bubble.                                                            )

It has some variations on how the bubble looks, and also lets you use customize to tweak the characters to use, and also has an "extra silly" mode too.

Updating this wasn't too bad. Mostly just a case of turning some instances of (setf (point) ...) into (goto-char ...), and also modifying one instance of incf to be cl-incf.

Honestly, I don't know how useful this package is to anyone anymore. Most folk don't even know what Usenet is these days, and all the "social" places seem to favour non-monospaced fonts, meaning the bubbles would look pretty terrible anyway.

On the other hand, it seems a shame to not update it, and perhaps someone somewhere still uses it to make some pithy parenthetical remark, possibly about September never ending.

blogmore.el v2.3

1 min read

I've bumped blogmore.el to v2.3. The main change in this release, which I've had on my mental to-do list for a couple of days now, revolves around categories, tags and case.

I've got BlogMore set up so that it's pretty relaxed about case when it comes to categories and tags; so when it comes to generated files and URLs everything collapses to lowercase. However, blogmore.el wasn't taking this into account.

While it wasn't a serious issue, it did have the side-effect that, if you had a tag of lisp and a tag of Lisp, both would appear in the list of tags you could complete from. Also, when you went to add a tag to the tags frontmatter (via the blogmore-add-tag command), if you selected Lisp and lisp was already there, you'd end up with both versions after the command finished.

ℹ️ Note

As mentioned earlier: BlogMore itself would collapse Lisp and lisp to the same tag; the downside here is you'd see both tags shown in the post itself. Not a real problem, just not very tidy.

So earlier I changed things up a little; first cleaning up when loading pre-existing values and then ensuring the newly-set tags are deduplicated.

This now means I can edit and update a post even faster, without needing to worry about accidentally duplicating tags. This in turn reduces the friction to writing a post for my blog. That is, after all, the whole point of the name of the package and the blogging tool it's connected to!

blogmore.el v2.2

3 min read

It really feels like BlogMore has kicked off a whole new thing when it comes to personal hacking. During the past few years I've developed a lot of Python applications and libraries, and have had a ton of fun doing so, but during that time I've not really done anything with writing stuff for Emacs.

To a large degree I think this says something about how stable Emacs is for me (I've been using it for a touch over 30 years at this point, you'd think I'd be kind of settled with it), but it's still always fun to have a reason to hack on some Lisp code. There's little doubt my Lisp -- especially Emacs Lisp -- has got a wee bit rusty.

So I'm having a lot of fun at the moment falling into the rabbit hole of expanding on and tinkering with blogmore.el. The reason I've just made v2.2 is a good example of exactly this. There are no real user-facing changes in the code, it was all things I just wanted to tidy up.

The main thing that has been bugging me for the past day is the repeating boilerplate that resulted from adding all the different current-blog-aware setting getter functions. There were 7 different functions, all looking like this:

(defun blogmore--post-maker-function ()
  "Get the post maker function for the current blog."
  (or
   (blogmore--blog-post-maker-function (blogmore--chosen-blog))
   blogmore-default-post-maker-function))

Exact same pattern, the only thing different being the name of the getter function being called on, and the name of the variable that contained the global default value.

So just a little earlier I cleaned this up using one of my favourite things about Lisp: defmacro. There's something about macros that makes me really like coding in Lisp, and which I cite as a really good thing when asked why I like Lisp, but which I always seem to utterly fail to explain well. Macros feel like one of those things you just have to experience for yourself to really get1.

Now, thanks to this:

(defmacro blogmore--setting (setting)
  "Generate a function to get the value of SETTING for the current blog."
  `(defun ,(intern (format "blogmore--%s" setting)) ()
     ,(format "Get the %s for the current blog." setting)
     (or (,(intern (format "blogmore--blog-%s" setting)) (blogmore--chosen-blog))
         ,(intern (format "blogmore-default-%s" setting)))))

all those 7 functions can collapse to this2:

(blogmore--setting post-template)
(blogmore--setting post-maker-function)
(blogmore--setting category-maker-function)
(blogmore--setting tag-maker-function)
(blogmore--setting post-link-format)
(blogmore--setting category-link-format)
(blogmore--setting tag-link-format)

Now the code is shorter, cleaner, and if I need to change anything I only need to change it in one place. Sure, the latter part especially is one of those "you could do that with a function too" things (have the work in one place), but here I can get the language to write me a whole load of functions, all of which refer to different functions and variables, each one based off just the one symbol.

The point of all of this being: v2.2 of blogmore.el is now out, it adds nothing for the user (who I suspect is only me anyway), but I had an absolute blast dusting off more of my Emacs Lisp knowledge and getting back the urge to code even more Emacs Lisp.

All of this has even got me tidying up my ~/.emacs.d/ and has me thinking I should go back through some of my older code and clean up all that legacy nonsense.


  1. There was a time I would have said "grok" here but... well that's spoiled now. 

  2. I suppose I could reduce that to one "call" with a loop over a list of symbols, but that feels unnecessary here. 

blogmore.el v2.1

1 min read

I've given blogmore.el a wee bump to v2.1. This release fixes a small problem I noticed today when I tried to use it to edit the tags for a post on my photoblog: the code to find and gather properties from posts didn't handle deeply-nested directory hierarchies for the post markdown files. I should have noticed this when I first wrote the code, but of course I was so busy testing against my primary blog, which only goes one sub-level deep, that I never noticed it wasn't going to work deeper.

So rather than using grep to look for things like foo/**/*.md I swapped to a combination of find and grep. Which works, but is slightly (but noticeably) slower.

Then I got to thinking that if I was doing this by hand, on the command line, I'd be using ripgrep anyway. Given this I might as well use it here. Of course, not everyone who might use blogmore.el will have rg installed so it makes sense to look for that and use it if it's available, otherwise fall back on find/grep.

There's still some low-priority cleaning up I want to do around this; an obvious change I want to make being one where I want to collapse all cases of the same word (Tree vs tree, etc) into one "hit"1. For now though, as always, it's working well enough for my needs and this change fixed an obvious issue I ran into.


  1. BlogMore itself takes care of this, but it would be nice to have the prompt in blogmore.el also take this into account. 

blogmore.el v2.0

3 min read

After kicking off blogmore.el, and then tinkering with it more and more, I've found it really quite helpful while writing posts. One thing I have noticed though -- given I use BlogMore for this blog and my photoblog -- is that I wanted to be able to use the package for working with more than one blog.

So today I found myself with some time to kill and the result is that blogmore.el v2.0 has now been released. This version allows for setting up multiple blogs, each with their own settings for where posts live, how their paths are formatted, and so on.

To handle this I've also added the blogmore-work-on command so that the active blog can be quickly changed.

All of this can be configured using Emacs' customize feature.

Customize blogmore

This has all changed since v1.x, where most of the customize options have now been renamed to include -default- in their name. The idea here is that what was the value for a setting previously is now the default value if a given blog hasn't had that setting defined.

For any given blog you wish to work with, you configure a name (for your own reference) and the path to the posts. Optionally you can also set lots of other values too.

Customize the blog

If a value is left on Default, then the corresponding default setting will be used; if it's set, then that value is used for that specific blog.

The defaults out of the box match how I do things with my blogs, of course, so the configuration is pretty straightforward. As of the time of writing my use-package for blogmore.el looks like this:

(use-package blogmore
  :vc (:url "https://github.com/davep/blogmore.el" :rev :newest)
  :init (add-hook 'blogmore-new-post-hook #'end-it)
  :custom
  (blogmore-blogs
   '(("blog.davep.org" "~/write/davep.github.com/content/posts/")
     ("seen-by.davep.dev" "~/write/seen-by/content/posts/")))
  :bind
  ("<f12> m b" . blogmore-work-on)
  ("<f12> m p n" . blogmore-new)
  ("<f12> m p e" . blogmore-edit)
  ("<f12> m s c" . blogmore-set-category)
  ("<f12> m a t" . blogmore-add-tag)
  ("<f12> m u d" . blogmore-update-date)
  ("<f12> m u m" . blogmore-update-modified)
  ("<f12> m l p" . blogmore-link-post)
  ("<f12> m l c" . blogmore-link-category)
  ("<f12> m l t" . blogmore-link-tag))

In the above you can see that I've set only the blog title and posts path for each blog in blogmore-blogs; the remaining values are all implied nil and so will be defaulted. The full list of values for any given blog are:

(BLOG-NAME
 POSTS-DIRECTORY
 POST-TEMPLATE
 POST-MAKER-FUNCTION
 CATEGORY-MAKER-FUNCTION
 TAG-MAKER-FUNCTION
 POST-LINK-FORMAT
 CATEGORY-LINK-FORMAT
 TAG-LINK-FORMAT)

where:

  • BLOG-NAME is the descriptive name to use for the blog.
  • POSTS-DIRECTORY is the directory where the blog's posts are stored.
  • POST-TEMPLATE is a template for new posts. If nil, blogmore-default-template is used.
  • POST-MAKER-FUNCTION is a function that takes a filename and returns a string to be used in the post's URL. If nil, blogmore-default-post-maker-function is used.
  • CATEGORY-MAKER-FUNCTION is a function that takes a category name and returns a string to be used in the category's URL. If nil, blogmore-default-category-maker-function is used.
  • TAG-MAKER-FUNCTION is a function that takes a tag name and returns a string to be used in the tag's URL. If nil, blogmore-default-tag-maker-function is used.
  • POST-LINK-FORMAT is a format string for the post's URL, where %s is replaced with the value returned by the post maker function. If nil, blogmore-default-post-link-format is used.
  • CATEGORY-LINK-FORMAT is a format string for the category's URL, where %s is replaced with the value returned by the category maker function. If nil, blogmore-default-category-link-format is used.
  • TAG-LINK-FORMAT is a format string for the tag's URL, where %s is replaced with the value returned by the tag maker function. If nil, blogmore-default-tag-link-format is used.

While I very much doubt any of this is useful to anyone else, it's at least flexible for my purposes and can probably be configured to someone else's purpose should they happen to be using BlogMore and Emacs.

blogmore.el v1.7

2 min read

Yes, the last time I mentioned blogmore.el it was v1.4 and now it's up to v1.7. So I tinkered a little with it last night, okay?

Anyway, the changes and additions keep happening as I have more fun writing some elisp again. Since the last post about the package I've:

  • Added a command to refresh the date frontmatter property
  • Added a command to add/refresh the modified frontmatter property
  • Added a command to insert a link to a previous post into what I'm writing
  • Made a few things defcustom rather than defconst for easier tweaking
  • Added a hook that can be run after a new post is started
  • Dropped the dependency on end-it and used the above hook to do the same thing

While this package is never intended for use by others, I guess it's not impossible someone might want to work with it (I had the same thing in mind with BlogMore itself yet someone else has started working with it!) and so I'm moving it in the direction of being my way by default but easy to modify to other requirements.

So, now, rather than forcing someone to have to use my obsession with end-of-file markers, I still have that without imposing it on anyone else by simply setting the hook.

(use-package blogmore
  :vc (:url "https://github.com/davep/blogmore.el" :rev :newest)
  :init (add-hook 'blogmore-new-post-hook #'end-it))

I think my favourite addition right now is blogmore-link-post. I like to cross-link posts in my blog as much as possible so having something that lets me do that and stay inside Emacs really speeds things up. So now I just run that command, I get speedy picker to find the post:

Picking a post to link

and the result is some Markdown inserted with the cursor between the two [] ready for me to write the text:

[](/2026/03/20/blogmore-el-v1-4.html)

Other things I link often are categories and tags, so I'm planning on adding commands that does something similar for those two.

blogmore.el v1.4

1 min read

Following on from yesterday's post, in the evening I found myself in a cafe with my MacBook Pro and an hour to kill, so I tinkered with blogmore.el a little more. The main aim here was to add a command for adding tags to a post and I now have blogmore-add-tag as of v1.4.

One thing that stood out was just how rusty my Emacs Lisp skills are. It took me a wee while to get the code working, mostly due to me being caught out by the gotchas I'd forgotten about surrounding match data and the need to make good use of save-match-data (I had a combination of re-search-forward, string-split and replace-match going on and it was chaos for a while).

I got there in the end, though, when I bothered to RTFM with a quick C-h f string-split RET.

Documentation for string-split

So now I have the following commands in Emacs when I get the urge to do something blog-related:

  • blogmore-new starts a new blog post
  • blogmore-edit lets me edit an existing post
  • blogmore-set-category lets me set the category from existing categories, or set a new one
  • blogmore-add-tag lets me add a tag from the existing tags, or add a new one

As suggested before, I think I'll probably add some other helper commands, things such as:

  • Update the date
  • Set the cover to a particular attachment
  • Insert a particular attachment as a Markdown image
  • Insert a link to another post in the blog

I'm sure more will come to me, but they seem like the most common operations I perform that would be helped with a little bit of Emacs Lisp magic.

Some BlogMore Elisp

2 min read

It's been a moment since I last wrote any Emacs Lisp code, at least anything non-trivial. I've tinkered with my Emacs configuration, I've tweaked the odd personal package here and there, but nothing fresh for ages. I actually can't remember what the last package was that I wrote.

But this morning I realised it would be handy to have a couple of functions in Emacs that let me start a new blog post, or edit an existing one. The code didn't need to be clever, just the bare minimum that gets me started; enough to reduce the friction when it comes to opening a new buffer and starting to write.

So blogmore.el happened. Like I say: nothing clever, it simply adds blogmore-new and blogmore-edit; the former starts a new post with the bare minimum frontmatter filled in, the latter lets me quickly pick an existing post and go edit it.

blogmore-edit in action

As time goes on I might expand on this. For example: it might be useful to have a command that updates the date frontmatter; perhaps another to add a modified1; one to set the category from any of the categories I've used so far would be good; ditto the tags property.

I doubt this will be useful to anyone else, although I will try my best to keep it so that it's easy to configure, so it's only ever going to stay amongst my list of personal packages.

Which reminds me... this is the first personal package I've not bothered to add to delpa. That approach to managing my own packages made a ton of sense at the time, but Emacs has moved on since then. Thanks to use-package and :vc I can easily pull blogmore.el into any of my environments with a simple declaration in my .emacs.d.

(use-package blogmore
  :vc (:url "https://github.com/davep/blogmore.el" :rev :newest))

Given how simple and clean that is I'm minded to "retire" delpa and use this approach for all of my personal packages.


  1. Note to self: did I make BlogMore support modified dates?