diff --git a/pkgs/default.nix b/pkgs/default.nix index e6cd67e..ddb5b26 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -24,5 +24,11 @@ doCheck = false; }); + + formats = + super.formats + // { + ron = import ./ron.nix {inherit (super) lib pkgs;}; + }; }) ] diff --git a/pkgs/ron.nix b/pkgs/ron.nix new file mode 100644 index 0000000..821dfc8 --- /dev/null +++ b/pkgs/ron.nix @@ -0,0 +1,147 @@ +{ + lib, + pkgs, + ... +}: {extensions ? []}: let + inherit + (lib) + boolToString + concatMapStrings + concatStringsSep + escape + length + mapAttrsToList + stringLength + types + ; + + toRon = indent: value: + with builtins; + if value == null + then "None" + else if isBool value + then boolToString value + else if isInt value || isFloat value + then toString value + else if isString value + then string value + else if isList value + then list indent value + else if isAttrs value + then attrs indent value + else abort "formats.ron: should never happen (value = ${value})"; + + specialType = indent: { + value, + _ronType, + ... + } @ args: + if _ronType == "literal" + then value + else if _ronType == "raw_string" + then rawString value + else if _ronType == "char" + then char value + else if _ronType == "optional" + then some indent value + else if _ronType == "tuple" + then tuple indent value + else if _ronType == "struct" + then struct indent args + else abort "formats.ron: should never happen (_ronType = ${_ronType})"; + + escapedValues = escape ["\\" "\""]; + string = value: ''"${escapedValues value}"''; + + listContent = indent: values: concatStringsSep ",\n${indent}" (map (toRon indent) values); + + list = indent: values: + if length values <= 1 + then "[${listContent indent values}]" + else let newIndent = "${indent}\t"; in "[\n${newIndent}${listContent newIndent values}\n${indent}]"; + + attrs = indent: set: + if set ? _ronType + then specialType indent set + else let + newIndent = "${indent}\t"; + toEntry = n: v: "${toRon newIndent n}: ${toRon newIndent v}"; + entries = concatStringsSep ",\n${newIndent}" (mapAttrsToList toEntry set); + in "{\n${indent}${entries}\n${indent}}"; + + rawString = value: ''r#"${value}"#''; + char = value: "'${escapedValues value}'"; + some = indent: value: "Some(${toRon indent value})"; + tuple = indent: values: let + newIndent = "${indent}\t"; + in "(\n${newIndent}${listContent newIndent values}\n${indent})"; + + struct = indent: { + name, + value, + ... + }: let + newIndent = "${indent}\t"; + toEntry = n: v: "${n}: ${toRon newIndent v}"; + entriesStr = + if value ? _ronType + then specialType indent value + else let + entries = mapAttrsToList toEntry value; + entriesStrSpace = concatStringsSep ", " entries; + entriesStrNl = "\n${newIndent}${concatStringsSep ",\n${newIndent}" entries}\n${indent}"; + in + if stringLength (indent + entriesStrSpace) < 120 + then entriesStrSpace + else entriesStrNl; + in + if stringLength name == 0 + then "(${entriesStr})" + else "${name} (${entriesStr})"; + + toFile = value: ''${concatMapStrings (x: "${x}\n") extensions}${toRon "" value}''; +in { + type = let + valueType = + types.nullOr (types.oneOf [ + types.bool + types.int + types.float + types.str + (types.attrsOf valueType) + (types.listOf valueType) + ]) + // { + description = "RON value"; + }; + in + valueType; + + lib = let + mkType = typeName: value: { + inherit value; + _ronType = typeName; + }; + in rec { + mkLiteral = mkType "literal"; + rawString = mkType "raw_string"; + char = mkType "character"; + some = mkType "optional"; + enum = mkLiteral; + tuple = mkType "tuple"; + struct = name: value: { + inherit value name; + _ronType = "struct"; + }; + + types = {}; + }; + + generate = name: value: + pkgs.runCommand name { + value = toFile value; + passAsFile = ["value"]; + } '' + cp "$valuePath" "$out" + ''; +} diff --git a/users/myuser/graphical/wired-notify.nix b/users/myuser/graphical/wired-notify.nix index ed4f133..8d09253 100644 --- a/users/myuser/graphical/wired-notify.nix +++ b/users/myuser/graphical/wired-notify.nix @@ -1,6 +1,300 @@ -{ +{pkgs, ...}: { services.wired = { enable = true; - config = ./wired.ron; + config = let + format = pkgs.formats.ron {}; + inherit (format.lib) struct; + unnamedStruct = struct ""; + Color = hex: struct "Color" {inherit hex;}; + Hook = struct "Hook"; + Vec2 = x: y: struct "Vec2" {inherit x y;}; + Padding = struct "Padding"; + ShortcutsConfig = struct "ShortcutsConfig"; + in + format.generate "wired.ron" (unnamedStruct { + max_notifications = 10; + timeout = 4000; + poll_interval = 6; # 6ms ~= 166hz. + history_length = 60; + replacing_enabled = true; + replacing_resets_timeout = true; + min_window_width = 500; + min_window_height = 100; + debug = true; + + # https://github.com/Toqozz/wired-notify/wiki/Shortcuts + shortcuts = ShortcutsConfig { + notification_interact = 1; # left click + notification_close = 2; # right click + notification_action1 = 3; # middle click + }; + + layout_blocks = map unnamedStruct [ + { + name = "general_root"; + parent = ""; + hook = Hook { + parent_anchor = "TR"; + self_anchor = "TR"; + }; + offset = Vec2 (-50) 50; + render_criteria = []; + params = struct "NotificationBlock" (unnamedStruct { + monitor = 0; + border_width = 0; + border_rounding = 8; + background_color = Color "#F5F5F5"; + border_color = Color "#00000000"; + border_color_low = Color "#00000000"; + border_color_critical = Color "#FF0000"; + border_color_paused = Color "#00000000"; + gap = Vec2 0.0 8.0; + notification_hook = Hook { + parent_anchor = "BM"; + self_anchor = "TM"; + }; + }); + } + + { + name = "general_notification"; + parent = "general_root"; + hook = Hook { + parent_anchor = "TM"; + self_anchor = "TM"; + }; + offset = Vec2 0 0; + params = struct "ImageBlock" (unnamedStruct { + image_type = "App"; + padding = Padding { + left = 40; + right = 40; + top = 40; + bottom = 8; + }; + rounding = 4.0; + scale_width = 152; + scale_height = 152; + filter_mode = "Lanczos3"; + }); + } + + { + name = "general_summary"; + parent = "general_notification"; + hook = Hook { + parent_anchor = "BM"; + self_anchor = "TM"; + }; + offset = Vec2 0 12; + params = struct "TextBlock" (unnamedStruct { + text = "%s"; + font = "Arial Bold 16"; + ellipsize = "End"; + color = Color "#000000"; + padding = Padding { + left = 0; + right = 0; + top = 0; + bottom = 0; + }; + dimensions = unnamedStruct { + width = unnamedStruct { + min = -1; + max = 185; + }; + height = unnamedStruct { + min = 0; + max = 0; + }; + }; + }); + } + + { + name = "general_body"; + parent = "general_summary"; + hook = Hook { + parent_anchor = "BM"; + self_anchor = "TM"; + }; + offset = Vec2 0 0; + params = struct "TextBlock" (unnamedStruct { + text = "%b"; + font = "Arial Bold 16"; + ellipsize = "End"; + color = Color "#000000"; + padding = Padding { + left = 0; + right = 0; + top = 0; + bottom = 24; + }; + dimensions = unnamedStruct { + width = unnamedStruct { + min = -1; + max = 250; + }; + height = unnamedStruct { + min = 0; + max = 0; + }; + }; + }); + } + ]; + }); + + /* + { + name: "app_root", + parent: "", + hook: Hook { parent_anchor = "MM"; self_anchor = "MM"; }; + offset: Vec2(x: 0, y: 0), + render_criteria: [AppImage], + params: NotificationBlock(( + monitor: 0, + border_width: 0, + border_rounding: 8, + background_color: Color "#F5F5F5", + border_color: Color "#00000000", + border_color_low: Color "#00000000", + border_color_critical: Color "#FF0000", + border_color_paused: Color "#00000000", + gap: Vec2(x: 0.0, y: 8.0), + notification_hook: Hook { parent_anchor = "BM"; self_anchor = "TM"; }; + )), + ), + + ( + name: "app_notification", + parent: "app_root", + hook: Hook { parent_anchor = "TM"; self_anchor = "TM"; }; + offset: Vec2(x: 0, y: 0), + params: ImageBlock(( + image_type: App, + padding: Padding(left: 40, right: 40, top: 40, bottom: 8), + rounding: 4.0, + scale_width: 152, + scale_height: 152, + filter_mode: "Lanczos3", + )), + ), + + ( + name: "app_summary", + parent: "app_notification", + hook: Hook { parent_anchor = "BM"; self_anchor = "TM"; }; + offset: Vec2(x: 0, y: 12), + params: TextBlock(( + text: "%s", + font: "Arial Bold 16", + ellipsize: End, + color: Color "#000000", + padding: Padding(left: 0, right: 0, top: 0, bottom: 0), + dimensions: (width: (min: -1, max: 185), height: (min: 0, max: 0)), + )), + ), + + ( + name: "app_body", + parent: "app_summary", + hook: Hook { parent_anchor = "BM"; self_anchor = "TM"; }; + offset: Vec2(x: 0, y: 0), + params: TextBlock(( + text: "%b", + font: "Arial Bold 16", + ellipsize: End, + color: Color "#000000", + padding: Padding(left: 0, right: 0, top: 0, bottom: 24), + dimensions: (width: (min: -1, max: 250), height: (min: 0, max: 0)), + )), + ), + + ( + name: "app_progress", + parent: "app_notification", + hook: Hook { parent_anchor = "BM"; self_anchor = "TM"; }; + offset: Vec2(x: 0, y: 50), + render_criteria: [Progress], + params: ProgressBlock(( + padding: Padding(left: 0, right: 0, top: 0, bottom: 32), + border_width: 2, + border_rounding: 2, + border_color: Color "#000000", + fill_rounding: 1, + background_color: Color "#00000000", + fill_color: Color "#000000", + width: -1.0, + height: 30.0, + )), + ), + + ( + name: "status_root", + parent: "", + hook: Hook { parent_anchor = "TM"; self_anchor = "TM"; }; + offset: Vec2(x: 0.0, y: 60), + # render_anti_criteria: [AppImage], + render_criteria: [HintImage], + params: NotificationBlock(( + monitor: 0, + border_width: 0, + border_rounding: 8, + background_color: Color "#F5F5F5", + border_color: Color "#00000000", + border_color_low: Color "#00000000", + border_color_critical: Color "#FF0000", + border_color_paused: Color "#00000000", + gap: Vec2(x: 0.0, y: 8.0), + notification_hook: Hook { parent_anchor = "BM"; self_anchor = "TM"; }; + )), + ), + + ( + name: "status_notification", + parent: "status_root", + hook: Hook { parent_anchor = "TL"; self_anchor = "TL"; }; + offset: Vec2(x: 0, y: 0), + params: TextBlock(( + text: "%s", + font: "Arial Bold 16", + ellipsize: End, + color: Color "#000000", + padding: Padding(left: 8, right: 8, top: 8, bottom: 8), + dimensions: (width: (min: 400, max: 400), height: (min: 84, max: 0)), + )), + ), + + ( + name: "status_body", + parent: "status_notification", + hook: Hook { parent_anchor = "ML"; self_anchor = "TL"; }; + offset: Vec2(x: 0, y: -24), + params: TextBlock(( + text: "%b", + font: "Arial 14", + ellipsize: End, + color: Color "#000000", + padding: Padding(left: 8, right: 8, top: 8, bottom: 8), + dimensions: (width: (min: 400, max: 400), height: (min: 0, max: 84)), + )), + ), + + ( + name: "status_image", + parent: "status_notification", + hook: Hook { parent_anchor = "TL"; self_anchor = "TR"; }; + offset: Vec2(x: 0, y: 0), + params: ImageBlock(( + image_type: Hint, + padding: Padding(left: 8, right: 0, top: 8, bottom: 8), + rounding: 4.0, + scale_width: 84, + scale_height: 84, + filter_mode: "Lanczos3", + )), + ), + */ }; } diff --git a/users/myuser/graphical/wired.ron b/users/myuser/graphical/wired.ron deleted file mode 100644 index 09b111d..0000000 --- a/users/myuser/graphical/wired.ron +++ /dev/null @@ -1,173 +0,0 @@ -( - max_notifications: 10, - timeout: 4000, - poll_interval: 6, // 6ms ~= 166hz. - history_length: 60, - replacing_enabled: true, - replacing_resets_timeout: true, - min_window_width: 500, - min_window_height: 100, - - debug: false, - debug_color: Color(r: 0.0, g: 1.0, b: 0.0, a: 1.0), - debug_color_alt: Color(r: 1.0, g: 0.0, b: 0.0, a: 1.0), - - // https://github.com/Toqozz/wired-notify/wiki/Shortcuts - shortcuts: ShortcutsConfig ( - notification_interact: 1, - notification_close: 2, - notification_action1: 3, - ), - - layout_blocks: [ - ( - name: "app_root", - parent: "", - hook: Hook(parent_anchor: MM, self_anchor: MM), - offset: Vec2(x: 0, y: 0), - render_criteria: [AppImage], - params: NotificationBlock(( - monitor: 0, - border_width: 0, - border_rounding: 8, - background_color: Color(hex: "#F5F5F5"), - border_color: Color(hex: "#00000000"), - border_color_low: Color(hex: "#00000000"), - border_color_critical: Color(hex: "#FF0000"), - border_color_paused: Color(hex: "#00000000"), - gap: Vec2(x: 0.0, y: 8.0), - notification_hook: Hook(parent_anchor: BM, self_anchor: TM), - )), - ), - - ( - name: "app_notification", - parent: "app_root", - hook: Hook(parent_anchor: TM, self_anchor: TM), - offset: Vec2(x: 0, y: 0), - params: ImageBlock(( - image_type: App, - padding: Padding(left: 40, right: 40, top: 40, bottom: 8), - rounding: 4.0, - scale_width: 152, - scale_height: 152, - filter_mode: Lanczos3, - )), - ), - - ( - name: "app_summary", - parent: "app_notification", - hook: Hook(parent_anchor: BM, self_anchor: TM), - offset: Vec2(x: 0, y: 12), - params: TextBlock(( - text: "%s", - font: "Arial Bold 16", - ellipsize: End, - color: Color(hex: "#000000"), - padding: Padding(left: 0, right: 0, top: 0, bottom: 0), - dimensions: (width: (min: -1, max: 185), height: (min: 0, max: 0)), - )), - ), - - ( - name: "app_body", - parent: "app_summary", - hook: Hook(parent_anchor: BM, self_anchor: TM), - offset: Vec2(x: 0, y: 0), - params: TextBlock(( - text: "%b", - font: "Arial Bold 16", - ellipsize: End, - color: Color(hex: "#000000"), - padding: Padding(left: 0, right: 0, top: 0, bottom: 24), - dimensions: (width: (min: -1, max: 250), height: (min: 0, max: 0)), - )), - ), - - ( - name: "app_progress", - parent: "app_notification", - hook: Hook(parent_anchor: BM, self_anchor: TM), - offset: Vec2(x: 0, y: 50), - render_criteria: [Progress], - params: ProgressBlock(( - padding: Padding(left: 0, right: 0, top: 0, bottom: 32), - border_width: 2, - border_rounding: 2, - border_color: Color(hex: "#000000"), - fill_rounding: 1, - background_color: Color(hex: "#00000000"), - fill_color: Color(hex: "#000000"), - width: -1.0, - height: 30.0, - )), - ), - - ( - name: "status_root", - parent: "", - hook: Hook(parent_anchor: TM, self_anchor: TM), - offset: Vec2(x: 0.0, y: 60), - // render_anti_criteria: [AppImage], - render_criteria: [HintImage], - params: NotificationBlock(( - monitor: 0, - border_width: 0, - border_rounding: 8, - background_color: Color(hex: "#F5F5F5"), - border_color: Color(hex: "#00000000"), - border_color_low: Color(hex: "#00000000"), - border_color_critical: Color(hex: "#FF0000"), - border_color_paused: Color(hex: "#00000000"), - gap: Vec2(x: 0.0, y: 8.0), - notification_hook: Hook(parent_anchor: BM, self_anchor: TM), - )), - ), - - ( - name: "status_notification", - parent: "status_root", - hook: Hook(parent_anchor: TL, self_anchor: TL), - offset: Vec2(x: 0, y: 0), - params: TextBlock(( - text: "%s", - font: "Arial Bold 16", - ellipsize: End, - color: Color(hex: "#000000"), - padding: Padding(left: 8, right: 8, top: 8, bottom: 8), - dimensions: (width: (min: 400, max: 400), height: (min: 84, max: 0)), - )), - ), - - ( - name: "status_body", - parent: "status_notification", - hook: Hook(parent_anchor: ML, self_anchor: TL), - offset: Vec2(x: 0, y: -24), - params: TextBlock(( - text: "%b", - font: "Arial 14", - ellipsize: End, - color: Color(hex: "#000000"), - padding: Padding(left: 8, right: 8, top: 8, bottom: 8), - dimensions: (width: (min: 400, max: 400), height: (min: 0, max: 84)), - )), - ), - - ( - name: "status_image", - parent: "status_notification", - hook: Hook(parent_anchor: TL, self_anchor: TR), - offset: Vec2(x: 0, y: 0), - params: ImageBlock(( - image_type: Hint, - padding: Padding(left: 8, right: 0, top: 8, bottom: 8), - rounding: 4.0, - scale_width: 84, - scale_height: 84, - filter_mode: Lanczos3, - )), - ), - ], -)