From a3790776751d1a6365aa0717f509d05adee90734 Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Tue, 5 Aug 2025 18:56:15 -0500 Subject: [PATCH] sherlock: init module Creating a sherlock module for the sherlock launcher. Prefer a file be controlled by a single option and using settings for the main config file. Signed-off-by: Austin Horstman --- .../misc/news/2025/08/2025-08-05_19-14-30.nix | 12 ++ modules/programs/sherlock.nix | 148 +++++++++++++ .../sherlock/basic-configuration.json | 5 + .../programs/sherlock/basic-configuration.nix | 19 ++ .../sherlock/basic-configuration.toml | 3 + .../sherlock/default-configuration.nix | 11 + tests/modules/programs/sherlock/default.nix | 7 + .../programs/sherlock/empty-settings.nix | 18 ++ .../sherlock/full-configuration-aliases.json | 8 + .../sherlock/full-configuration-fallback.json | 114 ++++++++++ .../sherlock/full-configuration-ignore | 5 + .../sherlock/full-configuration-style.css | 8 + .../programs/sherlock/full-configuration.nix | 200 ++++++++++++++++++ .../programs/sherlock/full-configuration.toml | 28 +++ 14 files changed, 586 insertions(+) create mode 100644 modules/misc/news/2025/08/2025-08-05_19-14-30.nix create mode 100644 modules/programs/sherlock.nix create mode 100644 tests/modules/programs/sherlock/basic-configuration.json create mode 100644 tests/modules/programs/sherlock/basic-configuration.nix create mode 100644 tests/modules/programs/sherlock/basic-configuration.toml create mode 100644 tests/modules/programs/sherlock/default-configuration.nix create mode 100644 tests/modules/programs/sherlock/default.nix create mode 100644 tests/modules/programs/sherlock/empty-settings.nix create mode 100644 tests/modules/programs/sherlock/full-configuration-aliases.json create mode 100644 tests/modules/programs/sherlock/full-configuration-fallback.json create mode 100644 tests/modules/programs/sherlock/full-configuration-ignore create mode 100644 tests/modules/programs/sherlock/full-configuration-style.css create mode 100644 tests/modules/programs/sherlock/full-configuration.nix create mode 100644 tests/modules/programs/sherlock/full-configuration.toml diff --git a/modules/misc/news/2025/08/2025-08-05_19-14-30.nix b/modules/misc/news/2025/08/2025-08-05_19-14-30.nix new file mode 100644 index 000000000..44c84f067 --- /dev/null +++ b/modules/misc/news/2025/08/2025-08-05_19-14-30.nix @@ -0,0 +1,12 @@ +{ + time = "2025-08-06T00:14:30+00:00"; + condition = true; + message = '' + A new module is available: 'programs.sherlock'. + + The sherlock module allows configuring Sherlock launcher, a fast and + lightweight application launcher for Linux. You can customize settings, + define custom aliases for web searches, configure fallback launchers, + specify applications to ignore, and apply custom CSS styling. + ''; +} diff --git a/modules/programs/sherlock.nix b/modules/programs/sherlock.nix new file mode 100644 index 000000000..39b09b0b2 --- /dev/null +++ b/modules/programs/sherlock.nix @@ -0,0 +1,148 @@ +{ + lib, + config, + pkgs, + ... +}: +let + inherit (lib) + mkIf + mkEnableOption + mkPackageOption + mkOption + types + ; + + cfg = config.programs.sherlock; + + tomlFormat = pkgs.formats.toml { }; + jsonFormat = pkgs.formats.json { }; +in +{ + meta.maintainers = [ lib.maintainers.khaneliman ]; + + options.programs.sherlock = { + enable = mkEnableOption "sherlock launcher" // { + description = '' + Enable Sherlock, a fast and lightweight application launcher for Wayland. + + See for more information. + ''; + }; + + package = mkPackageOption pkgs "sherlock" { + default = "sherlock-launcher"; + nullable = true; + }; + + settings = mkOption { + inherit (tomlFormat) type; + default = { }; + description = '' + Configuration for Sherlock. + + Written to `config.toml`. + + See for available options. + ''; + example = { + theme = "dark"; + width = 500; + max_results = 8; + }; + }; + + aliases = mkOption { + inherit (jsonFormat) type; + default = { }; + description = '' + Defines custom aliases. + + Written to `sherlock_alias.json`. + + See for more information. + ''; + example = { + "NixOS Wiki" = { + name = "NixOS Wiki"; + icon = "nixos"; + exec = "firefox https://nixos.wiki/index.php?search=%s"; + keywords = "nix wiki docs"; + }; + }; + }; + + ignore = mkOption { + type = types.lines; + default = ""; + description = '' + A list of desktop entry IDs to ignore. + + Written to `sherlockignore`. + + See for more information. + ''; + example = '' + hicolor-icon-theme.desktop + user-dirs.desktop + ''; + }; + + launchers = mkOption { + inherit (jsonFormat) type; + default = [ ]; + description = '' + Defines fallback launchers. + + Written to `fallback.json`. + + See for more information. + ''; + }; + + style = mkOption { + type = types.lines; + default = ""; + description = '' + Custom CSS to style the Sherlock UI. + + Written to `main.css`. + ''; + example = '' + window { + background-color: #2E3440; + } + ''; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + (lib.hm.assertions.assertPlatform "programs.sherlock" pkgs lib.platforms.linux) + ]; + + home.packages = mkIf (cfg.package != null) [ cfg.package ]; + + xdg.configFile = { + "sherlock/config.toml" = mkIf (cfg.settings != { }) { + source = tomlFormat.generate "sherlock-config.toml" cfg.settings; + }; + + "sherlock/sherlock_alias.json" = mkIf (cfg.aliases != { }) { + source = jsonFormat.generate "sherlock_alias.json" cfg.aliases; + }; + + "sherlock/fallback.json" = mkIf (cfg.launchers != [ ]) { + source = jsonFormat.generate "sherlock-fallback.json" cfg.launchers; + }; + + "sherlock/sherlockignore" = mkIf (cfg.ignore != "") { + text = cfg.ignore; + }; + + "sherlock/main.css" = mkIf (cfg.style != "") { + text = cfg.style; + }; + }; + }; +} diff --git a/tests/modules/programs/sherlock/basic-configuration.json b/tests/modules/programs/sherlock/basic-configuration.json new file mode 100644 index 000000000..e179eb2ef --- /dev/null +++ b/tests/modules/programs/sherlock/basic-configuration.json @@ -0,0 +1,5 @@ +{ + "max_results": 8, + "theme": "dark", + "width": 500 +} diff --git a/tests/modules/programs/sherlock/basic-configuration.nix b/tests/modules/programs/sherlock/basic-configuration.nix new file mode 100644 index 000000000..266c393b1 --- /dev/null +++ b/tests/modules/programs/sherlock/basic-configuration.nix @@ -0,0 +1,19 @@ +{ + programs.sherlock = { + enable = true; + settings = { + theme = "dark"; + width = 500; + max_results = 8; + }; + }; + + nmt.script = + let + configFile = "home-files/.config/sherlock/config.toml"; + in + '' + assertFileExists "${configFile}" + assertFileContent "${configFile}" ${./basic-configuration.toml} + ''; +} diff --git a/tests/modules/programs/sherlock/basic-configuration.toml b/tests/modules/programs/sherlock/basic-configuration.toml new file mode 100644 index 000000000..c5f75e067 --- /dev/null +++ b/tests/modules/programs/sherlock/basic-configuration.toml @@ -0,0 +1,3 @@ +max_results = 8 +theme = "dark" +width = 500 diff --git a/tests/modules/programs/sherlock/default-configuration.nix b/tests/modules/programs/sherlock/default-configuration.nix new file mode 100644 index 000000000..c6a9e47b3 --- /dev/null +++ b/tests/modules/programs/sherlock/default-configuration.nix @@ -0,0 +1,11 @@ +{ + programs.sherlock.enable = true; + + nmt.script = '' + assertPathNotExists home-files/.config/sherlock/config.toml + assertPathNotExists home-files/.config/sherlock/sherlock_alias.json + assertPathNotExists home-files/.config/sherlock/fallback.json + assertPathNotExists home-files/.config/sherlock/sherlockignore + assertPathNotExists home-files/.config/sherlock/main.css + ''; +} diff --git a/tests/modules/programs/sherlock/default.nix b/tests/modules/programs/sherlock/default.nix new file mode 100644 index 000000000..766b963e9 --- /dev/null +++ b/tests/modules/programs/sherlock/default.nix @@ -0,0 +1,7 @@ +{ lib, pkgs, ... }: +lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { + sherlock-default-configuration = ./default-configuration.nix; + sherlock-basic-configuration = ./basic-configuration.nix; + sherlock-full-configuration = ./full-configuration.nix; + sherlock-empty-settings = ./empty-settings.nix; +} diff --git a/tests/modules/programs/sherlock/empty-settings.nix b/tests/modules/programs/sherlock/empty-settings.nix new file mode 100644 index 000000000..41654857a --- /dev/null +++ b/tests/modules/programs/sherlock/empty-settings.nix @@ -0,0 +1,18 @@ +{ + programs.sherlock = { + enable = true; + package = null; + }; + + nmt.script = '' + # With null package, no package should be installed + assertPathNotExists home-path/bin/sherlock-launcher + + # With empty settings, no config files should be generated + assertPathNotExists home-files/.config/sherlock/config.toml + assertPathNotExists home-files/.config/sherlock/sherlock_alias.json + assertPathNotExists home-files/.config/sherlock/fallback.json + assertPathNotExists home-files/.config/sherlock/sherlockignore + assertPathNotExists home-files/.config/sherlock/main.css + ''; +} diff --git a/tests/modules/programs/sherlock/full-configuration-aliases.json b/tests/modules/programs/sherlock/full-configuration-aliases.json new file mode 100644 index 000000000..5e6b83468 --- /dev/null +++ b/tests/modules/programs/sherlock/full-configuration-aliases.json @@ -0,0 +1,8 @@ +{ + "DuckDuckGo": { + "exec": "firefox https://duckduckgo.com/?q=%s", + "icon": "duckduckgo", + "keywords": "search web ddg", + "name": "DuckDuckGo" + } +} diff --git a/tests/modules/programs/sherlock/full-configuration-fallback.json b/tests/modules/programs/sherlock/full-configuration-fallback.json new file mode 100644 index 000000000..f9a846c2e --- /dev/null +++ b/tests/modules/programs/sherlock/full-configuration-fallback.json @@ -0,0 +1,114 @@ +[ + { + "args": { + "location": "Appleton", + "update_interval": 60 + }, + "async": true, + "home": "OnlyHome", + "name": "Weather", + "priority": 1, + "shortcut": false, + "spawn_focus": false, + "type": "weather" + }, + { + "alias": "app", + "args": {}, + "home": "Home", + "name": "App Launcher", + "priority": 2, + "type": "app_launcher" + }, + { + "alias": "ddg", + "args": { + "icon": "duckduckgo", + "search_engine": "duckduckgo" + }, + "display_name": "DuckDuckGo Search", + "name": "Web Search", + "priority": 100, + "tag_end": "{keyword}", + "tag_start": "{keyword}", + "type": "web_launcher" + }, + { + "args": { + "capabilities": [ + "calc.math", + "calc.units" + ] + }, + "name": "Calculator", + "priority": 1, + "type": "calculation" + }, + { + "args": { + "capabilities": [ + "url", + "colors.all", + "calc.math", + "calc.units" + ] + }, + "home": "Home", + "name": "Clipboard", + "priority": 1, + "type": "clipboard-execution" + }, + { + "alias": "nix", + "args": { + "commands": { + "Nix Search TV": { + "exec": "kitty -e nix-search-tv", + "icon": "nix-snowflake", + "search_string": "interactive;search;tv" + }, + "NixOS Wiki": { + "exec": "firefox https://wiki.nixos.org/w/index.php?search={keyword}", + "icon": "nix-snowflake", + "search_string": "wiki;docs;documentation", + "tag_end": "", + "tag_start": "wiki:" + }, + "Search Options": { + "exec": "firefox https://search.nixos.org/options?query={keyword}", + "icon": "nix-snowflake", + "search_string": "options;config;nixos", + "tag_end": "", + "tag_start": "options:" + }, + "Search Packages": { + "exec": "firefox https://search.nixos.org/packages?query={keyword}", + "icon": "nix-snowflake", + "search_string": "packages;search;nixpkgs", + "tag_end": "", + "tag_start": "search:" + } + } + }, + "name": "Nix Commands", + "priority": 5, + "type": "command" + }, + { + "args": { + "default_skin_tone": "Simpsons" + }, + "home": "Search", + "name": "Emoji Picker", + "priority": 4, + "type": "emoji_picker" + }, + { + "alias": "kill", + "args": {}, + "home": "Search", + "name": "Kill Process", + "priority": 6, + "type": "process" + } +] diff --git a/tests/modules/programs/sherlock/full-configuration-ignore b/tests/modules/programs/sherlock/full-configuration-ignore new file mode 100644 index 000000000..d8e084b75 --- /dev/null +++ b/tests/modules/programs/sherlock/full-configuration-ignore @@ -0,0 +1,5 @@ +hicolor-icon-theme.desktop +user-dirs.desktop +mimeinfo.cache.desktop +org.freedesktop.IBus.Setup.desktop +ca.desrt.dconf-editor.desktop diff --git a/tests/modules/programs/sherlock/full-configuration-style.css b/tests/modules/programs/sherlock/full-configuration-style.css new file mode 100644 index 000000000..a473d196f --- /dev/null +++ b/tests/modules/programs/sherlock/full-configuration-style.css @@ -0,0 +1,8 @@ +window { + background-color: #2E3440; + border-radius: 8px; +} +entry { + background-color: #3B4252; + color: #ECEFF4; +} diff --git a/tests/modules/programs/sherlock/full-configuration.nix b/tests/modules/programs/sherlock/full-configuration.nix new file mode 100644 index 000000000..c623f6a95 --- /dev/null +++ b/tests/modules/programs/sherlock/full-configuration.nix @@ -0,0 +1,200 @@ +{ + programs.sherlock = { + enable = true; + + settings = { + appearance = { + width = 1000; + height = 600; + gsk_renderer = "cairo"; + icon_size = 32; + opacity = 0.95; + }; + + caching = { + enable = true; + }; + + default_apps = { + browser = "firefox"; + calendar_client = "thunderbird"; + teams = "teams-for-linux --enable-features=UseOzonePlatform --ozone-platform=wayland --url {meeting_url}"; + terminal = "kitty"; + }; + + search_bar_icon = { + enable = true; + }; + + status_bar.enable = true; + + units = { + lengths = "feet"; + weights = "lb"; + volumes = "oz"; + temperatures = "F"; + currency = "usd"; + }; + }; + + launchers = [ + { + name = "Weather"; + type = "weather"; + args = { + location = "Appleton"; + update_interval = 60; + }; + priority = 1; + home = "OnlyHome"; + async = true; + shortcut = false; + spawn_focus = false; + } + { + name = "App Launcher"; + alias = "app"; + type = "app_launcher"; + args = { }; + priority = 2; + home = "Home"; + } + { + name = "Web Search"; + display_name = "DuckDuckGo Search"; + alias = "ddg"; + type = "web_launcher"; + tag_start = "{keyword}"; + tag_end = "{keyword}"; + args = { + search_engine = "duckduckgo"; + icon = "duckduckgo"; + }; + priority = 100; + } + { + name = "Calculator"; + type = "calculation"; + args = { + capabilities = [ + "calc.math" + "calc.units" + ]; + }; + priority = 1; + } + { + name = "Clipboard"; + type = "clipboard-execution"; + args = { + capabilities = [ + "url" + "colors.all" + "calc.math" + "calc.units" + ]; + }; + priority = 1; + home = "Home"; + } + { + name = "Nix Commands"; + alias = "nix"; + type = "command"; + args = { + commands = { + "Search Packages" = { + icon = "nix-snowflake"; + exec = "firefox https://search.nixos.org/packages?query={keyword}"; + search_string = "packages;search;nixpkgs"; + tag_start = "search:"; + tag_end = ""; + }; + "Search Options" = { + icon = "nix-snowflake"; + exec = "firefox https://search.nixos.org/options?query={keyword}"; + search_string = "options;config;nixos"; + tag_start = "options:"; + tag_end = ""; + }; + "NixOS Wiki" = { + icon = "nix-snowflake"; + exec = "firefox https://wiki.nixos.org/w/index.php?search={keyword}"; + search_string = "wiki;docs;documentation"; + tag_start = "wiki:"; + tag_end = ""; + }; + "Nix Search TV" = { + icon = "nix-snowflake"; + exec = "kitty -e nix-search-tv"; + search_string = "interactive;search;tv"; + }; + }; + }; + priority = 5; + } + { + name = "Emoji Picker"; + type = "emoji_picker"; + args = { + default_skin_tone = "Simpsons"; + }; + priority = 4; + home = "Search"; + } + { + name = "Kill Process"; + alias = "kill"; + type = "process"; + args = { }; + priority = 6; + home = "Search"; + } + ]; + + aliases = { + "DuckDuckGo" = { + name = "DuckDuckGo"; + icon = "duckduckgo"; + exec = "firefox https://duckduckgo.com/?q=%s"; + keywords = "search web ddg"; + }; + }; + + ignore = '' + hicolor-icon-theme.desktop + user-dirs.desktop + mimeinfo.cache.desktop + org.freedesktop.IBus.Setup.desktop + ca.desrt.dconf-editor.desktop + ''; + + style = '' + window { + background-color: #2E3440; + border-radius: 8px; + } + entry { + background-color: #3B4252; + color: #ECEFF4; + } + ''; + }; + + nmt.script = '' + assertFileExists home-files/.config/sherlock/config.toml + assertFileContent home-files/.config/sherlock/config.toml ${./full-configuration.toml} + + assertFileExists home-files/.config/sherlock/sherlock_alias.json + assertFileContent home-files/.config/sherlock/sherlock_alias.json ${./full-configuration-aliases.json} + + assertFileExists home-files/.config/sherlock/fallback.json + assertFileContent home-files/.config/sherlock/fallback.json ${./full-configuration-fallback.json} + + assertFileExists home-files/.config/sherlock/sherlockignore + assertFileContent home-files/.config/sherlock/sherlockignore ${./full-configuration-ignore} + + assertFileExists home-files/.config/sherlock/main.css + assertFileContent home-files/.config/sherlock/main.css ${./full-configuration-style.css} + ''; +} diff --git a/tests/modules/programs/sherlock/full-configuration.toml b/tests/modules/programs/sherlock/full-configuration.toml new file mode 100644 index 000000000..835179be0 --- /dev/null +++ b/tests/modules/programs/sherlock/full-configuration.toml @@ -0,0 +1,28 @@ +[appearance] +gsk_renderer = "cairo" +height = 600 +icon_size = 32 +opacity = 0.95 +width = 1000 + +[caching] +enable = true + +[default_apps] +browser = "firefox" +calendar_client = "thunderbird" +teams = "teams-for-linux --enable-features=UseOzonePlatform --ozone-platform=wayland --url {meeting_url}" +terminal = "kitty" + +[search_bar_icon] +enable = true + +[status_bar] +enable = true + +[units] +currency = "usd" +lengths = "feet" +temperatures = "F" +volumes = "oz" +weights = "lb"