Skip to content

Instantly share code, notes, and snippets.

@ibizaman
Created June 18, 2026 16:15
Show Gist options
  • Select an option

  • Save ibizaman/b55f4b71fcec5448f7a8d195ca272c16 to your computer and use it in GitHub Desktop.

Select an option

Save ibizaman/b55f4b71fcec5448f7a8d195ca272c16 to your computer and use it in GitHub Desktop.
KDE services home-manager NixOS module
{
home-manager.users.${user} = {
imports = [
../../modules/kde-serviceMenus.nix
];
me.kde.serviceMenus."FFmpeg" = {
mimeTypes = [ "video/*" ];
actions = {
"remove-sound" = {
name = "Remove Sound";
icon = "audio-off";
cmd = ''
output="''${1%.*}.nosound.''${1##*.}"
${pkgs.ffmpeg}/bin/ffmpeg \
-i "$file" \
-c copy \
-an \
"$output"
'';
};
};
};
};
}
{
config,
lib,
pkgs,
...
}:
let
cfg = config.me.kde;
mkBin =
name:
{
runtimeInputs,
cmd,
...
}:
pkgs.writeShellApplication {
inherit name runtimeInputs;
text = ''
cmd() {
${cmd}
}
for file in "$@"; do
logfile=$(mktemp)
if cmd "$file" >"$logfile" 2>&1; then
${pkgs.kdePackages.kdialog}/bin/kdialog \
--passivepopup "Finished ${name}" 3
else
${pkgs.kdePackages.konsole}/bin/konsole \
--hold \
-e ${pkgs.bash}/bin/bash -c "
cat '$logfile'
echo
echo 'Press Enter to close'
read
"
fi
rm -f "$logfile"
done
'';
};
mkAction =
name: cfg':
lib.nameValuePair name {
inherit (cfg') name icon;
exec = "${lib.getExe (mkBin name cfg')} %F";
};
mkMenu =
name: cfg':
lib.nameValuePair ".local/share/kio/servicemenus/${name}.desktop" {
source = (pkgs.makeDesktopItem {
inherit name;
inherit (cfg') mimeTypes;
desktopName = cfg'.name;
type = "Application";
extraConfig.X-KDE-Submenu = cfg'.name;
actions = lib.mapAttrs' mkAction cfg'.actions;
}) + "/share/applications/${name}.desktop";
};
in
{
options.me.kde = {
serviceMenus = lib.mkOption {
description = ''
Create KDE service menus.
See https://develop.kde.org/docs/apps/dolphin/service-menus/
'';
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
example = "Convert video";
};
mimeTypes = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
description = ''
If not null, only show the action on the given mime types.
Inspect a file with:
nix shell nixpkgs#file.out -c file --mime-type movie.mkv
List of mime types on:
find /run/current-system/sw/share/mime -name '*.xml'
'';
};
actions = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
example = "Convert video";
};
submenu = lib.mkOption {
type = lib.types.str;
};
cmd = lib.mkOption {
type = lib.types.str;
description = "A bash command that receives a filename as local variable $file";
};
runtimeInputs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
icon = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = ''
Names come from:
nix shell nixpkgs#kdePackages.kdialog.out -c kdialog --geticon
'';
};
};
}
)
);
};
};
}
)
);
};
};
config = {
home.packages = lib.flatten (
lib.mapAttrsToList (n: { actions, ... }: lib.mapAttrsToList mkBin actions) cfg.serviceMenus
);
home.file = lib.mapAttrs' mkMenu cfg.serviceMenus;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment