From c936d859c7c59d81971afe0b1c8363a1ac2dd82a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Geoffrey=20=E2=80=9CFrogeye=E2=80=9D=20Preud=27homme?= Date: Sat, 27 Jan 2024 14:23:26 +0100 Subject: [PATCH] Frogarized! --- common/frogarized/default.nix | 22 ++++++ common/frogarized/frogarized.py | 112 ++++++++++++++++++++++++++++++ hm/default.nix | 1 + hm/desktop/background/default.nix | 5 -- hm/theme/default.nix | 9 --- hm/vim/decoration.nix | 1 + hm/vim/default.nix | 3 + os/default.nix | 1 + os/style/default.nix | 5 -- 9 files changed, 140 insertions(+), 19 deletions(-) create mode 100644 common/frogarized/default.nix create mode 100755 common/frogarized/frogarized.py diff --git a/common/frogarized/default.nix b/common/frogarized/default.nix new file mode 100644 index 0000000..571c67b --- /dev/null +++ b/common/frogarized/default.nix @@ -0,0 +1,22 @@ +{ pkgs, lib, config, ... }: +let + generator = pkgs.writers.writePython3 "frogarized" + { + libraries = [ pkgs.python3Packages.colorspacious ]; + } + (builtins.readFile ./frogarized.py); + frogarized_json = polarity: pkgs.runCommand "frogarized-${polarity}.json" { } "${generator} --polarity ${polarity} --output json > $out"; + frogarized_nix = polarity: builtins.fromJSON (builtins.readFile (frogarized_json polarity)); +in +{ + config = { + stylix = { + base16Scheme = frogarized_nix config.stylix.polarity; + # On purpose also enable without a DE because stylix complains otherwise + image = builtins.fetchurl { + url = "https://get.wallhere.com/photo/sunlight-abstract-minimalism-green-simple-circle-light-leaf-wave-material-line-wing-computer-wallpaper-font-close-up-macro-photography-124350.png"; + sha256 = "sha256:1zfq3f3v34i45mi72pkfqphm8kbhczsg260xjfl6dbydy91d7y93"; + }; + }; + }; +} diff --git a/common/frogarized/frogarized.py b/common/frogarized/frogarized.py new file mode 100755 index 0000000..c3aec87 --- /dev/null +++ b/common/frogarized/frogarized.py @@ -0,0 +1,112 @@ +import argparse +import json + +import colorspacious +import numpy as np + +# Original values for the Solarized color scheme, +# created by Ethan Schoonover (https://ethanschoonover.com/solarized/) +SOLARIZED_LAB = np.array( + [ + [15, -12, -12], + [20, -12, -12], + [45, -7, -7], + [50, -7, -7], + [60, -6, -3], + [65, -5, -2], + [92, -0, 10], + [97, 0, 10], + [50, 65, 45], + [50, 50, 55], + [60, 10, 65], + [60, -20, 65], + [60, -35, -5], + [55, -10, -45], + [50, 15, -45], + [50, 65, -5], + ] +) + +# I couldn't get a perfect translation of Solarized L*a*b values into sRGB, +# so here is upstream's translation for reference +SOLARIZED_RGB = np.array( + [ + [0, 43, 54], + [7, 54, 66], + [88, 110, 117], + [101, 123, 131], + [131, 148, 150], + [147, 161, 161], + [238, 232, 213], + [253, 246, 227], + [220, 50, 47], + [203, 75, 22], + [181, 137, 0], + [133, 153, 0], + [42, 161, 152], + [38, 139, 210], + [108, 113, 196], + [211, 54, 130], + ] +) + +# Parse arguments +parser = argparse.ArgumentParser( + description="Generate a base16-theme based derived from Solarized" +) +parser.add_argument("--source", choices=["lab", "rgb"], default="lab") +parser.add_argument("--lightness_factor", type=float, default=1.0) +parser.add_argument("--chroma-factor", type=float, default=1.0) +parser.add_argument("--hue_shift", type=float, default=-75.0) +parser.add_argument("--polarity", choices=["dark", "light"], default="dark") +parser.add_argument( + "--output", choices=["json", "truecolor"], default="truecolor" +) +args = parser.parse_args() + +# Convert source to JCh color space +if args.source == "lab": + solarized_jch = colorspacious.cspace_convert( + SOLARIZED_LAB, "CIELab", "JCh" + ) +elif args.source == "rgb": + solarized_jch = colorspacious.cspace_convert( + SOLARIZED_RGB, "sRGB255", "JCh" + ) + +# Build frogarized theme +jch_factor = [args.lightness_factor, args.chroma_factor, 1] +jch_shift = [0, 0, args.hue_shift] +frogarzied_jch = np.vstack( + [solarized_jch[:8] * jch_factor + jch_shift, solarized_jch[8:]] +) + +# Convert frogarized to RGB +frogarized_srgb = colorspacious.cspace_convert( + frogarzied_jch, "JCh", "sRGB255" +) +frogarized_rgb = np.uint8(np.rint(np.clip(frogarized_srgb, 0, 255))) +if args.polarity == "light": + frogarized_rgb = np.vstack([frogarized_rgb[7::-1], frogarized_rgb[8:]]) + +# Output +palette = dict() +for i in range(16): + rgb = frogarized_rgb[i] + r, g, b = rgb + hex = f"#{r:02x}{g:02x}{b:02x}" + palette[f"base{i:02X}"] = hex + if args.output == "truecolor": + print(f"\033[48;2;{r};{g};{b}m{hex}\033[0m") # ]] + # treesitter is silly and will consider brackets in strings + # as indentation, hence the comment above +if args.output == "json": + scheme = palette.copy() + scheme.update( + { + "slug": f"frogarized-{args.polarity}", + "scheme": f"Frogarized {args.polarity.title()}", + "author": "Geoffrey Frogeye (with work from Ethan Schoonover)", + } + ) + print(json.dumps(scheme, indent=4)) diff --git a/hm/default.nix b/hm/default.nix index 9f28122..04061d8 100644 --- a/hm/default.nix +++ b/hm/default.nix @@ -1,6 +1,7 @@ { ... }: { imports = [ + ../common/frogarized ../options.nix ./brightness ./common.nix diff --git a/hm/desktop/background/default.nix b/hm/desktop/background/default.nix index 37767e6..6587f27 100644 --- a/hm/desktop/background/default.nix +++ b/hm/desktop/background/default.nix @@ -1,11 +1,6 @@ { pkgs, config, lib, ... }: { config = { - # On purpose also enable without a DE because stylix complains otherwise - stylix.image = builtins.fetchurl { - url = "https://get.wallhere.com/photo/sunlight-abstract-minimalism-green-simple-circle-light-leaf-wave-material-line-wing-computer-wallpaper-font-close-up-macro-photography-124350.png"; - sha256 = "sha256:1zfq3f3v34i45mi72pkfqphm8kbhczsg260xjfl6dbydy91d7y93"; - }; # This correctly sets the background on some occasions, below does the rest programs.autorandr.hooks.postswitch = { background = "${pkgs.feh}/bin/feh --no-fehbg --bg-fill ${config.stylix.image}"; diff --git a/hm/theme/default.nix b/hm/theme/default.nix index b85b992..76463b1 100644 --- a/hm/theme/default.nix +++ b/hm/theme/default.nix @@ -1,16 +1,7 @@ { pkgs, config, lib, ... }: -let - basetheme = "solarized"; -in { config = { - # Setting a custom base16 theme via nixvim is required so feline works, and - # because stylix makes a config that otherwise only works with dark - # polarity. - programs.nixvim.colorschemes.base16.colorscheme = "${basetheme}-${config.frogeye.polarity}"; - stylix = { - base16Scheme = "${pkgs.base16-schemes}/share/themes/${basetheme}-${config.frogeye.polarity}.yaml"; polarity = config.frogeye.polarity; fonts = { monospace = { diff --git a/hm/vim/decoration.nix b/hm/vim/decoration.nix index a80e8b4..cbb7457 100644 --- a/hm/vim/decoration.nix +++ b/hm/vim/decoration.nix @@ -43,6 +43,7 @@ plugins = { # Tabline barbar.enable = true; + # TODO Reload make it use the preset colorscheme # Status line lualine = with config.lib.stylix.colors.withHashtag; let normal = { fg = base05; bg = base01; }; diff --git a/hm/vim/default.nix b/hm/vim/default.nix index e067dce..d50453f 100644 --- a/hm/vim/default.nix +++ b/hm/vim/default.nix @@ -12,6 +12,9 @@ vim = "nvim"; }; programs.nixvim = { + # Required, otherwise light mode becomes a default dark theme. + colorschemes.base16.colorscheme = "solarized-${config.stylix.polarity}"; + options = { ignorecase = true; smartcase = true; diff --git a/os/default.nix b/os/default.nix index 1b40690..28bd391 100644 --- a/os/default.nix +++ b/os/default.nix @@ -2,6 +2,7 @@ { imports = [ ../options.nix + ../common/frogarized ./battery.nix ./ccc ./common.nix diff --git a/os/style/default.nix b/os/style/default.nix index bc441a3..ab0fa91 100644 --- a/os/style/default.nix +++ b/os/style/default.nix @@ -6,11 +6,6 @@ initrd.systemd.enable = true; }; stylix = { - base16Scheme = "${pkgs.base16-schemes}/share/themes/solarized-${config.stylix.polarity}.yaml"; - image = builtins.fetchurl { - url = "https://get.wallhere.com/photo/sunlight-abstract-minimalism-green-simple-circle-light-leaf-wave-material-line-wing-computer-wallpaper-font-close-up-macro-photography-124350.png"; - sha256 = "sha256:1zfq3f3v34i45mi72pkfqphm8kbhczsg260xjfl6dbydy91d7y93"; - }; homeManagerIntegration.autoImport = false; # Makes config reuse easier polarity = "dark"; targets.plymouth.logo = pkgs.runCommand "flower.png" { } "${pkgs.inkscape}/bin/inkscape ${pkgs.substituteAll {