Archives 2026

Location-Based Themes in Emacs

There are lots of Emacs themes out there. People mostly use them to change colors. That’s great, but you can do more. As the documentation says:

Custom themes are collections of settings that can be enabled or disabled as a unit.

That can be any setting, not just colors.

I use Emacs in multiple situations. I use it at home, I use it in the office, I use it when I’m working from home, and so on. And there are settings that change depending on how and where I’m using Emacs, the most obvious of which being user-mail-address, which I want to set to user@home.org when I’m sending personal mail from home, and user@work.com when I’m sending professional mail from work. I have other settings that change between locations, like the directory where org files go, because reasons. Your location-dependent settings will be different.

So it seems the natural way to deal with this is to put all of the location-dependent settings in a theme, and load whichever theme is appropriate for what you’re doing. Since themes are groups of settings that can be turned on or off as a group, you can even switch themes in the middle of an Emacs session. For instance, if you’re a consultant working with two clients, you can enable theme client1 in the morning; and then, in the afternoon, disable theme client1 and enable theme client2 to update your settings.

To start with, let’s set up a couple of themes called personal and work, for personal and professional stuff, respectively. Check the value of custom-theme-directory. By default, Emacs looks for themes in the same directory as init.el, but I like to put them in a separate subdirectory, ~/.emacs.d/themes. Customize this to your taste. At any rate, that’s the directory where you’ll be creating theme files. For the rest of this post, I’ll assume that you’re using ~/.emacs.d/themes.

Theme files should go in a file named <theme-name>-theme.el. So create the file ~/.emacs.d/themes/personal-theme.el to hold the personal theme:

(deftheme personal
  "Settings when working on personal projects."
  :family "location")

(custom-theme-set-variables 'personal
 '(user-mail-address "bob@home.org")
 ;; Add additional variables here.
 )

(provide-theme 'loc-personal)

You can now run M-x load-theme personal to load the theme. Theme files contain Emacs Lisp code, which can be a security risk, so the first time you load it, or any time you make any changes, Emacs will ask you to confirm whether to load the theme, and whether to mark it as safe in the future. If you say yes, the next time it’ll just load the theme asking for confirmation.

Follow the same steps to create a work theme.

Once you have something that works reasonably well, you’ll probably want something that loads the right theme when Emacs starts. For this example, we’ll assume that if the hostname is my-laptop, then you’re working on personal things and want to load the personal theme, while if the hostname is office-workstation, then you’re at work and want to load the work theme.

Add something like the following to your ~/.emacs.d/init.el:

(add-hook 'emacs-startup-hook
  (lambda nil
    ;; Figure out which theme to load, depending on which machine this
    ;; is running on, and which options were specified.
    (let ((loc-theme 'unknon)
          )
      (cond
       ;; Running on personal laptop.
       ((string= system-name "my-laptop")
        (setq loc-theme 'personal)
        )

       ;; Running on work machine.
       ((string= system-name "office-workstation")
        (setq loc-theme 'work))

       ;; Add any other locations/work modes here.
       ))

      ;; Check whether the theme exists. If it does, load it.
      (if (member loc-theme (custom-available-themes))
          (progn
            (load-theme loc-theme)
            )
        (warn "Can't find location theme \"%s\"" loc-theme)
        ))))

Here, we’re just looking at the hostname, but obviously the condition can be arbitrarily complex. You might pick different themes depending on the day of the week, or whether you’re ssh-ed in from another host, or whatever makes sense in your situation. Add or remove themes as necessary.

One advantage of doing things this way is separation of information. Maybe you want to make your Emacs setup publicly visible on github, but your work setup includes hostnames or other information that shouldn’t leave company premises. In this case, you can store your work-theme.el file on your company machine, perhaps in a separate directory. You can add an entry to custom-theme-load-path, a directory outside of ~/.emacs.d, so that your work theme doesn’t accidentally get added to the git repo that has your init.el and your publicly-visible themes.

There’s one problem that I haven’t found a good solution to: child themes. Let’s say you have your work theme, with a hundred work-related settings. But of those 100 settings, there are three that change depending on whether you’re logged in to host1 or host2.It would be nice to have a host1 theme that automatically includes everything from the work theme, plus the three settings that are specific to host1. I don’t see a good way of doing this. It might make sense to use literate programming to generate multiple *-theme.el files from one source .org file.

Customizing Pasted Strings in Emacs

(A version of this post was posted earlier, but disappeared. Sorry for any inconvenience.)

The Problem

At my day job, we use the Jira ticketing system, so it’s very useful to link to tickets in Org-mode files, to the point where I’ve defined a shortcut, [[jira:ABC-12345]], and an org capture template for tickets. But sometimes, I’ll copy a link from an email message or something, and C-y to paste it in Emacs, and then I get an ugly

 

https://jira.example.com/ticket/ABC-12345

That got me to wondering if I could rewrite the text before pasting it, and turn that URL into

The Transform Function

We’re going to need a function to do the transformation, so let’s get that out of the way. Here’s a function that takes a string to be yanked from the kill buffer, and returns the string that we actually want. The only thing to note is that I used cond instead of if because I’ll probably want to expand it later, as I find new patterns I want to transform.

(defun my-org-convert-links (str)
  "Given a string to yank, try to convert it to org format."
  ;; Use `cond' rather than `if' to make it easier to add other
  ;; patterns.
  (cond
   ;; Example Jira URL. Extract the ticket number.
   ((string-match
     "^https://jira.example.com/ticket/\\([A-Z]+-[0-9]+\\)$"
     str)
    (let ((ticket (substring str
                             (match-beginning 1)
                             (match-end 1))))
      (format "[[jira:%s][%s]]" ticket ticket)
      ))

   ;; Insert other transformations here. Whatever's useful for you.

   ;; Nothing special. Just return the string.
   (t str))
  )

Hooking into yank

In an ordinary buffer, the Emacs function for pasting is yank, as you can confirm with M-x describe-key C-y, or whatever you’ve bound it to. And if you look up its documentation, you’ll see that it can be customized using yank-transform-functions. This is a list of functions that are called with the string to be yanked. We’ve already written a transform function above, so all we need to do is add it to yank-transform-functions:

(add-to-list 'yank-transform-functions
             #'my-org-convert-links)

In this case, the syntax [[jira:ABC-123456][ABC-123456]] doesn’t make sense outside of Org-Mode buffers, so let’s make it specific to org-mode buffers: we’ll make yank-transform-functions buffer-local, and only add our function to it in Org-Mode buffers:

(add-hook 'org-mode-hook
  (lambda nil
    (make-variable-buffer-local 'yank-transform-functions)
    (add-to-list 'yank-transform-functions
                 #'my-org-convert-links)
    ))

Now, the more astute among you will have noticed that in Org-Mode, C-y is bound to org-yank, which performs other org-specific magic before pasting. Thankfully, it winds up calling the built-in yank, so the customization above still works.

And that’s about it! I can now have Jira links look pretty when I paste them into my Org-Mode notes, and a structure where I can easily add more transformations if and when I want them.

I’ll note that yanking is different from drag-and-drop, and is handled differently from Emacs. I want to set up something similar for that, but that’ll be a story for a different day.

Voluntary Charity

There’s a trope I’ve run across a couple of times in conservative fora, that of voluntary charity, the idea that charitable giving should be a personal decision, not something forced by the state. To quote the Encyclopediat of Conservatism:

Charity is voluntary and personal; state welfare is compulsory and bureaucratic. Conservatives argue the two differ in kind, not merely in scale.

The first argument they give in favor of this position is

First, charity is a school of virtue. Giving that is chosen forms generosity, gratitude, and mutual obligation; taxation that is extracted forms nothing, and a citizen who has outsourced compassion to the state has been morally diminished, not relieved.

A similar sentiment is echoed in this editorial by Ray Nothstine in the Carolina Journal:

The reason [for donors’ generosity]? To model the message of Christmas, which embodies the kind of love that can only be voluntarily received. “Long before there was a government welfare program, this spirit of voluntary giving was ingrained in the American character,” declared former president Ronald Reagan in a 1981 Thanksgiving Proclamation.

and that

That kind of coercive effect [of using taxes to pay for charity] to create a bureaucratic caretaker society is a misguided view of charity. It’s a view that completely eschews virtue of voluntary giving.

In other words, the purpose is to make the giver feel good, or make them a better person. It’s not to improve the lives of the recipients. This feels like a main-character worldview, where other people are NPCs whose role is to help develop your character, not full-fledged human beings who’d like to get on with their lives.

Secondly, I’ve never seen the idea that giving should be voluntary applied to, say, national defense, or law enforcement, courts, agriculture subsidies, etc, even though you could presumably make the same arguments: “A society that merely punishes people by locking them up in jail at taxpayer expense merely creates a culture of criminality. We should voluntarily rehabilitate criminals”. Or how about “When the US switched from a mandatory draft to an all-volunteer military, the quality of our troops increased. So why stop there? Even those who don’t serve can donate money to buy missiles and tanks. Think how great our military would be if everything in it were voluntarily donated!”

Call me cynical, but these two things together make it sound as though “voluntary charity” is more of an excuse not to give to charity. Or to make sure that “the wrong people” don’t get their hands on that sweet, sweet cash.

I can’t speak for anyone else, but I think it makes more sense to focus on the problems, and the people experiencing those problems. If a government program helps ensure that a thousand people have something to eat today, even if they’re people I don’t like, well, that’s still a thousand people who’ll eat today. And if a few dozen of them use their government assistance to buy junk food instead of something nutritious, well, that’s still better than going hungry.

Another aspect of this is that government is a tool for solving problems at scale. In a democracy, we the people get to decide how our country is run, and that includes things like how much money and effort to put into helping other people, and how. Not necessarily through direct election, of course, but by electing people aligned with our views, and telling our elected representatives what the country should be doing and which problems need addressing. No, not everyone in a country will agree with what the government eventually winds up doing. You can’t get a thousand people to agree on anything, let alone three hundred million people. But we can, as a group, agree to work on some problems.

The Encyclopedia of Conservatism largely agrees:

The progressive critique holds that charity, whatever its virtues, fails the test of sufficiency. Voluntary giving is unpredictable, geographically uneven, and procyclical — it collapses in depressions exactly when need peaks, which is why every industrial democracy replaced it. Entitlement, on this view, is a feature: relief that arrives as a right preserves the dignity of the recipient, who need not perform gratitude or pass a benefactor’s moral inspection, while Tocqueville’s stigmatised pauper was precisely the product of discretionary, conditional alms. Social-democratic scholars add a structural point: poverty is produced by labour markets, housing costs, and ill health, not by individual character, so person-by-person moral formation treats symptoms. Empirically, they note that child-poverty rates in high-welfare states run far below those of charity-reliant eras, and that no private network ever matched the coverage of social insurance.

A word about that “pass a benefactor’s moral inspection”: we’ve all seen Gofundmes to pay people’s medical bills. That’s the purest form of voluntary charity, and it’s full of biases. To start with, there’s plain old fashioned racism; campaigns for Black people tend to do less well than ones for other people. They’re also biased in favor of good storytellers, or people who are better at tugging at your heartstrings, not necessarily those who need the most help.

Going back to the matter of scale: the Carolina Journal above lists a few examples of noteworthy voluntary-charity success stories:

Capitol Hill Lutheran Church in Des Moines, Iowa, just announced the forgiveness of $5 million in medical debt as part of an Advent campaign. Church leaders conclude their message by offering a commitment to continue the fundraising initiative.

Financial radio figure Dave Ramsey and his organization Ramsey Solutions recently paid off $10 million in debt for 8,000 people, including a large chunk of medical debt. A simple Google search of Christian churches and medical debt provides a lengthy list of articles detailing aggressive campaigns to pay off medical debts in the amounts of millions.

That’s great, but it’s a drop in the bucket. I’m glad that people were relieved of those $15 million in medical debt. Now what about the other $219,985 million? 1 Are there 10,000 other churches doing the same as Capitol Hill Lutheran and Ramsey Solutions, and are they coordinating their efforts to make sure they’re not stepping on each other’s toes?

Take an example of a large-scale voluntary charity: the American Red Cross. In 2025, it had revenues of almost $4 billion dollars. That same year, the US government spent $8.75 billion on improving health around the world. And another $18 billion for peace, $7 billion on economic development, and $5 billion on humanitarian assistance. Show me a private organization that has that kind of reach.

Back in 2005, when hurricane Katrina devastated New Orleans, lots of people ran drives to collect canned food and blankets for the victims, and the disaster-relief folks on the ground had to explain that they didn’t have the time or manpower to sort through disparate boxes. They enlisted the help of companies like Budweiser and Wal Mart to bring pallets of drinking water and supplies. Companies that had the infrastructure and knowledge to move tons and tons of supplies from point A to point B.

Sure, it feels good to open your wallet and help someone. Or to pay for a stranger’s meal. Or to send blankets and cans of food to earthquake victims. But if we really want to help people rather than make ourselves feel better, the artisanal approach won’t cut it. We need to help on an industrial scale. If there’s a better tool than government for doing this, I don’t know of one.

Footnotes:

1

$220,000 million minus $15 million.

Ansible at Home

Some years ago, I started managing my home machines using Ansible, an effort that continues to this day.

The first thing I did, naturally, was to set up an inventory of machines, organized into various classes, like desktop vs. laptop, operating system family, and the like.

The first mistake I made, as I later found out, was to spend all that time setting up classes. That would have been very useful in a large-scale environment, or even a small company with 30 employees, where you want to say “Set up all the Linux machines this way. Set up all the back-end servers this way”. But at home? Every one of my machines is a one-off, a special snowflake, so there’s very little benefit to be had from trying to group hosts into classes. I wound up making one playbook per host, nothing fancy, and that works just fine.

The big advantage, for me, is that this system provides a record of how my machines are set up, and just as importantly, why. Why did I install Inkscape? Did I just want to noodle with drawing pictures, or was that a prerequisite for some other project I was working on? So if I nuke it, will I miss it later? By the same token, if there’s some package I don’t recognize, I can just nuke it, and Ansible will reinstall it if it turns out to be needed.

I said above that it doesn’t help to organize machines into classes, because each one is a unique snowflake. But as it turns out, there are things I want to do everywhere. Things like Emacs config, or installing the Firefox plugins I want to use.

These are the things that roles are made for. So even though each machine is a unique snowflake, there are parts of their configuration that can be copied, and then you can just use that role in each machine’s playbook.

If you wind up with a lot of common tasks that don’t seem big enough to turn into roles, you can also set up a more traditional common.yml playbook for whichever bits of configuration are shared between hosts.

And finally, the big question is: is it worth it? Well, for me it is. At least, I haven’t given up. Your mileage may vary. I find that it keeps things tidy. If I wonder why something is set up some way, I can look at the Ansible directory and its editing history in git and see what I was thinking at the time. On the down side, there’s extra work involved in making any change.

It’s particularly worth it if you regularly need to make changes, whether it’s because you set up new machines all the time (I have an Ansible config for setting up a new Raspberry Pi). Also, Apple has a habit of overwriting /etc/auto_master with every OS upgrade and breaking my automounts. So being able to just run ansible-playbook= to fix it is very handy.