❀✿❀ SuperLaserNino ✿❀✿

Make Neovim respect your macOS appearance settings

7 January 2025

365 words

[It turns out they’re working on native support for this feature, but it looks like my approach might be more flexible, so I decided to post this anyway.]

When I discovered that Ghostty can change its colours based on the system light/dark mode settings, I was curious whether I could achieve the same effect in Neovim. It turns out, it’s possible! (You don’t need to use Ghostty for this to work, that was just my inspiration to figure this out.)

This code only works on macOS, but I’m sure you could get an AI to translate it to work on Windows or Linux:

function CheckAppearance()
  local theme = vim.fn.system('defaults read -g AppleInterfaceStyle'):gsub('\n', '')
  if theme == 'Dark' then
    vim.o.background = 'dark'
    vim.cmd('colorscheme modus_vivendi')
    vim.cmd [[ hi DiffText cterm=bold gui=bold ctermbg=225 guibg=DarkRed ]]
    -- For some reason the RenderMarkdown plugin doesn't pick up the changes
    -- when run through an autocmd
    vim.cmd [[ hi RenderMarkdown_bgtofg_RenderMarkdownCode guifg=#1e1e1e ]]
  else
    vim.o.background = 'light'
    -- These are my settings, but you can go wild and put whatever you want
    vim.cmd('colorscheme modus_operandi')
    vim.cmd [[ hi DiffText cterm=bold gui=bold ctermbg=225 guibg=LightRed ]]
    -- For some reason the RenderMarkdown plugin doesn't pick up the changes
    -- when run through an autocmd
    vim.cmd [[ hi RenderMarkdown_bgtofg_RenderMarkdownCode guifg=#f2f2f2 ]]
  end
end

-- Run on startup
CheckAppearance()

So far, it’ll just check the appearance setting when you start Neovim. There are a few ways to get it to dynamically detect changes to the setting:

Manually. Just create a user command and run it manually (ugh):

vim.api.nvim_create_user_command('CheckAppearance', function()
  CheckAppearance()
end, {})

On focus gained. This is what I’m using – Neovim will check the appearance whenever you activate it. This means it won’t switch immediately with the system, but it’ll always match when you’re actually using Neovim:

vim.api.nvim_create_autocmd("FocusGained", {
  callback = function()
    CheckAppearance()
  end,
})

Note: Some plugins might not pick up the changes properly, so you might have to add extra stuff in the CheckAppearance function, like that RenderMarkdown_bgtofg_RenderMarkdownCode highlight rule.

Here’s what it looks like in the end:

Don’t manually hunt around for yarn.lock or package-lock.json

27 August 2024

153 words

#!/usr/bin/env perl

# Node dependency manager. Never wonder whether to use `yarn` or `npm` again.

# Usage:
# np        --> runs `yarn` or `npm i`
# np <args> --> runs `yarn <args>` or `npm run <args>`

use strict;
use warnings;

if (!-e 'package.json') {
  my $did_run = 0;
  my @dirs = grep { -d $_ } glob('*');
  for my $dir (@dirs) {
    $did_run = 1;
    chdir($dir);
    if (-e 'package.json') {
      print "Running `np` in $dir\n";
      my $exit_code = system('np ' . join(' ', @ARGV));
      exit($exit_code >> 8) if $exit_code != 0;
    }
    chdir('..');
  }

  if ($did_run == 0) {
    print "No package.json found. Exiting.\n";
    exit(1);
  }
  exit(0);
}

my $exit_code;
if (-e 'package-lock.json') {
  if (@ARGV) {
    $exit_code = system('npm run ' . join(' ', @ARGV));
  } else {
    $exit_code = system('npm i');
  }
} else {
  $exit_code = system('yarn ' . join(' ', @ARGV));
}

exit($exit_code >> 8);

Catio Chronicles 1: Let’s make a plan

18 August 2024

745 words

Our cat Jinx keeps getting sick and vomiting, and the vets are saying this is most likely because young cats like to eat random stuff outside. We really don’t want to restrict Jinx to being an indoor cat, so we decided we would build him a little outside enclosure, a “catio”.

Since this will be a big undertaking, we need to figure out what we want to achieve with the catio, and make a plan. These are some hard requirements:

And we also have some things that would be nice to have:

The basic plan we started out with looked like this:

We would then add mesh to the top, the slanted area, the right side (against the brick wall), and the side facing the viewer. The walls of our flat should ideally not get any mesh, so Jinx can get in and out through the windows.

Buuuuut there are a bunch of pipes running along the walls, so the frame needs to somehow go around them.

My sister came up with the idea of putting the frame far enough away from the walls to avoid the pipes, and then fill the gaps with flat wooden panels (highlighted in red):

I discussed the plans with my dad (who had built us a tree-house when we were young, so I figured he might know stuff). His advice was:


If you know me in real life, you may be wondering: Didn’t I start this whole project like 8 million years ago? Why did it take me so long to write this post?

Well, I’ve been sitting on this unfinished draft since June, planning to have the following be the end of the article:

The final design looks like this:

%% Better design %%

In the next episode, we'll look at finding materials and starting to build stuff!

But it turned out, making a nice archviz-y render of the catio never felt quite worth it. We used Blender to solve many of the design problems – and it was really helpful for that purpose – but once we’d figured out the general idea, it felt really tedious to painstakingly attach every single bracket and make sure all the beams line up right, etc. Also, whenever I started finessing the scene, I’d hit some new design issue that we needed to solve, and that would mean more changes to the design, so, the more high-fidelity the model, the more stuff I’d need to change every time.

The main takeaway for this episode is:

  1. This is an exciting project.
  2. It was absolutely the right choice to plan this project in 3D. I tried a few sketches on paper and I kept getting hopelessly lost.
  3. I’d wished for a nice photoreal render at the end, but this would have required a lot more time investment. And if I’m gonna be spending time making “art” in Blender, I’d rather it be spaceships instead of wooden frames with mesh.

Anyway, here are some screenshots of the design as it currently exists:

I hesitate to call it “finished”, since a bunch of stuff might still change, and we’ve probably already deviated from this plan anyway in real life.

Next time, we’ll look at the materials we got, and the beginning of the construction process.

Finally you can remember whether the lift will ding once or twice

18 August 2024

80 words

Elevators Lifts have this cool accessibility feature where, depending on whether they’re going up or down, they’ll ding once or twice when they arrive. This is so you know the direction without having to look at the display above the doors.

I’ve finally come up with a mnemonic for remembering which is which:

🤯

Thoughts on Texts (a multi-platform instant messaging app)

5 June 2024

1004 words

Having a handful of different instant messaging clients on your computer is inconvenient. There is Ferdi Ferdium, but that’s basically just a browser with a tab for each service. I want something like Adium: an app that transparently talks to all your IM services, so you don’t have to think about it.

For years this seemed to be impossible, but recently I heard about Texts, and decided to give it a go.

My first thoughts were:

Setup and first impressions

The setup was relatively smooth. Adding accounts worked fine. The UI is pretty ok.

There are some nice settings:

The UI is pretty nice and feels almost like a normal app, except for the very modern-web-app-feeling tooltips:

A tooltip for a magnifying-glass icon. The tooltip says “Command Bar: Search Threads”.

I may be the only person on Earth with this opinion, but I do actually like the native tooltips you get on macOS (and, I assume, Windows and Linux), that only show up after you point your mouse at a thing for a second, and look a bit more subtle.

The app has a bunch of other interesting features like automatic reminders, labels, undo for sending messages (via a delay), etc. Also there are keyboard shortcuts for everything and you can change the app icon to whatever you like.

The notification settings seem reasonable too:

Text’s notification settings. Items are:
	A toggle for “Message notifications”. A dropdown for “Sound”. A toggle for “Group message notifications”. Another dropdown for “Sound”. A toggle for “Notify when app is in focus”. A toggle for “Notify when someone reacts to a message”. A toggle for “Notify when someone starts typing (supported platforms only)”. A dropdown for “Delay notifications for x seconds”, with explanation “Instead of getting notified for each message, delay and batch notifications for successive texts from someone”. There are also buttons “Open Notifications in System Preferences” and “Restart Notification Center”.

Glitches

When first setting up my accounts, the unread counter badge in the Dock icon was stuck on 1, but that eventually resolved itself.

Compatibility

So the app seems nice and things broadly work. But how well does Texts support all the custom features of the various IM services?

Replies

Yep:

Screenshot of a chat conversation (with all the text blurred).
        The first item is a turquoise bubble containing a white box with a quoted message from Nino. The bottom half of the turquoise bubble contains the reply to Nino's message. Below the bubble is a button titled “Show reply”.
        Next is a right-aligned blue bubble, also containing a white box with a quoted message and some response text.

This is Telegram, but it seems to work just as well with Messenger. Also, the original message gets a “Show reply” button and a “Show All Replies” button. “Show All Replies” opens a little popup with all replies to that particular message. (Would be nice if the UI team could make up their minds on whether they want sentence case or title case for their button labels tho.)

Forwarded messages

Nope. At least in Telegram, forwarded messages just show up as regular messages. This can be confusing, but people in my circles mostly use forwarding to quickly send a message to multiple people (i.e., send long message to person A, then forward to person B, C, etc.). In that case, it doesn’t matter that it’s not marked.

Stickers

The Telegram integration even gives you an extra button for stickers.

Reactions

Working totally fine in Telegram and Messenger (haven’t checked others), but the emoji picker looks a bit odd:

Screenshot of a reaction-emoji-picker like you'd see in most chat apps, but a random subset of the emoji are rendered as unsettling black-and-white line drawings instead of full-color pictures.

Spoilers

Yep. Text marked as a spoiler/redacted works with Telegram. You can click to reveal it.

Resource usage

CPU usage seems ok, but it uses 1 GB of RAM. But then again, what doesn’t, these days? My browser uses 5½ GB.

Pricing

Texts is free for up to 10 accounts, and £12 per month if you have more. This seems fair. I don’t have 10 accounts in the app, so I’m using the free tier. But, assuming I don’t find any big issues, I’d absolutely be willing to pay £12 per month for an app like this.

Conclusion

Using Texts really does revive some of that Adium feeling from the early 2000s. I’ll keep using it for now and see how it goes.