aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--niri-config/src/lib.rs99
-rw-r--r--resources/default-config.kdl24
2 files changed, 107 insertions, 16 deletions
diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs
index 65614966..f5f8efd6 100644
--- a/niri-config/src/lib.rs
+++ b/niri-config/src/lib.rs
@@ -422,15 +422,11 @@ impl From<Border> for FocusRing {
}
}
-#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq, Eq)]
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Color {
- #[knuffel(argument)]
pub r: u8,
- #[knuffel(argument)]
pub g: u8,
- #[knuffel(argument)]
pub b: u8,
- #[knuffel(argument)]
pub a: u8,
}
@@ -849,6 +845,97 @@ impl FromStr for Color {
}
}
+#[derive(knuffel::Decode)]
+struct ColorRgba {
+ #[knuffel(argument)]
+ r: u8,
+ #[knuffel(argument)]
+ g: u8,
+ #[knuffel(argument)]
+ b: u8,
+ #[knuffel(argument)]
+ a: u8,
+}
+
+impl From<ColorRgba> for Color {
+ fn from(value: ColorRgba) -> Self {
+ let ColorRgba { r, g, b, a } = value;
+ Self { r, g, b, a }
+ }
+}
+
+// Manual impl to allow both one-argument string and 4-argument RGBA forms.
+impl<S> knuffel::Decode<S> for Color
+where
+ S: knuffel::traits::ErrorSpan,
+{
+ fn decode_node(
+ node: &knuffel::ast::SpannedNode<S>,
+ ctx: &mut knuffel::decode::Context<S>,
+ ) -> Result<Self, knuffel::errors::DecodeError<S>> {
+ // Check for unexpected type name.
+ if let Some(type_name) = &node.type_name {
+ ctx.emit_error(knuffel::errors::DecodeError::unexpected(
+ type_name,
+ "type name",
+ "no type name expected for this node",
+ ));
+ }
+
+ // Get the first argument.
+ let mut iter_args = node.arguments.iter();
+ let val = iter_args.next().ok_or_else(|| {
+ knuffel::errors::DecodeError::missing(node, "additional argument is required")
+ })?;
+
+ // Check for unexpected type name.
+ if let Some(typ) = &val.type_name {
+ ctx.emit_error(knuffel::errors::DecodeError::TypeName {
+ span: typ.span().clone(),
+ found: Some((**typ).clone()),
+ expected: knuffel::errors::ExpectedType::no_type(),
+ rust_type: "str",
+ });
+ }
+
+ // Check the argument type.
+ let rv = match *val.literal {
+ // If it's a string, use FromStr.
+ knuffel::ast::Literal::String(ref s) => Color::from_str(s)
+ .map_err(|e| knuffel::errors::DecodeError::conversion(&val.literal, e)),
+ // Otherwise, fall back to the 4-argument RGBA form.
+ _ => return ColorRgba::decode_node(node, ctx).map(Color::from),
+ }?;
+
+ // Check for unexpected following arguments.
+ if let Some(val) = iter_args.next() {
+ ctx.emit_error(knuffel::errors::DecodeError::unexpected(
+ &val.literal,
+ "argument",
+ "unexpected argument",
+ ));
+ }
+
+ // Check for unexpected properties and children.
+ for name in node.properties.keys() {
+ ctx.emit_error(knuffel::errors::DecodeError::unexpected(
+ name,
+ "property",
+ format!("unexpected property `{}`", name.escape_default()),
+ ));
+ }
+ for child in node.children.as_ref().map(|lst| &lst[..]).unwrap_or(&[]) {
+ ctx.emit_error(knuffel::errors::DecodeError::unexpected(
+ child,
+ "node",
+ format!("unexpected node `{}`", child.node_name.escape_default()),
+ ));
+ }
+
+ Ok(rv)
+ }
+}
+
impl FromStr for Mode {
type Err = miette::Error;
@@ -1025,7 +1112,7 @@ mod tests {
border {
width 3
- inactive-color 255 200 100 0
+ inactive-color "rgba(255, 200, 100, 0.0)"
}
preset-column-widths {
diff --git a/resources/default-config.kdl b/resources/default-config.kdl
index 1a2843ae..36a9ca1d 100644
--- a/resources/default-config.kdl
+++ b/resources/default-config.kdl
@@ -113,18 +113,22 @@ layout {
// How many logical pixels the ring extends out from the windows.
width 4
- // Color of the ring on the active monitor: red, green, blue, alpha.
- active-color 127 200 255 255
+ // Colors can be set in a variety of ways:
+ // - CSS named colors: "red"
+ // - RGB hex: "#rgb", "#rgba", "#rrggbb", "#rrggbbaa"
+ // - CSS-like notation: "rgb(255, 127, 0)", rgba(), hsl() and a few others.
- // Color of the ring on inactive monitors: red, green, blue, alpha.
- inactive-color 80 80 80 255
+ // Color of the ring on the active monitor.
+ active-color "#7fc8ff"
+
+ // Color of the ring on inactive monitors.
+ inactive-color "#505050"
+
+ // Additionally, there's a legacy RGBA syntax:
+ // active-color 127 200 255 255
// You can also use gradients. They take precedence over solid colors.
// Gradients are rendered the same as CSS linear-gradient(angle, from, to).
- // Colors can be set in a variety of ways here:
- // - CSS named colors: from="red"
- // - RGB hex: from="#rgb", from="#rgba", from="#rrggbb", from="#rrggbbaa"
- // - CSS-like notation: from="rgb(255, 127, 0)", rgba(), hsl() and a few others.
// The angle is the same as in linear-gradient, and is optional,
// defaulting to 180 (top-to-bottom gradient).
// You can use any CSS linear-gradient tool on the web to set these up.
@@ -145,8 +149,8 @@ layout {
off
width 4
- active-color 255 200 127 255
- inactive-color 80 80 80 255
+ active-color "#ffc87f"
+ inactive-color "#505050"
// active-gradient from="#ffbb66" to="#ffc880" angle=45 relative-to="workspace-view"
// inactive-gradient from="#505050" to="#808080" angle=45 relative-to="workspace-view"