diff --git a/modules/misc/news.nix b/modules/misc/news.nix index 6319d6353..22a9a86c0 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1618,6 +1618,16 @@ in { https://github.com/fastfetch-cli/fastfetch for more. ''; } + + { + time = "2024-05-09T15:12:32+00:00"; + message = '' + A new module is available: 'programs.silicon'. + Silicon is an alternative to Carbon implemented in Rust, + it can render your source code into a beautiful image. + See https://github.com/Aloxaf/silicon for more. + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index 22664091c..71058c185 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -213,6 +213,7 @@ let ./programs/script-directory.nix ./programs/senpai.nix ./programs/sftpman.nix + ./programs/silicon.nix ./programs/sioyek.nix ./programs/skim.nix ./programs/sm64ex.nix diff --git a/modules/programs/silicon.nix b/modules/programs/silicon.nix new file mode 100644 index 000000000..f09f217ae --- /dev/null +++ b/modules/programs/silicon.nix @@ -0,0 +1,131 @@ +{ pkgs, lib, config, ... }: + +with lib; + +let cfg = config.programs.silicon; +in { + meta.maintainers = with hm.maintainers; [ afresquet ]; + + options.programs.silicon = { + enable = + mkEnableOption "silicon, create beautiful image of your source code"; + + package = mkPackageOption pkgs "silicon" { }; + + settings = mkOption { + type = types.str; + default = ""; + example = literalExpression '' + --shadow-color '#555' + --background '#fff' + --shadow-blur-radius 30 + --no-window-controls + ''; + description = '' + Silicon configuration. + ''; + }; + + themes = mkOption { + type = types.attrsOf (types.submodule { + options = { + src = mkOption { + type = types.path; + description = "Path to the theme folder."; + }; + + file = mkOption { + type = types.nullOr types.str; + default = null; + description = + "Subpath of the theme file within the source, if needed."; + }; + }; + }); + default = { }; + example = literalExpression '' + { + dracula = { + src = pkgs.fetchFromGitHub { + owner = "dracula"; + repo = "sublime"; # Silicon uses sublime syntax for its themes + rev = "26c57ec282abcaa76e57e055f38432bd827ac34e"; + sha256 = "019hfl4zbn4vm4154hh3bwk6hm7bdxbr1hdww83nabxwjn99ndhv"; + }; + file = "Dracula.tmTheme"; + }; + } + ''; + description = '' + Additional themes to provide. + ''; + }; + + syntaxes = mkOption { + type = types.attrsOf (types.submodule { + options = { + src = mkOption { + type = types.path; + description = "Path to the syntax folder."; + }; + file = mkOption { + type = types.nullOr types.str; + default = null; + description = + "Subpath of the syntax file within the source, if needed."; + }; + }; + }); + default = { }; + example = literalExpression '' + { + gleam = { + src = pkgs.fetchFromGitHub { + owner = "molnarmark"; + repo = "sublime-gleam"; + rev = "2e761cdb1a87539d827987f997a20a35efd68aa9"; + hash = "sha256-Zj2DKTcO1t9g18qsNKtpHKElbRSc9nBRE2QBzRn9+qs="; + }; + file = "syntax/gleam.sublime-syntax"; + }; + } + ''; + description = '' + Additional syntaxes to provide. + ''; + }; + }; + + config = mkIf cfg.enable { + home.packages = [ cfg.package ]; + + xdg.configFile = mkMerge ([({ + "silicon/config" = mkIf (cfg.settings != "") { text = cfg.settings; }; + })] ++ (flip mapAttrsToList cfg.themes (name: val: { + "silicon/themes/${name}.tmTheme" = { + source = + if isNull val.file then "${val.src}" else "${val.src}/${val.file}"; + }; + })) ++ (flip mapAttrsToList cfg.syntaxes (name: val: { + "silicon/syntaxes/${name}.sublime-syntax" = { + source = + if isNull val.file then "${val.src}" else "${val.src}/${val.file}"; + }; + }))); + + # NOTE: we are ensuring `themes` and `syntaxes` directories exist + # because silicon assumes they do when running `--build-cache` + # https://github.com/Aloxaf/silicon/issues/242 + home.activation.siliconCache = hm.dag.entryAfter [ "linkGeneration" ] '' + ( + export XDG_CACHE_HOME=${escapeShellArg config.xdg.cacheHome} + verboseEcho "Rebuilding silicon theme cache" + mkdir -p ${ + escapeShellArg config.xdg.configHome + }/silicon/{themes,syntaxes} + cd ${escapeShellArg config.xdg.configHome}/silicon + run ${getExe cfg.package} --build-cache + ) + ''; + }; +} diff --git a/tests/default.nix b/tests/default.nix index 0ebf47151..64e7f4d26 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -140,6 +140,7 @@ in import nmtSrc { ./modules/programs/scmpuff ./modules/programs/senpai ./modules/programs/sftpman + ./modules/programs/silicon ./modules/programs/sioyek ./modules/programs/sm64ex ./modules/programs/spotify-player diff --git a/tests/modules/programs/silicon/basic-configuration b/tests/modules/programs/silicon/basic-configuration new file mode 100755 index 000000000..c8f53453e --- /dev/null +++ b/tests/modules/programs/silicon/basic-configuration @@ -0,0 +1,4 @@ +--shadow-color '#555' +--background '#fff' +--shadow-blur-radius 30 +--no-window-controls diff --git a/tests/modules/programs/silicon/basic-configuration.nix b/tests/modules/programs/silicon/basic-configuration.nix new file mode 100644 index 000000000..184cf717f --- /dev/null +++ b/tests/modules/programs/silicon/basic-configuration.nix @@ -0,0 +1,19 @@ +{ + programs.silicon = { + enable = true; + settings = '' + --shadow-color '#555' + --background '#fff' + --shadow-blur-radius 30 + --no-window-controls + ''; + }; + + test.stubs.silicon = { }; + + nmt.script = let configFile = "home-files/.config/silicon/config"; + in '' + assertFileExists "${configFile}" + assertFileContent "${configFile}" ${./basic-configuration} + ''; +} diff --git a/tests/modules/programs/silicon/default-configuration.nix b/tests/modules/programs/silicon/default-configuration.nix new file mode 100644 index 000000000..5537b45e4 --- /dev/null +++ b/tests/modules/programs/silicon/default-configuration.nix @@ -0,0 +1,9 @@ +{ + programs.silicon.enable = true; + + test.stubs.silicon = { }; + + nmt.script = '' + assertPathNotExists "home-files/.config/silicon/config" + ''; +} diff --git a/tests/modules/programs/silicon/default.nix b/tests/modules/programs/silicon/default.nix new file mode 100644 index 000000000..d0c1833ab --- /dev/null +++ b/tests/modules/programs/silicon/default.nix @@ -0,0 +1,6 @@ +{ + silicon-default-configuration = ./default-configuration.nix; + silicon-basic-configuration = ./basic-configuration.nix; + silicon-themes = ./themes.nix; + silicon-syntaxes = ./syntaxes.nix; +} diff --git a/tests/modules/programs/silicon/syntaxes.nix b/tests/modules/programs/silicon/syntaxes.nix new file mode 100644 index 000000000..285fc81f1 --- /dev/null +++ b/tests/modules/programs/silicon/syntaxes.nix @@ -0,0 +1,30 @@ +{ pkgs, ... }: + +let syntaxName = "gleam"; +in { + programs.silicon = { + enable = true; + syntaxes = { + ${syntaxName} = { + src = pkgs.fetchFromGitHub { + owner = "molnarmark"; + repo = "sublime-gleam"; + rev = "2e761cdb1a87539d827987f997a20a35efd68aa9"; + hash = "sha256-Zj2DKTcO1t9g18qsNKtpHKElbRSc9nBRE2QBzRn9+qs="; + }; + file = "syntax/gleam.sublime-syntax"; + }; + }; + }; + + test.stubs.silicon = { }; + + nmt.script = let + syntaxFile = + "home-files/.config/silicon/syntaxes/${syntaxName}.sublime-syntax"; + cacheFile = "home-files/.cache/silicon/syntaxes.bin"; + in '' + assertFileExists "${syntaxFile}" + assertFileExists "${cacheFile}" + ''; +} diff --git a/tests/modules/programs/silicon/themes.nix b/tests/modules/programs/silicon/themes.nix new file mode 100644 index 000000000..b67ecdc02 --- /dev/null +++ b/tests/modules/programs/silicon/themes.nix @@ -0,0 +1,29 @@ +{ pkgs, ... }: + +let themeName = "dracula"; +in { + programs.silicon = { + enable = true; + themes = { + ${themeName} = { + src = pkgs.fetchFromGitHub { + owner = "dracula"; + repo = "sublime"; + rev = "26c57ec282abcaa76e57e055f38432bd827ac34e"; + sha256 = "019hfl4zbn4vm4154hh3bwk6hm7bdxbr1hdww83nabxwjn99ndhv"; + }; + file = "Dracula.tmTheme"; + }; + }; + }; + + test.stubs.silicon = { }; + + nmt.script = let + themeFile = "home-files/.config/silicon/themes/${themeName}.tmTheme"; + cacheFile = "home-files/.cache/silicon/themes.bin"; + in '' + assertFileExists "${themeFile}" + assertFileExists "${cacheFile}" + ''; +}