summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--home/default.nix13
-rw-r--r--home/ebisu/fortune/desktop/mako.nix29
-rw-r--r--lib/pywal/default.nix20
-rw-r--r--lib/pywal/wal.py356
4 files changed, 399 insertions, 19 deletions
diff --git a/home/default.nix b/home/default.nix
index 1475f01..01c167a 100644
--- a/home/default.nix
+++ b/home/default.nix
@@ -14,13 +14,21 @@ in
username = "ebisu";
flakeDirectory = ".nixos-config";
systems = import inputs.systems;
- in
- inputs.home-manager.lib.homeManagerConfiguration {
+
pkgs =
((import ../lib/systems.nix { inherit lib systems; }) (
system: import inputs.nixpkgs { inherit system; }
))."${builtins.currentSystem}";
+ colourscheme = import ../lib/pywal {
+ inherit pkgs;
+
+ wallpaper = ./${username}/wallpaper.png;
+ };
+ in
+ inputs.home-manager.lib.homeManagerConfiguration {
+ inherit pkgs;
+
modules = [
./${username}
inputs.chaotic.homeManagerModules.default
@@ -34,6 +42,7 @@ in
secrets
username
flakeDirectory
+ colourscheme
;
};
};
diff --git a/home/ebisu/fortune/desktop/mako.nix b/home/ebisu/fortune/desktop/mako.nix
index 836541c..615dd1a 100644
--- a/home/ebisu/fortune/desktop/mako.nix
+++ b/home/ebisu/fortune/desktop/mako.nix
@@ -1,9 +1,4 @@
-{ config, ... }:
-let
- colourScheme = builtins.fromJSON (
- builtins.readFile "${config.home.homeDirectory}/.cache/wal/colors.json"
- );
-in
+{ colourscheme, ... }:
{
services.mako.enable = true;
@@ -33,26 +28,26 @@ in
border-color=#00000040
border-size=1
- background-color=${colourScheme.colors.color0}
- text-color=${colourScheme.colors.color15}
+ background-color=${colourscheme.colour0}
+ text-color=${colourscheme.colour15}
# [urgency=low]
- # border-color=${colourScheme.colors.color2}
- # background-color=${colourScheme.colors.color4}
- # text-color=${colourScheme.colors.color6}
+ # border-color=${colourscheme.colour2}
+ # background-color=${colourscheme.colour4}
+ # text-color=${colourscheme.colour6}
# [urgency=normal]
- # border-color=${colourScheme.colors.color1}
- # background-color=${colourScheme.colors.color3}
- # text-color=${colourScheme.colors.color5}
+ # border-color=${colourscheme.colour1}
+ # background-color=${colourscheme.colour3}
+ # text-color=${colourscheme.colour5}
# default-timeout=10000
# ignore-timeout=1
# [urgency=high]
# font=Sauce Code Pro 16
- # border-color=${colourScheme.colors.color1}
- # background-color=${colourScheme.colors.color2}
- # text-color=${colourScheme.colors.color6}
+ # border-color=${colourscheme.colour1}
+ # background-color=${colourscheme.colour2}
+ # text-color=${colourscheme.colour6}
# default-timeout=0
# ignore-timeout=1
'';
diff --git a/lib/pywal/default.nix b/lib/pywal/default.nix
new file mode 100644
index 0000000..59ed30c
--- /dev/null
+++ b/lib/pywal/default.nix
@@ -0,0 +1,20 @@
+{ pkgs, wallpaper }:
+let
+ colourScheme = builtins.fromJSON (
+ builtins.readFile "${
+ pkgs.runCommand "colourscheme"
+ {
+ buildInputs = with pkgs; [
+ imagemagick
+ jq
+ ];
+ }
+ ''
+ mkdir -p $out
+
+ ${pkgs.python3}/bin/python3 ${./wal.py} ${wallpaper} | sed "s/'/\"/g" | jq 'to_entries | map({"colour\(.key)": .value}) | add' > $out/colourscheme
+ ''
+ }/colourscheme"
+ );
+in
+colourScheme
diff --git a/lib/pywal/wal.py b/lib/pywal/wal.py
new file mode 100644
index 0000000..d247b3f
--- /dev/null
+++ b/lib/pywal/wal.py
@@ -0,0 +1,356 @@
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+#
+# https://github.com/dylanaraps/pywal
+# https://github.com/dylanaraps/pywal/blob/master/pywal/backends/wal.py
+# https://github.com/dylanaraps/pywal/blob/master/pywal/util.py
+
+
+"""
+Misc helper functions.
+"""
+
+import colorsys
+import json
+import logging
+import os
+import platform
+import re
+import shutil
+import subprocess
+import sys
+
+
+class Color:
+ """Color formats."""
+
+ alpha_num = "100"
+
+ def __init__(self, hex_color):
+ self.hex_color = hex_color
+
+ def __str__(self):
+ return self.hex_color
+
+ @property
+ def rgb(self):
+ """Convert a hex color to rgb."""
+ return "%s,%s,%s" % (*hex_to_rgb(self.hex_color),)
+
+ @property
+ def xrgba(self):
+ """Convert a hex color to xrdb rgba."""
+ return hex_to_xrgba(self.hex_color)
+
+ @property
+ def rgba(self):
+ """Convert a hex color to rgba."""
+ return "rgba(%s,%s,%s,%s)" % (*hex_to_rgb(self.hex_color), self.alpha_dec)
+
+ @property
+ def alpha(self):
+ """Add URxvt alpha value to color."""
+ return "[%s]%s" % (self.alpha_num, self.hex_color)
+
+ @property
+ def alpha_dec(self):
+ """Export the alpha value as a decimal number in [0, 1]."""
+ return int(self.alpha_num) / 100
+
+ @property
+ def decimal(self):
+ """Export color in decimal."""
+ return "%s%s" % ("#", int(self.hex_color[1:], 16))
+
+ @property
+ def decimal_strip(self):
+ """Strip '#' from decimal color."""
+ return int(self.hex_color[1:], 16)
+
+ @property
+ def octal(self):
+ """Export color in octal."""
+ return "%s%s" % ("#", oct(int(self.hex_color[1:], 16))[2:])
+
+ @property
+ def octal_strip(self):
+ """Strip '#' from octal color."""
+ return oct(int(self.hex_color[1:], 16))[2:]
+
+ @property
+ def strip(self):
+ """Strip '#' from color."""
+ return self.hex_color[1:]
+
+ @property
+ def red(self):
+ """Red value as float between 0 and 1."""
+ return "%.3f" % (hex_to_rgb(self.hex_color)[0] / 255.0)
+
+ @property
+ def green(self):
+ """Green value as float between 0 and 1."""
+ return "%.3f" % (hex_to_rgb(self.hex_color)[1] / 255.0)
+
+ @property
+ def blue(self):
+ """Blue value as float between 0 and 1."""
+ return "%.3f" % (hex_to_rgb(self.hex_color)[2] / 255.0)
+
+ def lighten(self, percent):
+ """Lighten color by percent."""
+ percent = float(re.sub(r"[\D\.]", "", str(percent)))
+ return Color(lighten_color(self.hex_color, percent / 100))
+
+ def darken(self, percent):
+ """Darken color by percent."""
+ percent = float(re.sub(r"[\D\.]", "", str(percent)))
+ return Color(darken_color(self.hex_color, percent / 100))
+
+ def saturate(self, percent):
+ """Saturate a color."""
+ percent = float(re.sub(r"[\D\.]", "", str(percent)))
+ return Color(saturate_color(self.hex_color, percent / 100))
+
+
+def read_file(input_file):
+ """Read data from a file and trim newlines."""
+ with open(input_file, "r") as file:
+ return file.read().splitlines()
+
+
+def read_file_json(input_file):
+ """Read data from a json file."""
+ with open(input_file, "r") as json_file:
+ return json.load(json_file)
+
+
+def read_file_raw(input_file):
+ """Read data from a file as is, don't strip
+ newlines or other special characters."""
+ with open(input_file, "r") as file:
+ return file.readlines()
+
+
+def save_file(data, export_file):
+ """Write data to a file."""
+ create_dir(os.path.dirname(export_file))
+
+ try:
+ with open(export_file, "w") as file:
+ file.write(data)
+ except PermissionError:
+ logging.warning("Couldn't write to %s.", export_file)
+
+
+def save_file_json(data, export_file):
+ """Write data to a json file."""
+ create_dir(os.path.dirname(export_file))
+
+ with open(export_file, "w") as file:
+ json.dump(data, file, indent=4)
+
+
+def create_dir(directory):
+ """Alias to create the cache dir."""
+ os.makedirs(directory, exist_ok=True)
+
+
+def setup_logging():
+ """Logging config."""
+ logging.basicConfig(
+ format=(
+ "[%(levelname)s\033[0m] " "\033[1;31m%(module)s\033[0m: " "%(message)s"
+ ),
+ level=logging.INFO,
+ stream=sys.stdout,
+ )
+ logging.addLevelName(logging.ERROR, "\033[1;31mE")
+ logging.addLevelName(logging.INFO, "\033[1;32mI")
+ logging.addLevelName(logging.WARNING, "\033[1;33mW")
+
+
+def hex_to_rgb(color):
+ """Convert a hex color to rgb."""
+ return tuple(bytes.fromhex(color.strip("#")))
+
+
+def hex_to_xrgba(color):
+ """Convert a hex color to xrdb rgba."""
+ col = color.lower().strip("#")
+ return "%s%s/%s%s/%s%s/ff" % (*col,)
+
+
+def rgb_to_hex(color):
+ """Convert an rgb color to hex."""
+ return "#%02x%02x%02x" % (*color,)
+
+
+def darken_color(color, amount):
+ """Darken a hex color."""
+ color = [int(col * (1 - amount)) for col in hex_to_rgb(color)]
+ return rgb_to_hex(color)
+
+
+def lighten_color(color, amount):
+ """Lighten a hex color."""
+ color = [int(col + (255 - col) * amount) for col in hex_to_rgb(color)]
+ return rgb_to_hex(color)
+
+
+def blend_color(color, color2):
+ """Blend two colors together."""
+ r1, g1, b1 = hex_to_rgb(color)
+ r2, g2, b2 = hex_to_rgb(color2)
+
+ r3 = int(0.5 * r1 + 0.5 * r2)
+ g3 = int(0.5 * g1 + 0.5 * g2)
+ b3 = int(0.5 * b1 + 0.5 * b2)
+
+ return rgb_to_hex((r3, g3, b3))
+
+
+def saturate_color(color, amount):
+ """Saturate a hex color."""
+ r, g, b = hex_to_rgb(color)
+ r, g, b = [x / 255.0 for x in (r, g, b)]
+ h, l, s = colorsys.rgb_to_hls(r, g, b)
+ s = amount
+ r, g, b = colorsys.hls_to_rgb(h, l, s)
+ r, g, b = [x * 255.0 for x in (r, g, b)]
+
+ return rgb_to_hex((int(r), int(g), int(b)))
+
+
+def rgb_to_yiq(color):
+ """Sort a list of colors."""
+ return colorsys.rgb_to_yiq(*hex_to_rgb(color))
+
+
+def disown(cmd):
+ """Call a system command in the background,
+ disown it and hide it's output."""
+ subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+
+
+def get_pid(name):
+ """Check if process is running by name."""
+ if not shutil.which("pidof"):
+ return False
+
+ try:
+ if platform.system() != "Darwin":
+ subprocess.check_output(["pidof", "-s", name])
+ else:
+ subprocess.check_output(["pidof", name])
+
+ except subprocess.CalledProcessError:
+ return False
+
+ return True
+
+
+"""
+Generate a colorscheme using imagemagick.
+"""
+
+import logging
+import re
+import shutil
+import subprocess
+import sys
+
+
+def imagemagick(color_count, img, magick_command):
+ """Call Imagemagick to generate a scheme."""
+ flags = ["-resize", "25%", "-colors", str(color_count), "-unique-colors", "txt:-"]
+ img += "[0]"
+
+ return subprocess.check_output([*magick_command, img, *flags]).splitlines()
+
+
+def has_im():
+ """Check to see if the user has im installed."""
+ if shutil.which("magick"):
+ return ["magick"]
+
+ if shutil.which("convert"):
+ return ["convert"]
+
+ logging.error("Imagemagick wasn't found on your system.")
+ logging.error("Try another backend. (wal --backend)")
+ sys.exit(1)
+
+
+def gen_colors(img):
+ """Format the output from imagemagick into a list
+ of hex colors."""
+ magick_command = has_im()
+
+ for i in range(0, 20, 1):
+ raw_colors = imagemagick(16 + i, img, magick_command)
+
+ if len(raw_colors) > 16:
+ break
+
+ if i == 19:
+ logging.error("Imagemagick couldn't generate a suitable palette.")
+ sys.exit(1)
+
+ else:
+ logging.warning("Imagemagick couldn't generate a palette.")
+ logging.warning("Trying a larger palette size %s", 16 + i)
+
+ return [re.search("#.{6}", str(col)).group(0) for col in raw_colors[1:]]
+
+
+def adjust(colors, light):
+ """Adjust the generated colors and store them in a dict that
+ we will later save in json format."""
+ raw_colors = colors[:1] + colors[8:16] + colors[8:-1]
+
+ # Manually adjust colors.
+ if light:
+ for color in raw_colors:
+ color = saturate_color(color, 0.5)
+
+ raw_colors[0] = lighten_color(colors[-1], 0.85)
+ raw_colors[7] = colors[0]
+ raw_colors[8] = darken_color(colors[-1], 0.4)
+ raw_colors[15] = colors[0]
+
+ else:
+ # Darken the background color slightly.
+ if raw_colors[0][1] != "0":
+ raw_colors[0] = darken_color(raw_colors[0], 0.40)
+
+ raw_colors[7] = blend_color(raw_colors[7], "#EEEEEE")
+ raw_colors[8] = darken_color(raw_colors[7], 0.30)
+ raw_colors[15] = blend_color(raw_colors[15], "#EEEEEE")
+
+ return raw_colors
+
+
+def get(img, light=False):
+ """Get colorscheme."""
+ colors = gen_colors(img)
+ return adjust(colors, light)
+
+
+if __name__ == "__main__" and len(sys.argv) > 1:
+ print(get(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else False))