feat(pkgs/Profpatsch/alacritty): init dark mode dbus daemon

A simple dbus daemon that writes the alacritty config to
`~/.config/alacritty/alacritty-colors-autogen.toml` on startup and
whenever a change between dark/light mode is requested.

Alacritty only implements an config file isync watcher, no SIGHUP
handler or similar, so we have to actually write the config file lol.

This is all a little glue-y, but idk, whatever.

Further reading & inspo:

https://github.com/alacritty/alacritty/issues/5999
https://www.christianfosli.com/posts/2024-on-colorscheme-changed/
https://github.com/christianfosli/on-colorscheme-changed

Change-Id: Iac4eb9d85679dc87e28e57d68384645b3b91d08a
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12870
Tested-by: BuildkiteCI
Reviewed-by: Profpatsch <mail@profpatsch.de>
This commit is contained in:
Profpatsch 2024-12-05 19:11:34 +01:00
parent 22c46c8009
commit 6477428c36
9 changed files with 464 additions and 7 deletions

View file

@ -0,0 +1,2 @@
/node_modules/
/result

View file

@ -0,0 +1,136 @@
// Step 3: Create the script
const dbus = require('dbus-native');
const fs = require('fs');
const assert = require('assert');
const programName = process.argv[1];
let themeDir = process.argv[2];
// read the dark alacritty theme file as first argument
let darkThemeName = process.argv[3] ?? 'alacritty_0_12';
// read the light alacritty theme file as second argument
let lightThemeName = process.argv[4] ?? 'dayfox';
assert(themeDir, 'Theme directory is required');
const darkTheme = getThemePathSync(darkThemeName);
const lightTheme = getThemePathSync(lightThemeName);
console.log(`Dark theme: ${darkTheme}`);
console.log(`Light theme: ${lightTheme}`);
// Connect to the user session bus
const bus = dbus.sessionBus();
// set XDG_CONFIG_HOME if it's not set
if (!process.env.XDG_CONFIG_HOME) {
process.env.XDG_CONFIG_HOME = process.env.HOME + '/.config';
}
function getThemePathSync(theme) {
const path = `${themeDir}/${theme}.toml`;
const absolutePath = fs.realpathSync(path);
assert(fs.existsSync(absolutePath), `Theme file not found: ${absolutePath}`);
return absolutePath;
}
// write new color scheme
function writeAlacrittyColorConfig(cs, theme) {
console.log(`Writing color scheme ${cs} with theme ${theme}`);
fs.writeFileSync(
process.env.XDG_CONFIG_HOME + '/alacritty/alacritty-colors-autogen.toml',
`# !! THIS FILE IS GENERATED BY ${programName}
general.import = ["${theme}"]`,
'utf8',
);
}
// get the current value of the color scheme from dbus
function getColorScheme() {
return new Promise((resolve, reject) => {
bus
.getService('org.freedesktop.portal.Desktop')
.getInterface(
'/org/freedesktop/portal/desktop',
'org.freedesktop.portal.Settings',
(err, iface) => {
if (err) {
reject(`error getting interface: ${err}`);
return;
}
iface.ReadOne(
'org.gnome.desktop.interface',
'color-scheme',
(err, [_, [value]]) => {
if (err) {
reject(err);
return;
}
resolve(value);
},
);
},
);
});
}
// Define the callback function
function onColorSchemeChanged(cs) {
// only change the color scheme if it's different from the previous one
let previous = null;
if (previous === cs) {
console.log(`Color scheme already set to ${cs}`);
return;
}
previous = cs;
console.log(`Color scheme changed to ${cs}`);
writeAlacrittyColorConfig(cs, cs === 'prefer-dark' ? darkTheme : lightTheme);
}
function listenForColorschemeChange() {
return new Promise((resolve, reject) => {
bus
.getService('org.freedesktop.portal.Desktop')
.getInterface(
'/org/freedesktop/portal/desktop',
'org.freedesktop.portal.Settings',
(err, iface) => {
if (err) {
reject(`error getting interface: ${err}`);
}
// Listen for SettingChanged signals
iface.on('SettingChanged', (interfaceName, key, [_, [newValue]]) => {
if (
interfaceName === 'org.gnome.desktop.interface' &&
key == 'color-scheme'
) {
onColorSchemeChanged(newValue);
}
});
console.log('Listening for color scheme changes...');
},
);
});
}
async function main() {
// get the current color scheme
const currentColorScheme = await getColorScheme();
console.log(`Current color scheme: ${currentColorScheme}`);
// write the color scheme
writeAlacrittyColorConfig(
currentColorScheme,
currentColorScheme === 'prefer-dark' ? darkTheme : lightTheme,
);
// listen for color scheme changes
await listenForColorschemeChange();
}
main().catch(err => {
console.error(err);
});

View file

@ -0,0 +1,3 @@
{ depot, pkgs, ... }:
depot.users.Profpatsch.napalm.buildPackage ./. { }

View file

@ -0,0 +1,250 @@
{
"name": "alacritty-change-color-scheme",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "alacritty-change-color-scheme",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"dbus-native": "^0.4.0"
}
},
"node_modules/abstract-socket": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/abstract-socket/-/abstract-socket-2.1.1.tgz",
"integrity": "sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"dependencies": {
"bindings": "^1.2.1",
"nan": "^2.12.1"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"license": "MIT",
"optional": true,
"dependencies": {
"file-uri-to-path": "1.0.0"
}
},
"node_modules/dbus-native": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/dbus-native/-/dbus-native-0.4.0.tgz",
"integrity": "sha512-i3zvY3tdPEOaMgmK4riwupjDYRJ53rcE1Kj8rAgnLOFmBd0DekUih59qv8v+Oyils/U9p+s4sSsaBzHWLztI+Q==",
"license": "MIT",
"dependencies": {
"event-stream": "^4.0.0",
"hexy": "^0.2.10",
"long": "^4.0.0",
"optimist": "^0.6.1",
"put": "0.0.6",
"safe-buffer": "^5.1.1",
"xml2js": "^0.4.17"
},
"bin": {
"dbus2js": "bin/dbus2js.js"
},
"optionalDependencies": {
"abstract-socket": "^2.0.0"
}
},
"node_modules/duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"license": "MIT"
},
"node_modules/event-stream": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz",
"integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==",
"license": "MIT",
"dependencies": {
"duplexer": "^0.1.1",
"from": "^0.1.7",
"map-stream": "0.0.7",
"pause-stream": "^0.0.11",
"split": "^1.0.1",
"stream-combiner": "^0.2.2",
"through": "^2.3.8"
}
},
"node_modules/file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"license": "MIT",
"optional": true
},
"node_modules/from": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
"integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
"license": "MIT"
},
"node_modules/hexy": {
"version": "0.2.11",
"resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz",
"integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==",
"license": "MIT",
"bin": {
"hexy": "bin/hexy_cmd.js"
}
},
"node_modules/long": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
"license": "Apache-2.0"
},
"node_modules/map-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
"integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==",
"license": "MIT"
},
"node_modules/minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==",
"license": "MIT"
},
"node_modules/nan": {
"version": "2.22.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz",
"integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==",
"license": "MIT",
"optional": true
},
"node_modules/optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==",
"license": "MIT/X11",
"dependencies": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
}
},
"node_modules/pause-stream": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
"integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
"license": [
"MIT",
"Apache2"
],
"dependencies": {
"through": "~2.3"
}
},
"node_modules/put": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz",
"integrity": "sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==",
"license": "MIT/X11",
"engines": {
"node": ">=0.3.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"license": "ISC"
},
"node_modules/split": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
"integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
"license": "MIT",
"dependencies": {
"through": "2"
},
"engines": {
"node": "*"
}
},
"node_modules/stream-combiner": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
"integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==",
"license": "MIT",
"dependencies": {
"duplexer": "~0.1.1",
"through": "~2.3.4"
}
},
"node_modules/through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"license": "MIT"
},
"node_modules/wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"license": "MIT",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"license": "MIT",
"engines": {
"node": ">=4.0"
}
}
}
}

View file

@ -0,0 +1,15 @@
{
"name": "alacritty-change-color-scheme",
"version": "1.0.0",
"main": "alacritty-change-color-scheme.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": "alacritty-change-color-scheme.js",
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"dbus-native": "^0.4.0"
}
}

View file

@ -3,25 +3,53 @@
let
bins = depot.nix.getBins pkgs.alacritty [ "alacritty" ];
# https://github.com/alacritty/alacritty-theme
themes = {
# dark = "alacritty_0_12";
dark = "google";
light = "dayfox";
};
config =
{
alacritty-config = { font.size = 18; scrolling.history = 100000; };
config = {
# sets the theme for this config (autogenerated file)
general.import = [ "~/.config/alacritty/alacritty-colors-autogen.toml" ];
font.size = 18;
scrolling.history = 100000;
};
# This disables the dpi-sensitive scaling (cause otherwise the font will be humongous on my laptop screen)
alacritty-env.WINIT_X11_SCALE_FACTOR = 1;
};
config-file = (pkgs.formats.toml { }).generate "alacritty.conf" config.alacritty-config;
alacritty = depot.nix.writeExecline "alacritty" { } (
(lib.concatLists (lib.mapAttrsToList (k: v: [ "export" k (toString v) ]) config.alacritty-env))
++ [
"backtick"
"-E"
"config"
[ depot.users.Profpatsch.xdg-config-home ]
bins.alacritty
"--config-file"
config-file
((pkgs.formats.toml { }).generate "alacritty.conf" config.config)
"$@"
]
);
alacritty-themes = pkgs.fetchFromGitHub {
owner = "alacritty";
repo = "alacritty-theme";
rev = "95a7d695605863ede5b7430eb80d9e80f5f504bc";
sha256 = "sha256-D37MQtNS20ESny5UhW1u6ELo9czP4l+q0S8neH7Wdbc=";
};
in
{
inherit
alacritty
alacritty-themes
themes;
}

View file

@ -0,0 +1,9 @@
{ pkgs, ... }:
import
(builtins.fetchGit {
url = "https://github.com/nix-community/napalm";
rev = "e1babff744cd278b56abe8478008b4a9e23036cf";
})
{
inherit pkgs;
}

View file

@ -186,7 +186,7 @@ let
([
{
name = "bin/terminal-emulator";
path = depot.users.Profpatsch.alacritty;
path = depot.users.Profpatsch.alacritty.alacritty;
}
]);

View file

@ -0,0 +1,14 @@
{ depot, pkgs, lib, ... }:
depot.nix.writeExecline "xdg-config-home" { } [
"if"
"-n"
[
"printenv"
"XDG_CONFIG_HOME"
]
"importas"
"HOME"
"HOME"
"echo"
"\${HOME}/.config"
]